diff options
author | Olga Kornievskaia <kolga@netapp.com> | 2018-07-09 22:13:31 +0300 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2018-08-09 19:56:39 +0300 |
commit | 62164f317972fcd36590578888f33a1994dda519 (patch) | |
tree | 24608dd5c9a8cd89f5bb16325e21b44d7064acb3 /fs/nfs/nfs42proc.c | |
parent | 67aa7444c4beb40aafedd8d2c60bbcc54987adda (diff) | |
download | linux-62164f317972fcd36590578888f33a1994dda519.tar.xz |
NFS add support for asynchronous COPY
Change xdr to always send COPY asynchronously.
Keep the list copies send in a list under a server structure.
Once copy is sent, it waits on a completion structure that will
be signalled by the callback thread that receives CB_OFFLOAD.
If CB_OFFLOAD returned an error and even if it returned partial
bytes, ignore them (as we can't commit without a verifier to
match) and return an error.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Diffstat (limited to 'fs/nfs/nfs42proc.c')
-rw-r--r-- | fs/nfs/nfs42proc.c | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index 5f59b6f65a42..023aea8f6cf1 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c @@ -130,6 +130,37 @@ out_unlock: return err; } +static int handle_async_copy(struct nfs42_copy_res *res, + struct nfs_server *server, + struct file *src, + struct file *dst, + nfs4_stateid *src_stateid) +{ + struct nfs4_copy_state *copy; + int status = NFS4_OK; + + copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS); + if (!copy) + return -ENOMEM; + memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE); + init_completion(©->completion); + + spin_lock(&server->nfs_client->cl_lock); + list_add_tail(©->copies, &server->ss_copies); + spin_unlock(&server->nfs_client->cl_lock); + + wait_for_completion_interruptible(©->completion); + spin_lock(&server->nfs_client->cl_lock); + list_del_init(©->copies); + spin_unlock(&server->nfs_client->cl_lock); + res->write_res.count = copy->count; + memcpy(&res->write_res.verifier, ©->verf, sizeof(copy->verf)); + status = -copy->error; + + kfree(copy); + return status; +} + static ssize_t _nfs42_proc_copy(struct file *src, struct nfs_lock_context *src_lock, struct file *dst, @@ -168,9 +199,13 @@ static ssize_t _nfs42_proc_copy(struct file *src, if (status) return status; - res->commit_res.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS); - if (!res->commit_res.verf) - return -ENOMEM; + res->commit_res.verf = NULL; + if (args->sync) { + res->commit_res.verf = + kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS); + if (!res->commit_res.verf) + return -ENOMEM; + } status = nfs4_call_sync(server->client, server, &msg, &args->seq_args, &res->seq_res, 0); if (status == -ENOTSUPP) @@ -178,18 +213,27 @@ static ssize_t _nfs42_proc_copy(struct file *src, if (status) goto out; - if (nfs_write_verifier_cmp(&res->write_res.verifier.verifier, + if (args->sync && + nfs_write_verifier_cmp(&res->write_res.verifier.verifier, &res->commit_res.verf->verifier)) { status = -EAGAIN; goto out; } + if (!res->synchronous) { + status = handle_async_copy(res, server, src, dst, + &args->src_stateid); + if (status) + return status; + } + truncate_pagecache_range(dst_inode, pos_dst, pos_dst + res->write_res.count); status = res->write_res.count; out: - kfree(res->commit_res.verf); + if (args->sync) + kfree(res->commit_res.verf); return status; } @@ -206,6 +250,7 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, .dst_fh = NFS_FH(file_inode(dst)), .dst_pos = pos_dst, .count = count, + .sync = false, }; struct nfs42_copy_res res; struct nfs4_exception src_exception = { |