]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
NFS: Allow the NFS generic code to pass in a verifier to readdir
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 2 Nov 2020 22:34:23 +0000 (17:34 -0500)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 2 Dec 2020 19:05:52 +0000 (14:05 -0500)
If we're ever going to allow support for servers that use the readdir
verifier, then that use needs to be managed by the middle layers as
those need to be able to reject cookies from other verifiers.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
Tested-by: Benjamin Coddington <bcodding@redhat.com>
Tested-by: Dave Wysochanski <dwysocha@redhat.com>
fs/nfs/dir.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4proc.c
fs/nfs/proc.c
include/linux/nfs_xdr.h

index b226f6f3ae9694d015adced3f2fcd159b7dbb309..3ee0668a971921901184aa344305f6d743e24c59 100644 (file)
@@ -469,8 +469,20 @@ static int nfs_readdir_xdr_filler(struct nfs_readdir_descriptor *desc,
                                  u64 cookie, struct page **pages,
                                  size_t bufsize)
 {
-       struct file *file = desc->file;
-       struct inode *inode = file_inode(file);
+       struct inode *inode = file_inode(desc->file);
+       __be32 verf_res[2];
+       struct nfs_readdir_arg arg = {
+               .dentry = file_dentry(desc->file),
+               .cred = desc->file->f_cred,
+               .verf = NFS_I(inode)->cookieverf,
+               .cookie = cookie,
+               .pages = pages,
+               .page_len = bufsize,
+               .plus = desc->plus,
+       };
+       struct nfs_readdir_res res = {
+               .verf = verf_res,
+       };
        unsigned long   timestamp, gencount;
        int             error;
 
@@ -478,20 +490,21 @@ static int nfs_readdir_xdr_filler(struct nfs_readdir_descriptor *desc,
        timestamp = jiffies;
        gencount = nfs_inc_attr_generation_counter();
        desc->dir_verifier = nfs_save_change_attribute(inode);
-       error = NFS_PROTO(inode)->readdir(file_dentry(file), file->f_cred,
-                                         cookie, pages, bufsize, desc->plus);
+       error = NFS_PROTO(inode)->readdir(&arg, &res);
        if (error < 0) {
                /* We requested READDIRPLUS, but the server doesn't grok it */
                if (error == -ENOTSUPP && desc->plus) {
                        NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS;
                        clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
-                       desc->plus = false;
+                       desc->plus = arg.plus = false;
                        goto again;
                }
                goto error;
        }
        desc->timestamp = timestamp;
        desc->gencount = gencount;
+       memcpy(NFS_I(inode)->cookieverf, res.verf,
+              sizeof(NFS_I(inode)->cookieverf));
 error:
        return error;
 }
index 6b66b73a50ebbde562859038a92b30bd50c817e5..5c4e23abc3451bc6a47fe9f0b7e5c956ce7e3de6 100644 (file)
@@ -662,37 +662,36 @@ out:
  * Also note that this implementation handles both plain readdir and
  * readdirplus.
  */
-static int
-nfs3_proc_readdir(struct dentry *dentry, const struct cred *cred,
-                 u64 cookie, struct page **pages, unsigned int count, bool plus)
+static int nfs3_proc_readdir(struct nfs_readdir_arg *nr_arg,
+                            struct nfs_readdir_res *nr_res)
 {
-       struct inode            *dir = d_inode(dentry);
-       __be32                  *verf = NFS_I(dir)->cookieverf;
+       struct inode            *dir = d_inode(nr_arg->dentry);
        struct nfs3_readdirargs arg = {
                .fh             = NFS_FH(dir),
-               .cookie         = cookie,
-               .verf           = {verf[0], verf[1]},
-               .plus           = plus,
-               .count          = count,
-               .pages          = pages
+               .cookie         = nr_arg->cookie,
+               .plus           = nr_arg->plus,
+               .count          = nr_arg->page_len,
+               .pages          = nr_arg->pages
        };
        struct nfs3_readdirres  res = {
-               .verf           = verf,
-               .plus           = plus
+               .verf           = nr_res->verf,
+               .plus           = nr_arg->plus,
        };
        struct rpc_message      msg = {
                .rpc_proc       = &nfs3_procedures[NFS3PROC_READDIR],
                .rpc_argp       = &arg,
                .rpc_resp       = &res,
-               .rpc_cred       = cred,
+               .rpc_cred       = nr_arg->cred,
        };
        int status = -ENOMEM;
 
-       if (plus)
+       if (nr_arg->plus)
                msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS];
+       if (arg.cookie)
+               memcpy(arg.verf, nr_arg->verf, sizeof(arg.verf));
 
-       dprintk("NFS call  readdir%s %d\n",
-                       plus? "plus" : "", (unsigned int) cookie);
+       dprintk("NFS call  readdir%s %llu\n", nr_arg->plus ? "plus" : "",
+               (unsigned long long)nr_arg->cookie);
 
        res.dir_attr = nfs_alloc_fattr();
        if (res.dir_attr == NULL)
@@ -705,8 +704,8 @@ nfs3_proc_readdir(struct dentry *dentry, const struct cred *cred,
 
        nfs_free_fattr(res.dir_attr);
 out:
-       dprintk("NFS reply readdir%s: %d\n",
-                       plus? "plus" : "", status);
+       dprintk("NFS reply readdir%s: %d\n", nr_arg->plus ? "plus" : "",
+               status);
        return status;
 }
 
index 66f1f4a5c74cbd980402a0cdbc8abb0226ed70a0..adcaba68eaeda8242fc73bfde229a15a019574ee 100644 (file)
@@ -4961,41 +4961,40 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
        return err;
 }
 
-static int _nfs4_proc_readdir(struct dentry *dentry, const struct cred *cred,
-               u64 cookie, struct page **pages, unsigned int count, bool plus)
+static int _nfs4_proc_readdir(struct nfs_readdir_arg *nr_arg,
+                             struct nfs_readdir_res *nr_res)
 {
-       struct inode            *dir = d_inode(dentry);
+       struct inode            *dir = d_inode(nr_arg->dentry);
        struct nfs_server       *server = NFS_SERVER(dir);
        struct nfs4_readdir_arg args = {
                .fh = NFS_FH(dir),
-               .pages = pages,
+               .pages = nr_arg->pages,
                .pgbase = 0,
-               .count = count,
-               .plus = plus,
+               .count = nr_arg->page_len,
+               .plus = nr_arg->plus,
        };
        struct nfs4_readdir_res res;
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR],
                .rpc_argp = &args,
                .rpc_resp = &res,
-               .rpc_cred = cred,
+               .rpc_cred = nr_arg->cred,
        };
        int                     status;
 
-       dprintk("%s: dentry = %pd2, cookie = %Lu\n", __func__,
-                       dentry,
-                       (unsigned long long)cookie);
+       dprintk("%s: dentry = %pd2, cookie = %llu\n", __func__,
+               nr_arg->dentry, (unsigned long long)nr_arg->cookie);
        if (!(server->caps & NFS_CAP_SECURITY_LABEL))
                args.bitmask = server->attr_bitmask_nl;
        else
                args.bitmask = server->attr_bitmask;
 
-       nfs4_setup_readdir(cookie, NFS_I(dir)->cookieverf, dentry, &args);
+       nfs4_setup_readdir(nr_arg->cookie, nr_arg->verf, nr_arg->dentry, &args);
        res.pgbase = args.pgbase;
        status = nfs4_call_sync(server->client, server, &msg, &args.seq_args,
                        &res.seq_res, 0);
        if (status >= 0) {
-               memcpy(NFS_I(dir)->cookieverf, res.verifier.data, NFS4_VERIFIER_SIZE);
+               memcpy(nr_res->verf, res.verifier.data, NFS4_VERIFIER_SIZE);
                status += args.pgbase;
        }
 
@@ -5005,19 +5004,18 @@ static int _nfs4_proc_readdir(struct dentry *dentry, const struct cred *cred,
        return status;
 }
 
-static int nfs4_proc_readdir(struct dentry *dentry, const struct cred *cred,
-               u64 cookie, struct page **pages, unsigned int count, bool plus)
+static int nfs4_proc_readdir(struct nfs_readdir_arg *arg,
+                            struct nfs_readdir_res *res)
 {
        struct nfs4_exception exception = {
                .interruptible = true,
        };
        int err;
        do {
-               err = _nfs4_proc_readdir(dentry, cred, cookie,
-                               pages, count, plus);
-               trace_nfs4_readdir(d_inode(dentry), err);
-               err = nfs4_handle_exception(NFS_SERVER(d_inode(dentry)), err,
-                               &exception);
+               err = _nfs4_proc_readdir(arg, res);
+               trace_nfs4_readdir(d_inode(arg->dentry), err);
+               err = nfs4_handle_exception(NFS_SERVER(d_inode(arg->dentry)),
+                                           err, &exception);
        } while (exception.retry);
        return err;
 }
index 15c865cc837fa22bf9b3e015d4b96cb021c7c049..73ab7c59d3a768584e43d12b802819010c6094b8 100644 (file)
@@ -499,26 +499,26 @@ nfs_proc_rmdir(struct inode *dir, const struct qstr *name)
  * sure it is syntactically correct; the entries itself are decoded
  * from nfs_readdir by calling the decode_entry function directly.
  */
-static int
-nfs_proc_readdir(struct dentry *dentry, const struct cred *cred,
-                u64 cookie, struct page **pages, unsigned int count, bool plus)
+static int nfs_proc_readdir(struct nfs_readdir_arg *nr_arg,
+                           struct nfs_readdir_res *nr_res)
 {
-       struct inode            *dir = d_inode(dentry);
+       struct inode            *dir = d_inode(nr_arg->dentry);
        struct nfs_readdirargs  arg = {
                .fh             = NFS_FH(dir),
-               .cookie         = cookie,
-               .count          = count,
-               .pages          = pages,
+               .cookie         = nr_arg->cookie,
+               .count          = nr_arg->page_len,
+               .pages          = nr_arg->pages,
        };
        struct rpc_message      msg = {
                .rpc_proc       = &nfs_procedures[NFSPROC_READDIR],
                .rpc_argp       = &arg,
-               .rpc_cred       = cred,
+               .rpc_cred       = nr_arg->cred,
        };
        int                     status;
 
-       dprintk("NFS call  readdir %d\n", (unsigned int)cookie);
+       dprintk("NFS call  readdir %llu\n", (unsigned long long)nr_arg->cookie);
        status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+       nr_res->verf[0] = nr_res->verf[1] = 0;
 
        nfs_invalidate_atime(dir);
 
index d63cb862d58e5116c69eba7f728fde8202f69f88..3327239fa2f9a765bc757d24044b709669b41218 100644 (file)
@@ -750,6 +750,20 @@ struct nfs_entry {
        struct nfs_server *     server;
 };
 
+struct nfs_readdir_arg {
+       struct dentry           *dentry;
+       const struct cred       *cred;
+       __be32                  *verf;
+       u64                     cookie;
+       struct page             **pages;
+       unsigned int            page_len;
+       bool                    plus;
+};
+
+struct nfs_readdir_res {
+       __be32                  *verf;
+};
+
 /*
  * The following types are for NFSv2 only.
  */
@@ -1744,8 +1758,7 @@ struct nfs_rpc_ops {
                            unsigned int, struct iattr *);
        int     (*mkdir)   (struct inode *, struct dentry *, struct iattr *);
        int     (*rmdir)   (struct inode *, const struct qstr *);
-       int     (*readdir) (struct dentry *, const struct cred *,
-                           u64, struct page **, unsigned int, bool);
+       int     (*readdir) (struct nfs_readdir_arg *, struct nfs_readdir_res *);
        int     (*mknod)   (struct inode *, struct dentry *, struct iattr *,
                            dev_t);
        int     (*statfs)  (struct nfs_server *, struct nfs_fh *,