From: Jeff Layton Date: Tue, 13 Jan 2026 18:37:39 +0000 (-0500) Subject: nfsd/sunrpc: add svc_rqst->rq_private pointer and remove rq_lease_breaker X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=55b6dd54c3bcb6edf7ad630a4510759f4b0cf1cd;p=thirdparty%2Fkernel%2Fstable.git nfsd/sunrpc: add svc_rqst->rq_private pointer and remove rq_lease_breaker 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 Reviewed-by: Benjamin Coddington Signed-off-by: Chuck Lever --- diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 6880c5c520e75..85e94c30285a2 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -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) { diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6b9c399b89dfb..d8b0bd8ac842a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -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, diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index a01d709533585..938906c6d10cd 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -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 */ diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 4a04208393b82..fd979e5392a14 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -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 */ diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 4dc14c7a711b0..ab8237ba9596e 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -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 */