NFSv4: Close another NFSv4 recovery race
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 29 May 2013 17:34:46 +0000 (13:34 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 6 Jun 2013 20:24:44 +0000 (16:24 -0400)
State recovery currently relies on being able to find a valid
nfs_open_context in the inode->open_files list.
We therefore need to put the nfs_open_context on the list while
we're still protected by the sp->so_reclaim_seqcount in order
to avoid reboot races.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/inode.c
fs/nfs/nfs4proc.c
include/linux/nfs_fs.h

index c1c7a9d78722257867846f39c74780536b28d0c5..c121982659a27c534ceb21cfee177dbb329a3846 100644 (file)
@@ -713,16 +713,23 @@ EXPORT_SYMBOL_GPL(put_nfs_open_context);
  * Ensure that mmap has a recent RPC credential for use when writing out
  * shared pages
  */
-void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
+void nfs_inode_attach_open_context(struct nfs_open_context *ctx)
 {
-       struct inode *inode = file_inode(filp);
+       struct inode *inode = ctx->dentry->d_inode;
        struct nfs_inode *nfsi = NFS_I(inode);
 
-       filp->private_data = get_nfs_open_context(ctx);
        spin_lock(&inode->i_lock);
        list_add(&ctx->list, &nfsi->open_files);
        spin_unlock(&inode->i_lock);
 }
+EXPORT_SYMBOL_GPL(nfs_inode_attach_open_context);
+
+void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
+{
+       filp->private_data = get_nfs_open_context(ctx);
+       if (list_empty(&ctx->list))
+               nfs_inode_attach_open_context(ctx);
+}
 EXPORT_SYMBOL_GPL(nfs_file_set_open_context);
 
 /*
@@ -748,10 +755,11 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c
 
 static void nfs_file_clear_open_context(struct file *filp)
 {
-       struct inode *inode = file_inode(filp);
        struct nfs_open_context *ctx = nfs_file_open_context(filp);
 
        if (ctx) {
+               struct inode *inode = ctx->dentry->d_inode;
+
                filp->private_data = NULL;
                spin_lock(&inode->i_lock);
                list_move_tail(&ctx->list, &NFS_I(inode)->open_files);
index aaf2c1324be7ded0c6115538e0db380c254ea936..65467abbd5a67f5d439b423f4526560cc53e3485 100644 (file)
@@ -2002,8 +2002,11 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
                goto out;
 
        ctx->state = state;
-       if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
-               nfs4_schedule_stateid_recovery(server, state);
+       if (dentry->d_inode == state->inode) {
+               nfs_inode_attach_open_context(ctx);
+               if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
+                       nfs4_schedule_stateid_recovery(server, state);
+       }
 out:
        return ret;
 }
index fc01d5cb4cf1e013afc41f42f9f9f9b6da6908b7..1384ed92cad65801e50f1b2f4e4cc247ee1e1f84 100644 (file)
@@ -356,6 +356,7 @@ extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ct
 extern void put_nfs_open_context(struct nfs_open_context *ctx);
 extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode);
 extern struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, fmode_t f_mode);
+extern void nfs_inode_attach_open_context(struct nfs_open_context *ctx);
 extern void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx);
 extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx);
 extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx);