]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
NFSv4: Remove duplicate lookups, capability probes and fsinfo calls
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Sun, 3 Aug 2025 23:32:00 +0000 (16:32 -0700)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 4 Aug 2025 16:48:16 +0000 (09:48 -0700)
When crossing into a new filesystem, the NFSv4 client will look up the
new directory, and then call nfs4_server_capabilities() as well as
nfs4_do_fsinfo() at least twice.

This patch removes the duplicate calls, and reduces the initial lookup
to retrieve just a minimal set of attributes.

Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/nfs4_fs.h
fs/nfs/nfs4getroot.c
fs/nfs/nfs4proc.c

index d3ca91f60fc1e790a9d5302b0a4b4ef81ccb8671..c34c89af9c7d5ffd08997b2842c914cefcebc9e3 100644 (file)
@@ -63,7 +63,7 @@ struct nfs4_minor_version_ops {
        bool    (*match_stateid)(const nfs4_stateid *,
                        const nfs4_stateid *);
        int     (*find_root_sec)(struct nfs_server *, struct nfs_fh *,
-                       struct nfs_fsinfo *);
+                                struct nfs_fattr *);
        void    (*free_lock_state)(struct nfs_server *,
                        struct nfs4_lock_state *);
        int     (*test_and_free_expired)(struct nfs_server *,
@@ -296,7 +296,8 @@ extern int nfs4_call_sync(struct rpc_clnt *, struct nfs_server *,
 extern void nfs4_init_sequence(struct nfs4_sequence_args *, struct nfs4_sequence_res *, int, int);
 extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, const struct cred *, struct nfs4_setclientid_res *);
 extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, const struct cred *);
-extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *, bool);
+extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *,
+                               struct nfs_fattr *, bool);
 extern int nfs4_proc_bind_conn_to_session(struct nfs_client *, const struct cred *cred);
 extern int nfs4_proc_exchange_id(struct nfs_client *clp, const struct cred *cred);
 extern int nfs4_destroy_clientid(struct nfs_client *clp);
index 1a69479a3a59d3ce780ebff7785edb5202154d0e..e67ea345de69bc684be2d5ac20b480e11808b6f3 100644 (file)
 
 int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool auth_probe)
 {
-       struct nfs_fsinfo fsinfo;
+       struct nfs_fattr *fattr = nfs_alloc_fattr();
        int ret = -ENOMEM;
 
-       fsinfo.fattr = nfs_alloc_fattr();
-       if (fsinfo.fattr == NULL)
+       if (fattr == NULL)
                goto out;
 
        /* Start by getting the root filehandle from the server */
-       ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo, auth_probe);
+       ret = nfs4_proc_get_rootfh(server, mntfh, fattr, auth_probe);
        if (ret < 0) {
                dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret);
                goto out;
        }
 
-       if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE)
-                       || !S_ISDIR(fsinfo.fattr->mode)) {
+       if (!(fattr->valid & NFS_ATTR_FATTR_TYPE) || !S_ISDIR(fattr->mode)) {
                printk(KERN_ERR "nfs4_get_rootfh:"
                       " getroot encountered non-directory\n");
                ret = -ENOTDIR;
                goto out;
        }
 
-       memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid));
+       memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
 out:
-       nfs_free_fattr(fsinfo.fattr);
+       nfs_free_fattr(fattr);
        return ret;
 }
index c7c7ec22f21d7532a4a5f61eb2ec35b658c7b519..7d2b67e06cc37f4be64e4c4eedb280cba1c40e6e 100644 (file)
@@ -4240,15 +4240,18 @@ out:
 }
 
 static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
-               struct nfs_fsinfo *info)
+                            struct nfs_fattr *fattr)
 {
-       u32 bitmask[3];
+       u32 bitmask[3] = {
+               [0] = FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE |
+                     FATTR4_WORD0_SIZE | FATTR4_WORD0_FSID,
+       };
        struct nfs4_lookup_root_arg args = {
                .bitmask = bitmask,
        };
        struct nfs4_lookup_res res = {
                .server = server,
-               .fattr = info->fattr,
+               .fattr = fattr,
                .fh = fhandle,
        };
        struct rpc_message msg = {
@@ -4257,27 +4260,20 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
                .rpc_resp = &res,
        };
 
-       bitmask[0] = nfs4_fattr_bitmap[0];
-       bitmask[1] = nfs4_fattr_bitmap[1];
-       /*
-        * Process the label in the upcoming getfattr
-        */
-       bitmask[2] = nfs4_fattr_bitmap[2] & ~FATTR4_WORD2_SECURITY_LABEL;
-
-       nfs_fattr_init(info->fattr);
+       nfs_fattr_init(fattr);
        return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 }
 
 static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
-               struct nfs_fsinfo *info)
+                           struct nfs_fattr *fattr)
 {
        struct nfs4_exception exception = {
                .interruptible = true,
        };
        int err;
        do {
-               err = _nfs4_lookup_root(server, fhandle, info);
-               trace_nfs4_lookup_root(server, fhandle, info->fattr, err);
+               err = _nfs4_lookup_root(server, fhandle, fattr);
+               trace_nfs4_lookup_root(server, fhandle, fattr, err);
                switch (err) {
                case 0:
                case -NFS4ERR_WRONGSEC:
@@ -4290,8 +4286,9 @@ out:
        return err;
 }
 
-static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
-                               struct nfs_fsinfo *info, rpc_authflavor_t flavor)
+static int nfs4_lookup_root_sec(struct nfs_server *server,
+                               struct nfs_fh *fhandle, struct nfs_fattr *fattr,
+                               rpc_authflavor_t flavor)
 {
        struct rpc_auth_create_args auth_args = {
                .pseudoflavor = flavor,
@@ -4301,7 +4298,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
        auth = rpcauth_create(&auth_args, server->client);
        if (IS_ERR(auth))
                return -EACCES;
-       return nfs4_lookup_root(server, fhandle, info);
+       return nfs4_lookup_root(server, fhandle, fattr);
 }
 
 /*
@@ -4314,7 +4311,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
  * negative errno value.
  */
 static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
-                             struct nfs_fsinfo *info)
+                             struct nfs_fattr *fattr)
 {
        /* Per 3530bis 15.33.5 */
        static const rpc_authflavor_t flav_array[] = {
@@ -4330,8 +4327,9 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
        if (server->auth_info.flavor_len > 0) {
                /* try each flavor specified by user */
                for (i = 0; i < server->auth_info.flavor_len; i++) {
-                       status = nfs4_lookup_root_sec(server, fhandle, info,
-                                               server->auth_info.flavors[i]);
+                       status = nfs4_lookup_root_sec(
+                               server, fhandle, fattr,
+                               server->auth_info.flavors[i]);
                        if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
                                continue;
                        break;
@@ -4339,7 +4337,7 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
        } else {
                /* no flavors specified by user, try default list */
                for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
-                       status = nfs4_lookup_root_sec(server, fhandle, info,
+                       status = nfs4_lookup_root_sec(server, fhandle, fattr,
                                                      flav_array[i]);
                        if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
                                continue;
@@ -4363,28 +4361,22 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
  * nfs4_proc_get_rootfh - get file handle for server's pseudoroot
  * @server: initialized nfs_server handle
  * @fhandle: we fill in the pseudo-fs root file handle
- * @info: we fill in an FSINFO struct
+ * @fattr: we fill in a bare bones struct fattr
  * @auth_probe: probe the auth flavours
  *
  * Returns zero on success, or a negative errno.
  */
 int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
-                        struct nfs_fsinfo *info,
-                        bool auth_probe)
+                        struct nfs_fattr *fattr, bool auth_probe)
 {
        int status = 0;
 
        if (!auth_probe)
-               status = nfs4_lookup_root(server, fhandle, info);
+               status = nfs4_lookup_root(server, fhandle, fattr);
 
        if (auth_probe || status == NFS4ERR_WRONGSEC)
-               status = server->nfs_client->cl_mvops->find_root_sec(server,
-                               fhandle, info);
-
-       if (status == 0)
-               status = nfs4_server_capabilities(server, fhandle);
-       if (status == 0)
-               status = nfs4_do_fsinfo(server, fhandle, info);
+               status = server->nfs_client->cl_mvops->find_root_sec(
+                       server, fhandle, fattr);
 
        return nfs4_map_errors(status);
 }
@@ -10351,10 +10343,10 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
  * Use the state managment nfs_client cl_rpcclient, which uses krb5i (if
  * possible) as per RFC3530bis and RFC5661 Security Considerations sections
  */
-static int
-_nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
-                   struct nfs_fsinfo *info,
-                   struct nfs4_secinfo_flavors *flavors, bool use_integrity)
+static int _nfs41_proc_secinfo_no_name(struct nfs_server *server,
+                                      struct nfs_fh *fhandle,
+                                      struct nfs4_secinfo_flavors *flavors,
+                                      bool use_integrity)
 {
        struct nfs41_secinfo_no_name_args args = {
                .style = SECINFO_STYLE_CURRENT_FH,
@@ -10398,9 +10390,9 @@ _nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
        return status;
 }
 
-static int
-nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
-                          struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
+static int nfs41_proc_secinfo_no_name(struct nfs_server *server,
+                                     struct nfs_fh *fhandle,
+                                     struct nfs4_secinfo_flavors *flavors)
 {
        struct nfs4_exception exception = {
                .interruptible = true,
@@ -10412,7 +10404,7 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
 
                /* try to use integrity protection with machine cred */
                if (_nfs4_is_integrity_protected(server->nfs_client))
-                       err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
+                       err = _nfs41_proc_secinfo_no_name(server, fhandle,
                                                          flavors, true);
 
                /*
@@ -10422,7 +10414,7 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
                 * the current filesystem's rpc_client and the user cred.
                 */
                if (err == -NFS4ERR_WRONGSEC)
-                       err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
+                       err = _nfs41_proc_secinfo_no_name(server, fhandle,
                                                          flavors, false);
 
                switch (err) {
@@ -10438,9 +10430,8 @@ out:
        return err;
 }
 
-static int
-nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
-                   struct nfs_fsinfo *info)
+static int nfs41_find_root_sec(struct nfs_server *server,
+                              struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
        int err;
        struct page *page;
@@ -10456,14 +10447,14 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
        }
 
        flavors = page_address(page);
-       err = nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
+       err = nfs41_proc_secinfo_no_name(server, fhandle, flavors);
 
        /*
         * Fall back on "guess and check" method if
         * the server doesn't support SECINFO_NO_NAME
         */
        if (err == -NFS4ERR_WRONGSEC || err == -ENOTSUPP) {
-               err = nfs4_find_root_sec(server, fhandle, info);
+               err = nfs4_find_root_sec(server, fhandle, fattr);
                goto out_freepage;
        }
        if (err)
@@ -10488,8 +10479,8 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
                        flavor = RPC_AUTH_MAXFLAVOR;
 
                if (flavor != RPC_AUTH_MAXFLAVOR) {
-                       err = nfs4_lookup_root_sec(server, fhandle,
-                                                  info, flavor);
+                       err = nfs4_lookup_root_sec(server, fhandle, fattr,
+                                                  flavor);
                        if (!err)
                                break;
                }