diff options
author | Olga Kornievskaia <kolga@netapp.com> | 2018-07-09 22:13:32 +0300 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2018-08-09 19:56:39 +0300 |
commit | bc0c9079b48ddcf1f8a6e1aaa277288b263c78d8 (patch) | |
tree | df6f4429ec4d1aeffcdced295f86410c9368a3c0 /fs/nfs/nfs42proc.c | |
parent | 62164f317972fcd36590578888f33a1994dda519 (diff) | |
download | linux-bc0c9079b48ddcf1f8a6e1aaa277288b263c78d8.tar.xz |
NFS handle COPY reply CB_OFFLOAD call race
It's possible that server replies back with CB_OFFLOAD call and
COPY reply at the same time such that client will process
CB_OFFLOAD before reply to COPY. For that keep a list of pending
callback stateids received and then before waiting on completion
check the pending list.
Cleanup any pending copies on the client shutdown.
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 | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index 023aea8f6cf1..c7d31f72070e 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c @@ -138,14 +138,31 @@ static int handle_async_copy(struct nfs42_copy_res *res, { struct nfs4_copy_state *copy; int status = NFS4_OK; + bool found_pending = false; + + spin_lock(&server->nfs_client->cl_lock); + list_for_each_entry(copy, &server->nfs_client->pending_cb_stateids, + copies) { + if (memcmp(&res->write_res.stateid, ©->stateid, + NFS4_STATEID_SIZE)) + continue; + found_pending = true; + list_del(©->copies); + break; + } + if (found_pending) { + spin_unlock(&server->nfs_client->cl_lock); + goto out; + } copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS); - if (!copy) + if (!copy) { + spin_unlock(&server->nfs_client->cl_lock); 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); @@ -153,6 +170,7 @@ static int handle_async_copy(struct nfs42_copy_res *res, spin_lock(&server->nfs_client->cl_lock); list_del_init(©->copies); spin_unlock(&server->nfs_client->cl_lock); +out: res->write_res.count = copy->count; memcpy(&res->write_res.verifier, ©->verf, sizeof(copy->verf)); status = -copy->error; |