]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
NFS: Extend rdirplus mount option with "force|none"
authorBenjamin Coddington <bcodding@redhat.com>
Thu, 13 Mar 2025 17:01:22 +0000 (13:01 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Fri, 21 Mar 2025 13:34:52 +0000 (09:34 -0400)
There are certain users that wish to force the NFS client to choose
READDIRPLUS over READDIR for a particular mount.  Update the "rdirplus" mount
option to optionally accept values.  For "rdirplus=force", the NFS client
will always attempt to use READDDIRPLUS.  The setting of "rdirplus=none" is
aliased to the existing "nordirplus".

Signed-off-by: Benjamin Coddington <bcodding@redhat.com>
Link: https://lore.kernel.org/r/c4cf0de4c8be0930b91bc74bee310d289781cd3b.1741885071.git.bcodding@redhat.com
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/dir.c
fs/nfs/fs_context.c
fs/nfs/super.c
include/linux/nfs_fs_sb.h

index 2b04038b0e40525be67f1ec512fb0db547e5f6ed..5c4566a8dabb7f3a77309630e91a5fcde28f4bbf 100644 (file)
@@ -666,6 +666,8 @@ static bool nfs_use_readdirplus(struct inode *dir, struct dir_context *ctx,
 {
        if (!nfs_server_capable(dir, NFS_CAP_READDIRPLUS))
                return false;
+       if (NFS_SERVER(dir)->flags & NFS_MOUNT_FORCE_RDIRPLUS)
+               return true;
        if (ctx->pos == 0 ||
            cache_hits + cache_misses > NFS_READDIR_CACHE_USAGE_THRESHOLD)
                return true;
index b069385eea176766591cb7fd010f7efed687c34a..1cabba1231d678a725249fedf4ed70b3c48bb904 100644 (file)
@@ -72,6 +72,8 @@ enum nfs_param {
        Opt_posix,
        Opt_proto,
        Opt_rdirplus,
+       Opt_rdirplus_none,
+       Opt_rdirplus_force,
        Opt_rdma,
        Opt_resvport,
        Opt_retrans,
@@ -174,7 +176,8 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = {
        fsparam_u32   ("port",          Opt_port),
        fsparam_flag_no("posix",        Opt_posix),
        fsparam_string("proto",         Opt_proto),
-       fsparam_flag_no("rdirplus",     Opt_rdirplus),
+       fsparam_flag_no("rdirplus", Opt_rdirplus), // rdirplus|nordirplus
+       fsparam_string("rdirplus",  Opt_rdirplus), // rdirplus=...
        fsparam_flag  ("rdma",          Opt_rdma),
        fsparam_flag_no("resvport",     Opt_resvport),
        fsparam_u32   ("retrans",       Opt_retrans),
@@ -288,6 +291,12 @@ static const struct constant_table nfs_xprtsec_policies[] = {
        {}
 };
 
+static const struct constant_table nfs_rdirplus_tokens[] = {
+       { "none",       Opt_rdirplus_none },
+       { "force",      Opt_rdirplus_force },
+       {}
+};
+
 /*
  * Sanity-check a server address provided by the mount command.
  *
@@ -636,10 +645,25 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
                        ctx->flags &= ~NFS_MOUNT_NOACL;
                break;
        case Opt_rdirplus:
-               if (result.negated)
+               if (result.negated) {
+                       ctx->flags &= ~NFS_MOUNT_FORCE_RDIRPLUS;
                        ctx->flags |= NFS_MOUNT_NORDIRPLUS;
-               else
-                       ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
+               } else if (!param->string) {
+                       ctx->flags &= ~(NFS_MOUNT_NORDIRPLUS | NFS_MOUNT_FORCE_RDIRPLUS);
+               } else {
+                       switch (lookup_constant(nfs_rdirplus_tokens, param->string, -1)) {
+                       case Opt_rdirplus_none:
+                               ctx->flags &= ~NFS_MOUNT_FORCE_RDIRPLUS;
+                               ctx->flags |= NFS_MOUNT_NORDIRPLUS;
+                               break;
+                       case Opt_rdirplus_force:
+                               ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
+                               ctx->flags |= NFS_MOUNT_FORCE_RDIRPLUS;
+                               break;
+                       default:
+                               goto out_invalid_value;
+                       }
+               }
                break;
        case Opt_sharecache:
                if (result.negated)
index aeb715b4a6902dc907b4b4cf2712232b080c497f..96de658a78868d76b24b3418054098628337f61f 100644 (file)
@@ -454,6 +454,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
                { NFS_MOUNT_NONLM, ",nolock", "" },
                { NFS_MOUNT_NOACL, ",noacl", "" },
                { NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" },
+               { NFS_MOUNT_FORCE_RDIRPLUS, ",rdirplus=force", "" },
                { NFS_MOUNT_UNSHARED, ",nosharecache", "" },
                { NFS_MOUNT_NORESVPORT, ",noresvport", "" },
                { 0, NULL, NULL }
index 1711eefcf24fc60c79d4dcb882f2c20261cf74dd..b83d16a42afc58d973af36875e13fd1b2e150c82 100644 (file)
@@ -167,6 +167,7 @@ struct nfs_server {
 #define NFS_MOUNT_TRUNK_DISCOVERY      0x04000000
 #define NFS_MOUNT_SHUTDOWN                     0x08000000
 #define NFS_MOUNT_NO_ALIGNWRITE                0x10000000
+#define NFS_MOUNT_FORCE_RDIRPLUS       0x20000000
 
        unsigned int            fattr_valid;    /* Valid attributes */
        unsigned int            caps;           /* server capabilities */