NFS: Create nfs_open_dir_context
authorBryan Schumaker <bjschuma@netapp.com>
Wed, 23 Mar 2011 18:48:29 +0000 (14:48 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 23 Mar 2011 19:13:11 +0000 (15:13 -0400)
nfs_opendir() created a context that held much more information than we
need for a readdir.  This patch introduces a slimmed-down
nfs_open_dir_context that contains only the cookie and the cred used for
RPC operations.  The new context will eventually be used to help detect
readdir loops.

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

index c5c71cb62fbd5c7396264ffb94eeb93c4ea6a8f7..cda73814f666ac3f0b004834a64e3172be2e8399 100644 (file)
@@ -44,6 +44,7 @@
 /* #define NFS_DEBUG_VERBOSE 1 */
 
 static int nfs_opendir(struct inode *, struct file *);
+static int nfs_closedir(struct inode *, struct file *);
 static int nfs_readdir(struct file *, void *, filldir_t);
 static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *);
 static int nfs_create(struct inode *, struct dentry *, int, struct nameidata *);
@@ -64,7 +65,7 @@ const struct file_operations nfs_dir_operations = {
        .read           = generic_read_dir,
        .readdir        = nfs_readdir,
        .open           = nfs_opendir,
-       .release        = nfs_release,
+       .release        = nfs_closedir,
        .fsync          = nfs_fsync_dir,
 };
 
@@ -133,13 +134,33 @@ const struct inode_operations nfs4_dir_inode_operations = {
 
 #endif /* CONFIG_NFS_V4 */
 
+static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct rpc_cred *cred)
+{
+       struct nfs_open_dir_context *ctx;
+       ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+       if (ctx != NULL) {
+               ctx->dir_cookie = 0;
+               ctx->cred = get_rpccred(cred);
+       } else
+               ctx = ERR_PTR(-ENOMEM);
+       return ctx;
+}
+
+static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx)
+{
+       put_rpccred(ctx->cred);
+       kfree(ctx);
+}
+
 /*
  * Open file
  */
 static int
 nfs_opendir(struct inode *inode, struct file *filp)
 {
-       int res;
+       int res = 0;
+       struct nfs_open_dir_context *ctx;
+       struct rpc_cred *cred;
 
        dfprintk(FILE, "NFS: open dir(%s/%s)\n",
                        filp->f_path.dentry->d_parent->d_name.name,
@@ -147,8 +168,15 @@ nfs_opendir(struct inode *inode, struct file *filp)
 
        nfs_inc_stats(inode, NFSIOS_VFSOPEN);
 
-       /* Call generic open code in order to cache credentials */
-       res = nfs_open(inode, filp);
+       cred = rpc_lookup_cred();
+       if (IS_ERR(cred))
+               return PTR_ERR(cred);
+       ctx = alloc_nfs_open_dir_context(cred);
+       if (IS_ERR(ctx)) {
+               res = PTR_ERR(ctx);
+               goto out;
+       }
+       filp->private_data = ctx;
        if (filp->f_path.dentry == filp->f_path.mnt->mnt_root) {
                /* This is a mountpoint, so d_revalidate will never
                 * have been called, so we need to refresh the
@@ -156,9 +184,18 @@ nfs_opendir(struct inode *inode, struct file *filp)
                 */
                __nfs_revalidate_inode(NFS_SERVER(inode), inode);
        }
+out:
+       put_rpccred(cred);
        return res;
 }
 
+static int
+nfs_closedir(struct inode *inode, struct file *filp)
+{
+       put_nfs_open_dir_context(filp->private_data);
+       return 0;
+}
+
 struct nfs_cache_array_entry {
        u64 cookie;
        u64 ino;
@@ -355,7 +392,8 @@ static
 int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc,
                        struct nfs_entry *entry, struct file *file, struct inode *inode)
 {
-       struct rpc_cred *cred = nfs_file_cred(file);
+       struct nfs_open_dir_context *ctx = file->private_data;
+       struct rpc_cred *cred = ctx->cred;
        unsigned long   timestamp, gencount;
        int             error;
 
@@ -786,6 +824,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        struct inode    *inode = dentry->d_inode;
        nfs_readdir_descriptor_t my_desc,
                        *desc = &my_desc;
+       struct nfs_open_dir_context *dir_ctx = filp->private_data;
        int res;
 
        dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n",
@@ -802,7 +841,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        memset(desc, 0, sizeof(*desc));
 
        desc->file = filp;
-       desc->dir_cookie = &nfs_file_open_context(filp)->dir_cookie;
+       desc->dir_cookie = &dir_ctx->dir_cookie;
        desc->decode = NFS_PROTO(inode)->decode_dirent;
        desc->plus = NFS_USE_READDIRPLUS(inode);
 
@@ -854,6 +893,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
 {
        struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
+       struct nfs_open_dir_context *dir_ctx = filp->private_data;
 
        dfprintk(FILE, "NFS: llseek dir(%s/%s, %lld, %d)\n",
                        dentry->d_parent->d_name.name,
@@ -873,7 +913,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
        }
        if (offset != filp->f_pos) {
                filp->f_pos = offset;
-               nfs_file_open_context(filp)->dir_cookie = 0;
+               dir_ctx->dir_cookie = 0;
        }
 out:
        mutex_unlock(&inode->i_mutex);
index 2f8e61816d75dd5a1620c510ea09111dfe20b326..477a2e512b39ee44316a81b49e080caad45e5e87 100644 (file)
@@ -639,7 +639,6 @@ struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cr
                ctx->mode = f_mode;
                ctx->flags = 0;
                ctx->error = 0;
-               ctx->dir_cookie = 0;
                nfs_init_lock_context(&ctx->lock_context);
                ctx->lock_context.open_context = ctx;
                INIT_LIST_HEAD(&ctx->list);
index cb2add401f253c3920b347d1b5cf766bce9a5761..4b851a02f7f32cd96c29d0ffda8526c0bc47400c 100644 (file)
@@ -95,7 +95,10 @@ struct nfs_open_context {
        int error;
 
        struct list_head list;
+};
 
+struct nfs_open_dir_context {
+       struct rpc_cred *cred;
        __u64 dir_cookie;
 };