]> www.infradead.org Git - users/hch/misc.git/commitdiff
NFS: add a clientid mount option nfs-clientid-mount-options
authorChristoph Hellwig <hch@lst.de>
Sun, 13 Jul 2025 04:45:37 +0000 (06:45 +0200)
committerChristoph Hellwig <hch@lst.de>
Fri, 18 Jul 2025 08:15:59 +0000 (10:15 +0200)
Add a mount option to set a clientid, similarly to how it can be
configured through the per-netfs sysfs file.  This allows for easy
testing of behavior that relies on the client ID likes locks or
delegations with having to resort to separate VMs or containers.

Signed-off-by: Christoph Hellwig <hch@lst.de>
fs/nfs/client.c
fs/nfs/fs_context.c
fs/nfs/internal.h
fs/nfs/nfs4client.c
fs/nfs/nfs4proc.c
include/linux/nfs_fs_sb.h

index 47258dc3af70b8f677a77217395d4195492325e1..1a55debab6e543e7f805e3b15190c21d8e898005 100644 (file)
@@ -181,6 +181,12 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
        clp->cl_nconnect = cl_init->nconnect;
        clp->cl_max_connect = cl_init->max_connect ? cl_init->max_connect : 1;
        clp->cl_net = get_net_track(cl_init->net, &clp->cl_ns_tracker, GFP_KERNEL);
+       if (cl_init->clientid) {
+               err = -ENOMEM;
+               clp->clientid = kstrdup(cl_init->clientid, GFP_KERNEL);
+               if (!clp->clientid)
+                       goto error_free_host;
+       }
 
 #if IS_ENABLED(CONFIG_NFS_LOCALIO)
        seqlock_init(&clp->cl_boot_lock);
@@ -193,6 +199,8 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
        clp->cl_xprtsec = cl_init->xprtsec;
        return clp;
 
+error_free_host:
+       kfree(clp->cl_hostname);
 error_cleanup:
        put_nfs_version(clp->cl_nfs_mod);
 error_dealloc:
@@ -254,6 +262,7 @@ void nfs_free_client(struct nfs_client *clp)
        put_nfs_version(clp->cl_nfs_mod);
        kfree(clp->cl_hostname);
        kfree(clp->cl_acceptor);
+       kfree(clp->clientid);
        kfree_rcu(clp, rcu);
 }
 EXPORT_SYMBOL_GPL(nfs_free_client);
@@ -339,6 +348,9 @@ again:
                if (clp->cl_xprtsec.policy != data->xprtsec.policy)
                        continue;
 
+               if (data->clientid && data->clientid != clp->clientid)
+                       continue;
+
                refcount_inc(&clp->cl_count);
                return clp;
        }
index 9e94d18448ffcf2e2c114dac177f11ed66abe886..fe9ecdc8db3c44a1a7cdeed74d3fbb2396d7a63d 100644 (file)
@@ -98,6 +98,7 @@ enum nfs_param {
        Opt_xprtsec,
        Opt_cert_serial,
        Opt_privkey_serial,
+       Opt_clientid,
 };
 
 enum {
@@ -225,6 +226,7 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = {
        fsparam_string("xprtsec",       Opt_xprtsec),
        fsparam_s32("cert_serial",      Opt_cert_serial),
        fsparam_s32("privkey_serial",   Opt_privkey_serial),
+       fsparam_string("clientid",      Opt_clientid),
        {}
 };
 
@@ -1031,6 +1033,14 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
                        goto out_invalid_value;
                }
                break;
+       case Opt_clientid:
+               if (!param->string || strlen(param->string) == 0 ||
+                   strlen(param->string) > NFS4_CLIENT_ID_UNIQ_LEN - 1)
+                       goto out_of_bounds;
+               kfree(ctx->clientid);
+               ctx->clientid = param->string;
+               param->string = NULL;
+               break;
 
                /*
                 * Special options
@@ -1650,6 +1660,7 @@ static int nfs_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
        ctx->nfs_server.hostname        = NULL;
        ctx->fscache_uniq               = NULL;
        ctx->clone_data.fattr           = NULL;
+       ctx->clientid                   = NULL;
        fc->fs_private = ctx;
        return 0;
 }
@@ -1670,6 +1681,7 @@ static void nfs_fs_context_free(struct fs_context *fc)
                kfree(ctx->fscache_uniq);
                nfs_free_fhandle(ctx->mntfh);
                nfs_free_fattr(ctx->clone_data.fattr);
+               kfree(ctx->clientid);
                kfree(ctx);
        }
 }
index d55dce8bf04372ce9c6765d37d9545ed8595473a..1e9f87f83a31e8ab460b5e063d865a283e1d8bab 100644 (file)
@@ -86,6 +86,7 @@ struct nfs_client_initdata {
        struct xprtsec_parms xprtsec;
        unsigned long connect_timeout;
        unsigned long reconnect_timeout;
+       const char *clientid;
 };
 
 /*
@@ -115,6 +116,7 @@ struct nfs_fs_context {
        unsigned short          mountfamily;
        bool                    has_sec_mnt_opts;
        int                     lock_status;
+       char                    *clientid;
 
        struct {
                union {
index 2e623da1a78794cc07f2885c5d2441b9e80fc083..3ab5cc985224e2467e7750c2e068e46754a92d39 100644 (file)
@@ -1153,6 +1153,7 @@ static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc)
                .xprtsec = ctx->xprtsec,
                .nconnect = ctx->nfs_server.nconnect,
                .max_connect = ctx->nfs_server.max_connect,
+               .clientid = ctx->clientid,
        };
        int error;
 
index ef2077e185b6a7a8c193718e78a2a6519d8358af..ad53bc4ef50c1b4d05c1ffb57f5af5e63ff8846d 100644 (file)
@@ -6487,6 +6487,11 @@ nfs4_get_uniquifier(struct nfs_client *clp, char *buf, size_t buflen)
 
        buf[0] = '\0';
 
+       if (clp->clientid) {
+               strscpy(buf, clp->clientid, buflen);
+               goto out;
+       }
+
        if (nn_clp) {
                rcu_read_lock();
                id = rcu_dereference(nn_clp->identifier);
@@ -6497,7 +6502,7 @@ nfs4_get_uniquifier(struct nfs_client *clp, char *buf, size_t buflen)
 
        if (nfs4_client_id_uniquifier[0] != '\0' && buf[0] == '\0')
                strscpy(buf, nfs4_client_id_uniquifier, buflen);
-
+out:
        return strlen(buf);
 }
 
index d2d36711a1190b36c9d140ed78614a2e9d0fc181..73bed04529a722b8c3225c1ad81a34bad0c1dcf3 100644 (file)
@@ -128,6 +128,7 @@ struct nfs_client {
        netns_tracker           cl_ns_tracker;
        struct list_head        pending_cb_stateids;
        struct rcu_head         rcu;
+       const char              *clientid;
 
 #if IS_ENABLED(CONFIG_NFS_LOCALIO)
        struct timespec64       cl_nfssvc_boot;