@@ -1100,11 +1100,19 @@ static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write)
out:
return status;
}
+
+void nfs4_put_copy(struct nfsd4_copy *copy)
+{
+ if (!refcount_dec_and_test(©->refcount))
+ return;
+ kfree(copy);
+}
+
static void nfsd4_cb_offload_release(struct nfsd4_callback *cb)
{
struct nfsd4_copy *copy = container_of(cb, struct nfsd4_copy, cp_cb);
- kfree(copy);
+ nfs4_put_copy(copy);
}
static int nfsd4_cb_offload_done(struct nfsd4_callback *cb,
@@ -1135,6 +1143,8 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
u64 dst_pos = copy->cp_dst_pos;
do {
+ if (signalled() || kthread_should_stop())
+ break;
bytes_copied = nfsd_copy_file_range(copy->file_src, src_pos,
copy->file_dst, dst_pos, bytes_total);
if (bytes_copied <= 0)
@@ -1188,7 +1198,7 @@ static void cleanup_async_copy(struct nfsd4_copy *copy)
spin_lock(©->cp_clp->async_lock);
list_del(©->copies);
spin_unlock(©->cp_clp->async_lock);
- kfree(copy);
+ nfs4_put_copy(copy);
}
static int nfsd4_do_async_copy(void *data)
@@ -1238,6 +1248,7 @@ static int nfsd4_do_async_copy(void *data)
goto out;
if (!nfs4_init_cp_state(nn, copy))
goto out;
+ refcount_set(&async_copy->refcount, 1);
memcpy(©->cp_res.cb_stateid, ©->cp_stateid,
sizeof(copy->cp_stateid));
dup_copy_fields(copy, async_copy);
@@ -1267,7 +1278,30 @@ static int nfsd4_do_async_copy(void *data)
struct nfsd4_compound_state *cstate,
union nfsd4_op_u *u)
{
- return 0;
+ struct nfsd4_offload_status *os = &u->offload_status;
+ __be32 status = 0;
+ struct nfsd4_copy *copy;
+ bool found = false;
+ struct nfs4_client *clp = cstate->clp;
+
+ spin_lock(&clp->async_lock);
+ list_for_each_entry(copy, &clp->async_copies, copies) {
+ if (memcmp(©->cp_stateid, &os->stateid,
+ NFS4_STATEID_SIZE))
+ continue;
+ found = true;
+ refcount_inc(©->refcount);
+ break;
+ }
+ spin_unlock(&clp->async_lock);
+ if (found) {
+ set_tsk_thread_flag(copy->copy_task, TIF_SIGPENDING);
+ kthread_stop(copy->copy_task);
+ nfs4_put_copy(copy);
+ } else
+ status = nfserr_bad_stateid;
+
+ return status;
}
static __be32
@@ -641,6 +641,7 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name,
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);
static inline void get_nfs4_file(struct nfs4_file *fi)
{
refcount_inc(&fi->fi_ref);
@@ -542,6 +542,7 @@ struct nfsd4_copy {
struct list_head copies;
struct task_struct *copy_task;
+ refcount_t refcount;
};
extern bool async_copy_offload_enable;