]> rtime.felk.cvut.cz Git - linux-imx.git/commitdiff
NFSv4.1: Handle BAD_STATEID and EXPIRED errors in layoutget
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 2 Oct 2012 00:25:48 +0000 (17:25 -0700)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 2 Oct 2012 15:34:29 +0000 (08:34 -0700)
If the layoutget call returns a stateid error, we want to invalidate the
layout stateid, and/or recover the open stateid.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/nfs4proc.c

index e10d66f5be0ad0dd5c83d627daaf745fc221eb42..1e0faf9fa0788536fc7ccde39bd20fed73797b99 100644 (file)
@@ -6272,26 +6272,44 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
 static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutget *lgp = calldata;
-       struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+       struct inode *inode = lgp->args.inode;
+       struct nfs_server *server = NFS_SERVER(inode);
+       struct pnfs_layout_hdr *lo;
+       struct nfs4_state *state = NULL;
 
        dprintk("--> %s\n", __func__);
 
        if (!nfs4_sequence_done(task, &lgp->res.seq_res))
-               return;
+               goto out;
 
        switch (task->tk_status) {
        case 0:
-               break;
+               goto out;
        case -NFS4ERR_LAYOUTTRYLATER:
        case -NFS4ERR_RECALLCONFLICT:
                task->tk_status = -NFS4ERR_DELAY;
-               /* Fall through */
-       default:
-               if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
-                       rpc_restart_call_prepare(task);
-                       return;
+               break;
+       case -NFS4ERR_EXPIRED:
+       case -NFS4ERR_BAD_STATEID:
+               spin_lock(&inode->i_lock);
+               lo = NFS_I(inode)->layout;
+               if (!lo || list_empty(&lo->plh_segs)) {
+                       spin_unlock(&inode->i_lock);
+                       /* If the open stateid was bad, then recover it. */
+                       state = lgp->args.ctx->state;
+               } else {
+                       LIST_HEAD(head);
+
+                       pnfs_mark_matching_lsegs_invalid(lo, &head, NULL);
+                       spin_unlock(&inode->i_lock);
+                       /* Mark the bad layout state as invalid, then
+                        * retry using the open stateid. */
+                       pnfs_free_lseg_list(&head);
                }
        }
+       if (nfs4_async_handle_error(task, server, state) == -EAGAIN)
+               rpc_restart_call_prepare(task);
+out:
        dprintk("<-- %s\n", __func__);
 }