mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
nfsd: split nfsd4_copy into transient and durable async copy objects
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>
This commit is contained in:
parent
45b06a7508
commit
f307b4f7ed
|
|
@ -57,7 +57,7 @@ module_param(inter_copy_offload_enable, bool, 0644);
|
|||
MODULE_PARM_DESC(inter_copy_offload_enable,
|
||||
"Enable inter server to server copy offload. Default: false");
|
||||
|
||||
static void cleanup_async_copy(struct nfsd4_copy *copy);
|
||||
static void cleanup_async_copy(struct nfsd4_async_copy *copy);
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
|
||||
static int nfsd4_ssc_umount_timeout = 900000; /* default to 15 mins */
|
||||
|
|
@ -1465,13 +1465,13 @@ nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
*/
|
||||
bool nfsd4_has_active_async_copies(struct nfs4_client *clp)
|
||||
{
|
||||
struct nfsd4_copy *copy;
|
||||
struct nfsd4_async_copy *copy;
|
||||
bool result = false;
|
||||
|
||||
spin_lock(&clp->async_lock);
|
||||
list_for_each_entry(copy, &clp->async_copies, copies) {
|
||||
if (!test_bit(NFSD4_COPY_F_COMPLETED, ©->cp_flags) &&
|
||||
!test_bit(NFSD4_COPY_F_STOPPED, ©->cp_flags)) {
|
||||
if (!test_bit(NFSD4_COPY_F_COMPLETED, ©->cp_copy.cp_flags) &&
|
||||
!test_bit(NFSD4_COPY_F_STOPPED, ©->cp_copy.cp_flags)) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1487,7 +1487,7 @@ bool nfsd4_has_active_async_copies(struct nfs4_client *clp)
|
|||
void nfsd4_async_copy_reaper(struct nfsd_net *nn)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd4_copy *copy;
|
||||
struct nfsd4_async_copy *copy;
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
|
|
@ -1496,8 +1496,9 @@ void nfsd4_async_copy_reaper(struct nfsd_net *nn)
|
|||
|
||||
spin_lock(&clp->async_lock);
|
||||
list_for_each_safe(pos, next, &clp->async_copies) {
|
||||
copy = list_entry(pos, struct nfsd4_copy, copies);
|
||||
if (test_bit(NFSD4_COPY_F_OFFLOAD_DONE, ©->cp_flags)) {
|
||||
copy = list_entry(pos, struct nfsd4_async_copy, copies);
|
||||
if (test_bit(NFSD4_COPY_F_OFFLOAD_DONE,
|
||||
©->cp_copy.cp_flags)) {
|
||||
if (!--copy->cp_ttl) {
|
||||
list_del_init(©->copies);
|
||||
list_add(©->copies, &reaplist);
|
||||
|
|
@ -1509,52 +1510,53 @@ void nfsd4_async_copy_reaper(struct nfsd_net *nn)
|
|||
spin_unlock(&nn->client_lock);
|
||||
|
||||
while (!list_empty(&reaplist)) {
|
||||
copy = list_first_entry(&reaplist, struct nfsd4_copy, copies);
|
||||
copy = list_first_entry(&reaplist, struct nfsd4_async_copy,
|
||||
copies);
|
||||
list_del_init(©->copies);
|
||||
cleanup_async_copy(copy);
|
||||
}
|
||||
}
|
||||
|
||||
static void nfs4_put_copy(struct nfsd4_copy *copy)
|
||||
static void nfs4_put_copy(struct nfsd4_async_copy *copy)
|
||||
{
|
||||
if (!refcount_dec_and_test(©->refcount))
|
||||
return;
|
||||
/* Drop the task_struct pinned in nfsd4_copy(); NULL on sync copies. */
|
||||
/* Drop the task_struct pinned in nfsd4_copy(). */
|
||||
if (copy->copy_task)
|
||||
put_task_struct(copy->copy_task);
|
||||
kfree(copy->cp_src);
|
||||
kfree(copy->cp_copy.cp_src);
|
||||
kfree(copy);
|
||||
}
|
||||
|
||||
static void release_copy_files(struct nfsd4_copy *copy);
|
||||
|
||||
static void nfsd4_stop_copy(struct nfsd4_copy *copy)
|
||||
static void nfsd4_stop_copy(struct nfsd4_async_copy *copy)
|
||||
{
|
||||
trace_nfsd_copy_async_cancel(copy);
|
||||
trace_nfsd_copy_async_cancel(©->cp_copy);
|
||||
/*
|
||||
* Join the kthread before releasing its resources. The task_struct is
|
||||
* pinned in nfsd4_copy(), so kthread_stop() is safe even after the
|
||||
* one-shot kthread has exited. The caller already unlinked the copy,
|
||||
* so this runs once per copy.
|
||||
*/
|
||||
set_bit(NFSD4_COPY_F_STOPPED, ©->cp_flags);
|
||||
set_bit(NFSD4_COPY_F_STOPPED, ©->cp_copy.cp_flags);
|
||||
kthread_stop(copy->copy_task);
|
||||
if (!test_bit(NFSD4_COPY_F_CB_ERROR, ©->cp_flags))
|
||||
copy->nfserr = nfs_ok;
|
||||
set_bit(NFSD4_COPY_F_COMPLETED, ©->cp_flags);
|
||||
if (!test_bit(NFSD4_COPY_F_CB_ERROR, ©->cp_copy.cp_flags))
|
||||
copy->cp_copy.nfserr = nfs_ok;
|
||||
set_bit(NFSD4_COPY_F_COMPLETED, ©->cp_copy.cp_flags);
|
||||
|
||||
release_copy_files(copy);
|
||||
release_copy_files(©->cp_copy);
|
||||
nfs4_put_copy(copy);
|
||||
}
|
||||
|
||||
static struct nfsd4_copy *nfsd4_unhash_copy(struct nfs4_client *clp)
|
||||
static struct nfsd4_async_copy *nfsd4_unhash_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);
|
||||
/*
|
||||
* Unlinking hides the copy from the reaper, so drop its
|
||||
|
|
@ -1562,7 +1564,7 @@ static struct nfsd4_copy *nfsd4_unhash_copy(struct nfs4_client *clp)
|
|||
*/
|
||||
nfs4_free_copy_state(copy);
|
||||
/* Pairs with smp_load_acquire() in nfsd4_send_cb_offload(). */
|
||||
smp_store_release(©->cp_clp, NULL);
|
||||
smp_store_release(©->cp_copy.cp_clp, NULL);
|
||||
if (!list_empty(©->copies))
|
||||
list_del_init(©->copies);
|
||||
}
|
||||
|
|
@ -1572,7 +1574,7 @@ static struct nfsd4_copy *nfsd4_unhash_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_unhash_copy(clp)) != NULL) {
|
||||
nfsd4_stop_copy(copy);
|
||||
|
|
@ -1605,7 +1607,7 @@ static bool nfsd4_copy_on_sb(const struct nfsd4_copy *copy,
|
|||
void nfsd4_cancel_copy_by_sb(struct net *net, struct super_block *sb)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
struct nfsd4_copy *copy, *tmp;
|
||||
struct nfsd4_async_copy *copy, *tmp;
|
||||
struct nfs4_client *clp;
|
||||
unsigned int idhashval;
|
||||
LIST_HEAD(to_cancel);
|
||||
|
|
@ -1619,7 +1621,7 @@ void nfsd4_cancel_copy_by_sb(struct net *net, struct super_block *sb)
|
|||
spin_lock(&clp->async_lock);
|
||||
list_for_each_entry_safe(copy, tmp,
|
||||
&clp->async_copies, copies) {
|
||||
if (nfsd4_copy_on_sb(copy, sb)) {
|
||||
if (nfsd4_copy_on_sb(©->cp_copy, sb)) {
|
||||
refcount_inc(©->refcount);
|
||||
/*
|
||||
* Hold a reference on the client while
|
||||
|
|
@ -1631,9 +1633,9 @@ void nfsd4_cancel_copy_by_sb(struct net *net, struct super_block *sb)
|
|||
* survive callback flight.
|
||||
*/
|
||||
kref_get(&clp->cl_nfsdfs.cl_ref);
|
||||
copy->nfserr = nfserr_admin_revoked;
|
||||
copy->cp_copy.nfserr = nfserr_admin_revoked;
|
||||
set_bit(NFSD4_COPY_F_CB_ERROR,
|
||||
©->cp_flags);
|
||||
©->cp_copy.cp_flags);
|
||||
list_move(©->copies, &to_cancel);
|
||||
}
|
||||
}
|
||||
|
|
@ -1643,7 +1645,7 @@ void nfsd4_cancel_copy_by_sb(struct net *net, struct super_block *sb)
|
|||
spin_unlock(&nn->client_lock);
|
||||
|
||||
list_for_each_entry_safe(copy, tmp, &to_cancel, copies) {
|
||||
struct nfs4_client *clp = copy->cp_clp;
|
||||
struct nfs4_client *clp = copy->cp_copy.cp_clp;
|
||||
|
||||
list_del_init(©->copies);
|
||||
/* Reaper can't reach it; drop the s2s entry while cp_clp is valid. */
|
||||
|
|
@ -1940,10 +1942,10 @@ static void nfsd4_cb_offload_release(struct nfsd4_callback *cb)
|
|||
{
|
||||
struct nfsd4_cb_offload *cbo =
|
||||
container_of(cb, struct nfsd4_cb_offload, co_cb);
|
||||
struct nfsd4_copy *copy =
|
||||
container_of(cbo, struct nfsd4_copy, cp_cb_offload);
|
||||
struct nfsd4_async_copy *copy =
|
||||
container_of(cbo, struct nfsd4_async_copy, cp_cb_offload);
|
||||
|
||||
set_bit(NFSD4_COPY_F_OFFLOAD_DONE, ©->cp_flags);
|
||||
set_bit(NFSD4_COPY_F_OFFLOAD_DONE, ©->cp_copy.cp_flags);
|
||||
nfsd4_put_client(cb->cb_clp);
|
||||
/* Drop the copy reference taken in nfsd4_send_cb_offload(). */
|
||||
nfs4_put_copy(copy);
|
||||
|
|
@ -2059,7 +2061,6 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
|
|||
if (!nfsd4_ssc_is_inter(src))
|
||||
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));
|
||||
|
|
@ -2082,14 +2083,14 @@ static void release_copy_files(struct nfsd4_copy *copy)
|
|||
* Called from the reaper and from nfsd4_copy()'s error path; in both
|
||||
* cases the copy is already unreachable from clp->async_copies.
|
||||
*/
|
||||
static void cleanup_async_copy(struct nfsd4_copy *copy)
|
||||
static void cleanup_async_copy(struct nfsd4_async_copy *copy)
|
||||
{
|
||||
nfs4_free_copy_state(copy);
|
||||
release_copy_files(copy);
|
||||
release_copy_files(©->cp_copy);
|
||||
nfs4_put_copy(copy);
|
||||
}
|
||||
|
||||
static void nfsd4_send_cb_offload(struct nfsd4_copy *copy)
|
||||
static void nfsd4_send_cb_offload(struct nfsd4_async_copy *copy)
|
||||
{
|
||||
struct nfsd4_cb_offload *cbo = ©->cp_cb_offload;
|
||||
struct nfs4_client *clp;
|
||||
|
|
@ -2100,15 +2101,15 @@ static void nfsd4_send_cb_offload(struct nfsd4_copy *copy)
|
|||
* cp_clp is NULL once the copy was canceled; skip the callback, the
|
||||
* canceling path owns the notification.
|
||||
*/
|
||||
clp = smp_load_acquire(©->cp_clp);
|
||||
clp = smp_load_acquire(©->cp_copy.cp_clp);
|
||||
if (!clp) {
|
||||
set_bit(NFSD4_COPY_F_OFFLOAD_DONE, ©->cp_flags);
|
||||
set_bit(NFSD4_COPY_F_OFFLOAD_DONE, ©->cp_copy.cp_flags);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&cbo->co_res, ©->cp_res, sizeof(copy->cp_res));
|
||||
memcpy(&cbo->co_fh, ©->fh, sizeof(copy->fh));
|
||||
cbo->co_nfserr = copy->nfserr;
|
||||
memcpy(&cbo->co_res, ©->cp_copy.cp_res, sizeof(copy->cp_copy.cp_res));
|
||||
memcpy(&cbo->co_fh, ©->cp_copy.fh, sizeof(copy->cp_copy.fh));
|
||||
cbo->co_nfserr = copy->cp_copy.nfserr;
|
||||
cbo->co_retries = 5;
|
||||
|
||||
/*
|
||||
|
|
@ -2125,7 +2126,8 @@ static void nfsd4_send_cb_offload(struct nfsd4_copy *copy)
|
|||
cbo->co_referring_slotid,
|
||||
cbo->co_referring_seqno);
|
||||
trace_nfsd_cb_offload(clp, &cbo->co_res.cb_stateid,
|
||||
&cbo->co_fh, copy->cp_count, copy->nfserr);
|
||||
&cbo->co_fh, copy->cp_copy.cp_count,
|
||||
copy->cp_copy.nfserr);
|
||||
nfsd4_try_run_cb(&cbo->co_cb);
|
||||
}
|
||||
|
||||
|
|
@ -2138,7 +2140,8 @@ static void nfsd4_send_cb_offload(struct nfsd4_copy *copy)
|
|||
*/
|
||||
static int nfsd4_do_async_copy(void *data)
|
||||
{
|
||||
struct nfsd4_copy *copy = (struct nfsd4_copy *)data;
|
||||
struct nfsd4_async_copy *async = data;
|
||||
struct nfsd4_copy *copy = &async->cp_copy;
|
||||
__be32 nfserr = nfs_ok;
|
||||
|
||||
trace_nfsd_copy_async(copy);
|
||||
|
|
@ -2180,9 +2183,9 @@ static int nfsd4_do_async_copy(void *data)
|
|||
atomic_dec(©->cp_nn->pending_async_copies);
|
||||
if (copy->cp_res.wr_bytes_written > 0 && copy->attr_update)
|
||||
nfsd_update_cmtime_attr(copy->nf_dst->nf_file, 0);
|
||||
nfsd4_send_cb_offload(copy);
|
||||
nfsd4_send_cb_offload(async);
|
||||
/* Drop the kthread's reference (taken in nfsd4_copy()); copy may be freed after this. */
|
||||
nfs4_put_copy(copy);
|
||||
nfs4_put_copy(async);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2191,7 +2194,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
union nfsd4_op_u *u)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
||||
struct nfsd4_copy *async_copy = NULL;
|
||||
struct nfsd4_async_copy *async_copy = NULL;
|
||||
struct nfsd4_copy *copy = &u->copy;
|
||||
struct nfsd42_write_res *result;
|
||||
__be32 status;
|
||||
|
|
@ -2223,10 +2226,10 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
if (nfsd4_copy_is_async(copy)) {
|
||||
struct task_struct *task;
|
||||
|
||||
async_copy = kzalloc_obj(struct nfsd4_copy);
|
||||
async_copy = kzalloc_obj(struct nfsd4_async_copy);
|
||||
if (!async_copy)
|
||||
goto out_err;
|
||||
async_copy->cp_nn = nn;
|
||||
async_copy->cp_copy.cp_nn = nn;
|
||||
INIT_LIST_HEAD(&async_copy->copies);
|
||||
refcount_set(&async_copy->refcount, 1);
|
||||
async_copy->cp_ttl = NFSD_COPY_INITIAL_TTL;
|
||||
|
|
@ -2234,18 +2237,22 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
if (atomic_inc_return(&nn->pending_async_copies) >
|
||||
(int)rqstp->rq_pool->sp_nrthreads)
|
||||
goto out_dec_async_copy_err;
|
||||
async_copy->cp_src = kmalloc_obj(*async_copy->cp_src);
|
||||
if (!async_copy->cp_src)
|
||||
async_copy->cp_copy.cp_src = kmalloc_obj(*async_copy->cp_copy.cp_src);
|
||||
if (!async_copy->cp_copy.cp_src)
|
||||
goto out_dec_async_copy_err;
|
||||
dup_copy_fields(copy, async_copy);
|
||||
|
||||
if (!nfs4_init_copy_state(nn, async_copy))
|
||||
goto out_dec_async_copy_err;
|
||||
memcpy(&result->cb_stateid, &async_copy->cp_stateid.cs_stid,
|
||||
sizeof(result->cb_stateid));
|
||||
/*
|
||||
* dup after writing cb_stateid; duplicating first would leave
|
||||
* the callback stateid zeroed.
|
||||
*/
|
||||
dup_copy_fields(copy, &async_copy->cp_copy);
|
||||
if ((READ_ONCE(copy->nf_dst->nf_file->f_mode) &
|
||||
FMODE_NOCMTIME) != 0)
|
||||
async_copy->attr_update = true;
|
||||
async_copy->cp_copy.attr_update = true;
|
||||
memcpy(async_copy->cp_cb_offload.co_referring_sessionid.data,
|
||||
cstate->session->se_sessionid.data,
|
||||
NFS4_MAX_SESSIONID_LEN);
|
||||
|
|
@ -2268,10 +2275,10 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
*/
|
||||
refcount_inc(&async_copy->refcount);
|
||||
wake_up_process(async_copy->copy_task);
|
||||
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);
|
||||
status = nfs_ok;
|
||||
} else {
|
||||
status = nfsd4_do_copy(copy, copy->nf_src->nf_file,
|
||||
|
|
@ -2303,10 +2310,10 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
goto out;
|
||||
}
|
||||
|
||||
static struct nfsd4_copy *
|
||||
static struct nfsd4_async_copy *
|
||||
find_async_copy_locked(struct nfs4_client *clp, stateid_t *stateid)
|
||||
{
|
||||
struct nfsd4_copy *copy;
|
||||
struct nfsd4_async_copy *copy;
|
||||
|
||||
lockdep_assert_held(&clp->async_lock);
|
||||
|
||||
|
|
@ -2318,10 +2325,10 @@ find_async_copy_locked(struct nfs4_client *clp, stateid_t *stateid)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static struct nfsd4_copy *
|
||||
static 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);
|
||||
copy = find_async_copy_locked(clp, stateid);
|
||||
|
|
@ -2333,7 +2340,7 @@ find_async_copy(struct nfs4_client *clp, stateid_t *stateid)
|
|||
* async_lock so the reaper can't reach it. Caller drops the
|
||||
* membership ref after nfsd4_stop_copy().
|
||||
*/
|
||||
smp_store_release(©->cp_clp, NULL);
|
||||
smp_store_release(©->cp_copy.cp_clp, NULL);
|
||||
if (!list_empty(©->copies))
|
||||
list_del_init(©->copies);
|
||||
}
|
||||
|
|
@ -2347,7 +2354,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);
|
||||
|
|
@ -2440,17 +2447,17 @@ nfsd4_offload_status(struct svc_rqst *rqstp,
|
|||
{
|
||||
struct nfsd4_offload_status *os = &u->offload_status;
|
||||
__be32 status = nfs_ok;
|
||||
struct nfsd4_copy *copy;
|
||||
struct nfsd4_async_copy *copy;
|
||||
struct nfs4_client *clp = cstate->clp;
|
||||
|
||||
os->completed = false;
|
||||
spin_lock(&clp->async_lock);
|
||||
copy = find_async_copy_locked(clp, &os->stateid);
|
||||
if (copy) {
|
||||
os->count = copy->cp_res.wr_bytes_written;
|
||||
if (test_bit(NFSD4_COPY_F_COMPLETED, ©->cp_flags)) {
|
||||
os->count = copy->cp_copy.cp_res.wr_bytes_written;
|
||||
if (test_bit(NFSD4_COPY_F_COMPLETED, ©->cp_copy.cp_flags)) {
|
||||
os->completed = true;
|
||||
os->status = copy->nfserr;
|
||||
os->status = copy->cp_copy.nfserr;
|
||||
}
|
||||
} else
|
||||
status = nfserr_bad_stateid;
|
||||
|
|
|
|||
|
|
@ -1016,7 +1016,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, NULL);
|
||||
}
|
||||
|
|
@ -1050,13 +1050,13 @@ 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;
|
||||
|
||||
if (copy->cp_stateid.cs_type != NFS4_COPY_STID)
|
||||
return;
|
||||
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.cs_stid.si_opaque.so_id);
|
||||
|
|
|
|||
|
|
@ -872,6 +872,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,
|
||||
|
|
@ -883,8 +884,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_put_stid(struct nfs4_stid *s);
|
||||
|
|
|
|||
|
|
@ -759,28 +759,38 @@ struct nfsd4_copy {
|
|||
struct nfsd42_write_res cp_res;
|
||||
struct knfsd_fh fh;
|
||||
|
||||
/* offload callback */
|
||||
struct nfsd4_cb_offload cp_cb_offload;
|
||||
|
||||
struct nfs4_client *cp_clp;
|
||||
|
||||
struct nfsd_file *nf_src;
|
||||
struct nfsd_file *nf_dst;
|
||||
bool attr_update;
|
||||
|
||||
copy_stateid_t cp_stateid;
|
||||
|
||||
struct list_head copies;
|
||||
struct task_struct *copy_task;
|
||||
refcount_t refcount;
|
||||
unsigned int cp_ttl;
|
||||
|
||||
struct nfsd4_ssc_umount_item *ss_nsui;
|
||||
struct nfs_fh c_fh;
|
||||
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, CB_OFFLOAD), 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;
|
||||
unsigned int cp_ttl;
|
||||
copy_stateid_t cp_stateid; /* s2s_cp_stateids IDR entry */
|
||||
struct nfsd4_cb_offload cp_cb_offload;
|
||||
};
|
||||
|
||||
static inline void nfsd4_copy_set_sync(struct nfsd4_copy *copy, bool sync)
|
||||
{
|
||||
if (sync)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user