Commit 99f2c555 authored by Olga Kornievskaia's avatar Olga Kornievskaia Committed by Trond Myklebust

NFSv4.2 copy do not allocate memory under the lock

Bruce pointed out that we shouldn't allocate memory while holding
a lock in the nfs4_callback_offload() and handle_async_copy()
that deal with a racing CB_OFFLOAD and reply to COPY case.
Signed-off-by: default avatarOlga Kornievskaia <kolga@netapp.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent aeabb3c9
......@@ -686,20 +686,24 @@ __be32 nfs4_callback_offload(void *data, void *dummy,
{
struct cb_offloadargs *args = data;
struct nfs_server *server;
struct nfs4_copy_state *copy;
struct nfs4_copy_state *copy, *tmp_copy;
bool found = false;
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
if (!copy)
return htonl(NFS4ERR_SERVERFAULT);
spin_lock(&cps->clp->cl_lock);
rcu_read_lock();
list_for_each_entry_rcu(server, &cps->clp->cl_superblocks,
client_link) {
list_for_each_entry(copy, &server->ss_copies, copies) {
list_for_each_entry(tmp_copy, &server->ss_copies, copies) {
if (memcmp(args->coa_stateid.other,
copy->stateid.other,
tmp_copy->stateid.other,
sizeof(args->coa_stateid.other)))
continue;
nfs4_copy_cb_args(copy, args);
complete(&copy->completion);
nfs4_copy_cb_args(tmp_copy, args);
complete(&tmp_copy->completion);
found = true;
goto out;
}
......@@ -707,15 +711,11 @@ __be32 nfs4_callback_offload(void *data, void *dummy,
out:
rcu_read_unlock();
if (!found) {
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
if (!copy) {
spin_unlock(&cps->clp->cl_lock);
return htonl(NFS4ERR_SERVERFAULT);
}
memcpy(&copy->stateid, &args->coa_stateid, NFS4_STATEID_SIZE);
nfs4_copy_cb_args(copy, args);
list_add_tail(&copy->copies, &cps->clp->pending_cb_stateids);
}
} else
kfree(copy);
spin_unlock(&cps->clp->cl_lock);
return 0;
......
......@@ -137,31 +137,32 @@ static int handle_async_copy(struct nfs42_copy_res *res,
struct file *dst,
nfs4_stateid *src_stateid)
{
struct nfs4_copy_state *copy;
struct nfs4_copy_state *copy, *tmp_copy;
int status = NFS4_OK;
bool found_pending = false;
struct nfs_open_context *ctx = nfs_file_open_context(dst);
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
if (!copy)
return -ENOMEM;
spin_lock(&server->nfs_client->cl_lock);
list_for_each_entry(copy, &server->nfs_client->pending_cb_stateids,
list_for_each_entry(tmp_copy, &server->nfs_client->pending_cb_stateids,
copies) {
if (memcmp(&res->write_res.stateid, &copy->stateid,
if (memcmp(&res->write_res.stateid, &tmp_copy->stateid,
NFS4_STATEID_SIZE))
continue;
found_pending = true;
list_del(&copy->copies);
list_del(&tmp_copy->copies);
break;
}
if (found_pending) {
spin_unlock(&server->nfs_client->cl_lock);
kfree(copy);
copy = tmp_copy;
goto out;
}
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
if (!copy) {
spin_unlock(&server->nfs_client->cl_lock);
return -ENOMEM;
}
memcpy(&copy->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
init_completion(&copy->completion);
copy->parent_state = ctx->state;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment