]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
nfsd/sunrpc: add svc_rqst->rq_private pointer and remove rq_lease_breaker
authorJeff Layton <jlayton@kernel.org>
Tue, 13 Jan 2026 18:37:39 +0000 (13:37 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 30 Mar 2026 01:25:09 +0000 (21:25 -0400)
rq_lease_breaker has always been a NFSv4 specific layering violation in
svc_rqst. The reason it's there though is that we need a place that is
thread-local, and accessible from the svc_rqst pointer.

Add a new rq_private pointer to struct svc_rqst. This is intended for
use by the threads that are handling the service. sunrpc code doesn't
touch it.

In nfsd, define a new struct nfsd_thread_local_info. nfsd declares one
of these on the stack and puts a pointer to it in rq_private.

Add a new ntli_lease_breaker field to the new struct and convert all of
the places that access rq_lease_breaker to use the new field instead.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Benjamin Coddington <bcodding@hammerspace.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfsd.h
fs/nfsd/nfssvc.c
include/linux/sunrpc/svc.h

index 6880c5c520e75da7ce08a107546a66eeef5110d9..85e94c30285a26e6f1b5f0298ad98584341e2240 100644 (file)
@@ -3043,6 +3043,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
        struct svc_fh *current_fh = &cstate->current_fh;
        struct svc_fh *save_fh = &cstate->save_fh;
        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+       struct nfsd_thread_local_info *ntli = rqstp->rq_private;
        __be32          status;
 
        resp->xdr = &rqstp->rq_res_stream;
@@ -3081,7 +3082,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
        }
        check_if_stalefh_allowed(args);
 
-       rqstp->rq_lease_breaker = (void **)&cstate->clp;
+       ntli->ntli_lease_breaker = &cstate->clp;
 
        trace_nfsd_compound(rqstp, args->tag, args->taglen, args->client_opcnt);
        while (!status && resp->opcnt < args->opcnt) {
index 6b9c399b89dfb71a52b9c97f0efe9a1dea0558a6..d8b0bd8ac842a51b9515975ce508bf58618fd678 100644 (file)
@@ -5535,13 +5535,15 @@ nfsd_break_deleg_cb(struct file_lease *fl)
 static bool nfsd_breaker_owns_lease(struct file_lease *fl)
 {
        struct nfs4_delegation *dl = fl->c.flc_owner;
+       struct nfsd_thread_local_info *ntli;
        struct svc_rqst *rqst;
        struct nfs4_client *clp;
 
        rqst = nfsd_current_rqst();
        if (!nfsd_v4client(rqst))
                return false;
-       clp = *(rqst->rq_lease_breaker);
+       ntli = rqst->rq_private;
+       clp = *ntli->ntli_lease_breaker;
        return dl->dl_stid.sc_client == clp;
 }
 
@@ -9348,13 +9350,14 @@ __be32
 nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry,
                             struct nfs4_delegation **pdp)
 {
-       __be32 status;
        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+       struct nfsd_thread_local_info *ntli = rqstp->rq_private;
        struct file_lock_context *ctx;
        struct nfs4_delegation *dp = NULL;
        struct file_lease *fl;
        struct nfs4_cb_fattr *ncf;
        struct inode *inode = d_inode(dentry);
+       __be32 status;
 
        ctx = locks_inode_context(inode);
        if (!ctx)
@@ -9375,7 +9378,7 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry,
                break;
        }
        if (dp == NULL || dp == NON_NFSD_LEASE ||
-           dp->dl_recall.cb_clp == *(rqstp->rq_lease_breaker)) {
+           dp->dl_recall.cb_clp == *(ntli->ntli_lease_breaker)) {
                spin_unlock(&ctx->flc_lock);
                if (dp == NON_NFSD_LEASE) {
                        status = nfserrno(nfsd_open_break_lease(inode,
index a01d709533585f09df1399b85eecc36ea7c466c5..938906c6d10cd65e7e3a1bc889b4fdcb56918f6f 100644 (file)
@@ -82,6 +82,10 @@ extern atomic_t                      nfsd_th_cnt;            /* number of available threads */
 
 extern const struct seq_operations nfs_exports_op;
 
+struct nfsd_thread_local_info {
+       struct nfs4_client      **ntli_lease_breaker;
+};
+
 /*
  * Common void argument and result helpers
  */
index 4a04208393b823d0b5ef738a614723ecd6dc91a0..fd979e5392a14d0cc11c154e990b9ec4c79be2d0 100644 (file)
@@ -887,6 +887,7 @@ nfsd(void *vrqstp)
        struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list);
        struct net *net = perm_sock->xpt_net;
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       struct nfsd_thread_local_info ntli = { };
        bool have_mutex = false;
 
        /* At this point, the thread shares current->fs
@@ -901,6 +902,10 @@ nfsd(void *vrqstp)
 
        set_freezable();
 
+       /* use dynamic allocation if ntli should ever become large */
+       static_assert(sizeof(struct nfsd_thread_local_info) < 256);
+       rqstp->rq_private = &ntli;
+
        /*
         * The main request loop
         */
index 4dc14c7a711b010473bf03fc401df0e66d9aa4bd..ab8237ba9596e9f31e2c42abedec435a23162b40 100644 (file)
@@ -175,6 +175,9 @@ static inline unsigned long svc_serv_maxpages(const struct svc_serv *serv)
 /*
  * The context of a single thread, including the request currently being
  * processed.
+ *
+ * RPC programs are free to use rq_private to stash thread-local information.
+ * The sunrpc layer will not access it.
  */
 struct svc_rqst {
        struct list_head        rq_all;         /* all threads list */
@@ -251,7 +254,7 @@ struct svc_rqst {
        unsigned long           bc_to_initval;
        unsigned int            bc_to_retries;
        unsigned int            rq_status_counter; /* RPC processing counter */
-       void                    **rq_lease_breaker; /* The v4 client breaking a lease */
+       void                    *rq_private;    /* For use by the service thread */
 };
 
 /* bits for rq_flags */