[PATCH OLK-5.10] nfsd: split nfsd4_copy into transient and durable async copy objects
From: Jeff Layton <jlayton@kernel.org> mainline inclusion from mainline-v7.3-rc1 commit f307b4f7ed174a3252d2f292904fd276c78c77de category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18939 CVE: CVE-2026-89676 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- struct nfsd4_copy served two roles: as &u->copy it is a transient per-COMPOUND argument in the request buffer; as the heap async_copy it is a durable object (worker kthread, reaper linkage, CB_OFFLOAD callback, IDR stateid) that outlives the COMPOUND, with dup_copy_fields() shuttling state between them. That dual identity was the root of the recent lifetime bugs. Introduce struct nfsd4_async_copy for the durable object. It embeds a struct nfsd4_copy (cp_copy) for the operation parameters/result and adds the durable-only fields: async_copies linkage, task_struct, refcount, reaper TTL, copy stateid, and CB_OFFLOAD callback. The durable object therefore never points into the request buffer. cp_clp stays in nfsd4_copy -- it is a request property read by the sync-copy tracepoints on the transient object. Mechanical split, no intended behavioral change; a step toward folding the copy stateids into the common nfs4_stid infrastructure. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Jeff Layton <jlayton@kernel.org> Link: https://patch.msgid.link/20260710-nfsd-testing-v3-8-a0ff7db6aa3e@kernel.org Signed-off-by: Chuck Lever <cel@kernel.org> Conflicts: fs/nfsd/nfs4proc.c [OLK-5.10 carries the original 5.10 nfsd async-copy design, not the modern one the patch targets, so the split is re-derived on top of OLK-5.10's helpers: nfsd4_get_copy() (not nfsd4_unhash_copy()), check_and_set_stop_copy()/stopped, find_async_copy(), and the separate cb_copy allocated in nfsd4_do_async_copy() for CB_OFFLOAD; cb_copy is retyped to struct nfsd4_async_copy so nfs4_put_copy() keeps working; nfs4_put_copy()/nfsd4_stop_copy()/cleanup_async_copy() adjust only the type and cp_copy field paths; dup_copy_fields() drops the cp_stateid copy] fs/nfsd/nfs4state.c [nfs4_init_copy_state()/nfs4_free_copy_state() updated to struct nfsd4_async_copy; nfs4_free_copy_state() reads cp_copy.cp_clp while the callback stateid stays in the outer struct] fs/nfsd/state.h [forward declaration plus the nfs4_*_copy_state(), nfs4_put_copy() and find_async_copy() prototypes updated to struct nfsd4_async_copy] fs/nfsd/xdr4.h [OLK-5.10's struct nfsd4_copy differs from mainline (cp_intra/ cp_synchronous/stopped/ss_mnt, embedded cp_cb/nfserr, embedded cp_src); only copies/copy_task/refcount/cp_stateid move into the new struct nfsd4_async_copy, and mainline's cp_ttl/cp_cb_offload are omitted since they do not exist in OLK-5.10] Signed-off-by: Lu Jialin <lujialin4@huawei.com> --- fs/nfsd/nfs4proc.c | 79 +++++++++++++++++++++++---------------------- fs/nfsd/nfs4state.c | 6 ++-- fs/nfsd/state.h | 9 +++--- fs/nfsd/xdr4.h | 23 ++++++++++--- 4 files changed, 66 insertions(+), 51 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index ecbde42093d5..76d218280c3a 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1110,11 +1110,11 @@ nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return status; } -void nfs4_put_copy(struct nfsd4_copy *copy) +void nfs4_put_copy(struct nfsd4_async_copy *copy) { if (!refcount_dec_and_test(©->refcount)) return; - atomic_dec(©->cp_nn->pending_async_copies); + atomic_dec(©->cp_copy.cp_nn->pending_async_copies); kfree(copy); } @@ -1131,22 +1131,22 @@ check_and_set_stop_copy(struct nfsd4_copy *copy) return value; } -static void nfsd4_stop_copy(struct nfsd4_copy *copy) +static void nfsd4_stop_copy(struct nfsd4_async_copy *copy) { /* only 1 thread should stop the copy */ - if (!check_and_set_stop_copy(copy)) + if (!check_and_set_stop_copy(©->cp_copy)) kthread_stop(copy->copy_task); nfs4_put_copy(copy); } -static struct nfsd4_copy *nfsd4_get_copy(struct nfs4_client *clp) +static struct nfsd4_async_copy *nfsd4_get_copy(struct nfs4_client *clp) { - struct nfsd4_copy *copy = NULL; + struct nfsd4_async_copy *copy = NULL; spin_lock(&clp->async_lock); if (!list_empty(&clp->async_copies)) { - copy = list_first_entry(&clp->async_copies, struct nfsd4_copy, - copies); + copy = list_first_entry(&clp->async_copies, + struct nfsd4_async_copy, copies); refcount_inc(©->refcount); } spin_unlock(&clp->async_lock); @@ -1155,7 +1155,7 @@ static struct nfsd4_copy *nfsd4_get_copy(struct nfs4_client *clp) void nfsd4_shutdown_copy(struct nfs4_client *clp) { - struct nfsd4_copy *copy; + struct nfsd4_async_copy *copy; while ((copy = nfsd4_get_copy(clp)) != NULL) nfsd4_stop_copy(copy); @@ -1351,7 +1351,8 @@ nfsd4_cleanup_intra_ssc(struct nfsd_file *src, struct nfsd_file *dst) static void nfsd4_cb_offload_release(struct nfsd4_callback *cb) { - struct nfsd4_copy *copy = container_of(cb, struct nfsd4_copy, cp_cb); + struct nfsd4_async_copy *copy = + container_of(cb, struct nfsd4_async_copy, cp_copy.cp_cb); nfs4_put_copy(copy); } @@ -1437,29 +1438,29 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst) if (src->cp_intra) /* for inter, file_src doesn't exist yet */ dst->nf_src = nfsd_file_get(src->nf_src); - memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid)); memcpy(&dst->cp_src, &src->cp_src, sizeof(struct nl4_server)); memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid)); memcpy(&dst->c_fh, &src->c_fh, sizeof(src->c_fh)); dst->ss_mnt = src->ss_mnt; } -static void cleanup_async_copy(struct nfsd4_copy *copy) +static void cleanup_async_copy(struct nfsd4_async_copy *copy) { nfs4_free_copy_state(copy); - nfsd_file_put(copy->nf_dst); - if (copy->cp_intra) - nfsd_file_put(copy->nf_src); - spin_lock(©->cp_clp->async_lock); + nfsd_file_put(copy->cp_copy.nf_dst); + if (copy->cp_copy.cp_intra) + nfsd_file_put(copy->cp_copy.nf_src); + spin_lock(©->cp_copy.cp_clp->async_lock); list_del(©->copies); - spin_unlock(©->cp_clp->async_lock); + spin_unlock(©->cp_copy.cp_clp->async_lock); nfs4_put_copy(copy); } static int nfsd4_do_async_copy(void *data) { - struct nfsd4_copy *copy = (struct nfsd4_copy *)data; - struct nfsd4_copy *cb_copy; + struct nfsd4_async_copy *async = data; + struct nfsd4_copy *copy = &async->cp_copy; + struct nfsd4_async_copy *cb_copy; if (!copy->cp_intra) { /* Inter server SSC */ copy->nf_src = kzalloc(sizeof(struct nfsd_file), GFP_KERNEL); @@ -1479,21 +1480,21 @@ static int nfsd4_do_async_copy(void *data) copy->nfserr = nfsd4_do_copy(copy, 0); do_callback: - cb_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL); + cb_copy = kzalloc(sizeof(struct nfsd4_async_copy), GFP_KERNEL); if (!cb_copy) goto out; refcount_set(&cb_copy->refcount, 1); - memcpy(&cb_copy->cp_res, ©->cp_res, sizeof(copy->cp_res)); - cb_copy->cp_clp = copy->cp_clp; - cb_copy->nfserr = copy->nfserr; - memcpy(&cb_copy->fh, ©->fh, sizeof(copy->fh)); - nfsd4_init_cb(&cb_copy->cp_cb, cb_copy->cp_clp, + memcpy(&cb_copy->cp_copy.cp_res, ©->cp_res, sizeof(copy->cp_res)); + cb_copy->cp_copy.cp_clp = copy->cp_clp; + cb_copy->cp_copy.nfserr = copy->nfserr; + memcpy(&cb_copy->cp_copy.fh, ©->fh, sizeof(copy->fh)); + nfsd4_init_cb(&cb_copy->cp_copy.cp_cb, cb_copy->cp_copy.cp_clp, &nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD); - nfsd4_run_cb(&cb_copy->cp_cb); + nfsd4_run_cb(&cb_copy->cp_copy.cp_cb); out: if (!copy->cp_intra) kfree(copy->nf_src); - cleanup_async_copy(copy); + cleanup_async_copy(async); return 0; } @@ -1503,7 +1504,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, { struct nfsd4_copy *copy = &u->copy; __be32 status; - struct nfsd4_copy *async_copy = NULL; + struct nfsd4_async_copy *async_copy = NULL; if (!copy->cp_intra) { /* Inter server SSC */ if (!inter_copy_offload_enable || copy->cp_synchronous) { @@ -1526,16 +1527,16 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (!copy->cp_synchronous) { struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); - async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL); + async_copy = kzalloc(sizeof(struct nfsd4_async_copy), GFP_KERNEL); if (!async_copy) goto out_err; - async_copy->cp_nn = nn; + async_copy->cp_copy.cp_nn = nn; refcount_set(&async_copy->refcount, 1); /* Arbitrary cap on number of pending async copy operations */ if (atomic_inc_return(&nn->pending_async_copies) > (int)rqstp->rq_pool->sp_nrthreads) goto out_err; - dup_copy_fields(copy, async_copy); + dup_copy_fields(copy, &async_copy->cp_copy); if (!nfs4_init_copy_state(nn, async_copy)) goto out_err; @@ -1545,10 +1546,10 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, async_copy, "%s", "copy thread"); if (IS_ERR(async_copy->copy_task)) goto out_err; - spin_lock(&async_copy->cp_clp->async_lock); + spin_lock(&async_copy->cp_copy.cp_clp->async_lock); list_add(&async_copy->copies, - &async_copy->cp_clp->async_copies); - spin_unlock(&async_copy->cp_clp->async_lock); + &async_copy->cp_copy.cp_clp->async_copies); + spin_unlock(&async_copy->cp_copy.cp_clp->async_lock); wake_up_process(async_copy->copy_task); status = nfs_ok; } else { @@ -1567,10 +1568,10 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; } -struct nfsd4_copy * +struct nfsd4_async_copy * find_async_copy(struct nfs4_client *clp, stateid_t *stateid) { - struct nfsd4_copy *copy; + struct nfsd4_async_copy *copy; spin_lock(&clp->async_lock); list_for_each_entry(copy, &clp->async_copies, copies) { @@ -1590,7 +1591,7 @@ nfsd4_offload_cancel(struct svc_rqst *rqstp, union nfsd4_op_u *u) { struct nfsd4_offload_status *os = &u->offload_status; - struct nfsd4_copy *copy; + struct nfsd4_async_copy *copy; struct nfs4_client *clp = cstate->clp; copy = find_async_copy(clp, &os->stateid); @@ -1677,12 +1678,12 @@ nfsd4_offload_status(struct svc_rqst *rqstp, { struct nfsd4_offload_status *os = &u->offload_status; __be32 status = 0; - struct nfsd4_copy *copy; + struct nfsd4_async_copy *copy; struct nfs4_client *clp = cstate->clp; copy = find_async_copy(clp, &os->stateid); if (copy) { - os->count = copy->cp_res.wr_bytes_written; + os->count = copy->cp_copy.cp_res.wr_bytes_written; nfs4_put_copy(copy); } else status = nfserr_bad_stateid; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7bfe0a6bc5fd..d1541848e1d0 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -820,7 +820,7 @@ static int nfs4_init_cp_state(struct nfsd_net *nn, copy_stateid_t *stid, return 1; } -int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy) +int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_async_copy *copy) { return nfs4_init_cp_state(nn, ©->cp_stateid, NFS4_COPY_STID); } @@ -846,12 +846,12 @@ struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn, return NULL; } -void nfs4_free_copy_state(struct nfsd4_copy *copy) +void nfs4_free_copy_state(struct nfsd4_async_copy *copy) { struct nfsd_net *nn; WARN_ON_ONCE(copy->cp_stateid.sc_type != NFS4_COPY_STID); - nn = net_generic(copy->cp_clp->net, nfsd_net_id); + nn = net_generic(copy->cp_copy.cp_clp->net, nfsd_net_id); spin_lock(&nn->s2s_cp_lock); idr_remove(&nn->s2s_cp_stateids, copy->cp_stateid.stid.si_opaque.so_id); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index a16e3d6fcbc0..6c080c63e880 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -636,6 +636,7 @@ struct nfsd4_blocked_lock { struct nfsd4_compound_state; struct nfsd_net; struct nfsd4_copy; +struct nfsd4_async_copy; extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct svc_fh *fhp, @@ -646,8 +647,8 @@ __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, struct nfs4_stid **s, struct nfsd_net *nn); struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, void (*sc_free)(struct nfs4_stid *)); -int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy); -void nfs4_free_copy_state(struct nfsd4_copy *copy); +int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_async_copy *copy); +void nfs4_free_copy_state(struct nfsd4_async_copy *copy); struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn, struct nfs4_stid *p_stid); void nfs4_unhash_stid(struct nfs4_stid *s); @@ -676,8 +677,8 @@ extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn struct nfs4_file *find_file(struct knfsd_fh *fh); void put_nfs4_file(struct nfs4_file *fi); -extern void nfs4_put_copy(struct nfsd4_copy *copy); -extern struct nfsd4_copy * +extern void nfs4_put_copy(struct nfsd4_async_copy *copy); +extern struct nfsd4_async_copy * find_async_copy(struct nfs4_client *clp, stateid_t *staetid); extern void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps); diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 1ced060704a3..e18979147010 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -569,11 +569,6 @@ struct nfsd4_copy { struct nfsd_file *nf_src; struct nfsd_file *nf_dst; - copy_stateid_t cp_stateid; - - struct list_head copies; - struct task_struct *copy_task; - refcount_t refcount; bool stopped; struct vfsmount *ss_mnt; @@ -581,6 +576,24 @@ struct nfsd4_copy { nfs4_stateid stateid; struct nfsd_net *cp_nn; }; + +/* + * Durable state for an async (background) server-side COPY. + * + * struct nfsd4_copy is transient: it lives in the COMPOUND argument buffer + * and is reused once the op returns. An async COPY outlives the COMPOUND + * (worker kthread, reaper linkage), so its params and result are snapshotted + * into the embedded cp_copy and it never points into the request buffer. + */ +struct nfsd4_async_copy { + struct nfsd4_copy cp_copy; /* operation params + result */ + + struct list_head copies; /* nfs4_client.async_copies */ + struct task_struct *copy_task; + refcount_t refcount; + copy_stateid_t cp_stateid; /* s2s_cp_stateids IDR entry */ +}; + extern bool inter_copy_offload_enable; struct nfsd4_seek { -- 2.34.1
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,转换为PR失败! 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/B26... 失败原因:应用补丁/补丁集失败,Patch failed at 0001 nfsd: split nfsd4_copy into transient and durable async copy objects 建议解决方法:请查看失败原因, 确认补丁是否可以应用在当前期望分支的最新代码上 FeedBack: The patch(es) which you have sent to kernel@openeuler.org has been converted to PR failed! Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/B26... Failed Reason: apply patch(es) failed, Patch failed at 0001 nfsd: split nfsd4_copy into transient and durable async copy objects Suggest Solution: please checkout if the failed patch(es) can work on the newest codes in expected branch
participants (2)
-
Lu Jialin -
patchwork bot