NFS client bugfixes for Linux 4.20
Highlights include: Bugfixes: - Fix a NFSv4 state manager deadlock when returning a delegation - NFSv4.2 copy do not allocate memory under the lock - flexfiles: Use the correct stateid for IO in the tightly coupled case -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJb+hCNAAoJEA4mA3inWBJc8ZQP/jR+uemJycwgyWINvnn6PEtE hyiSwL+c3jhBHwX2IroF1KvaHIa8GXMbIWj+DfW1iB2htYnIJYz4IFJOGpfN1S7n bKCgonV0V06+dFF4DqcL3HcM1L6bo26n16voi3otgY0R5U5HGwB1tocZPCbR6DpK meiRbrmB6O962zluUlTuu9zFSvsALyZR0h4tYMGYA0MlgWQJVLH6+dufyG2Zgp2Z OH9tUzRFknD/Q4KrJv7zrMY198mHa+RQovsO2Jc/iE4bbrSMyVNtrPuVJphsP1BD lZ5SvvWLXjNepUMsDCK+Es7i6dUmtHsGPS6gNDwUwY9/UlwOPYlp44VJzmEYmQcz /VrrHn3LSoKDSAVNrksghto9O4T1NPnuVja1Q+SHf5hVX5OlsxyDkvX23ZUdgdkW BeXeNWZuAJdDTI1KU+ahm2ilfUnuFpRGRHUrH2sYczV2okC38cO5YCIRI3Tckz6e jrhmJcw+zCWv3Yl3h2Rbf8fVRcWJHA+qLWT3Str5nCyZiqPCag7Z7br9r5316zDv Yma7nITZO7HH1cZUv+byA0PVHU96kDsMhhpxYISrSr4lf2BcZNnjQC/0IHb7qdWz FgpYzv/BsIi+KxyZKshiR5E60kOmVxv2wIhre8uLOuuabcGsh/wit6URVnQJ+GDp 7klRY1t1P24XaIbgBR9U =hqbe -----END PGP SIGNATURE----- Merge tag 'nfs-for-4.20-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client bugfixes from Trond Myklebust: - Fix a NFSv4 state manager deadlock when returning a delegation - NFSv4.2 copy do not allocate memory under the lock - flexfiles: Use the correct stateid for IO in the tightly coupled case * tag 'nfs-for-4.20-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: flexfiles: use per-mirror specified stateid for IO NFSv4.2 copy do not allocate memory under the lock NFSv4: Fix a NFSv4 state manager deadlock
This commit is contained in:
commit
17c2f54086
@ -686,20 +686,24 @@ __be32 nfs4_callback_offload(void *data, void *dummy,
|
|||||||
{
|
{
|
||||||
struct cb_offloadargs *args = data;
|
struct cb_offloadargs *args = data;
|
||||||
struct nfs_server *server;
|
struct nfs_server *server;
|
||||||
struct nfs4_copy_state *copy;
|
struct nfs4_copy_state *copy, *tmp_copy;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
|
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
|
||||||
|
if (!copy)
|
||||||
|
return htonl(NFS4ERR_SERVERFAULT);
|
||||||
|
|
||||||
spin_lock(&cps->clp->cl_lock);
|
spin_lock(&cps->clp->cl_lock);
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
list_for_each_entry_rcu(server, &cps->clp->cl_superblocks,
|
list_for_each_entry_rcu(server, &cps->clp->cl_superblocks,
|
||||||
client_link) {
|
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,
|
if (memcmp(args->coa_stateid.other,
|
||||||
copy->stateid.other,
|
tmp_copy->stateid.other,
|
||||||
sizeof(args->coa_stateid.other)))
|
sizeof(args->coa_stateid.other)))
|
||||||
continue;
|
continue;
|
||||||
nfs4_copy_cb_args(copy, args);
|
nfs4_copy_cb_args(tmp_copy, args);
|
||||||
complete(©->completion);
|
complete(&tmp_copy->completion);
|
||||||
found = true;
|
found = true;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -707,15 +711,11 @@ __be32 nfs4_callback_offload(void *data, void *dummy,
|
|||||||
out:
|
out:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
if (!found) {
|
if (!found) {
|
||||||
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
|
|
||||||
if (!copy) {
|
|
||||||
spin_unlock(&cps->clp->cl_lock);
|
|
||||||
return htonl(NFS4ERR_SERVERFAULT);
|
|
||||||
}
|
|
||||||
memcpy(©->stateid, &args->coa_stateid, NFS4_STATEID_SIZE);
|
memcpy(©->stateid, &args->coa_stateid, NFS4_STATEID_SIZE);
|
||||||
nfs4_copy_cb_args(copy, args);
|
nfs4_copy_cb_args(copy, args);
|
||||||
list_add_tail(©->copies, &cps->clp->pending_cb_stateids);
|
list_add_tail(©->copies, &cps->clp->pending_cb_stateids);
|
||||||
}
|
} else
|
||||||
|
kfree(copy);
|
||||||
spin_unlock(&cps->clp->cl_lock);
|
spin_unlock(&cps->clp->cl_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1361,12 +1361,7 @@ static void ff_layout_read_prepare_v4(struct rpc_task *task, void *data)
|
|||||||
task))
|
task))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ff_layout_read_prepare_common(task, hdr))
|
ff_layout_read_prepare_common(task, hdr);
|
||||||
return;
|
|
||||||
|
|
||||||
if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context,
|
|
||||||
hdr->args.lock_context, FMODE_READ) == -EIO)
|
|
||||||
rpc_exit(task, -EIO); /* lost lock, terminate I/O */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ff_layout_read_call_done(struct rpc_task *task, void *data)
|
static void ff_layout_read_call_done(struct rpc_task *task, void *data)
|
||||||
@ -1542,12 +1537,7 @@ static void ff_layout_write_prepare_v4(struct rpc_task *task, void *data)
|
|||||||
task))
|
task))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ff_layout_write_prepare_common(task, hdr))
|
ff_layout_write_prepare_common(task, hdr);
|
||||||
return;
|
|
||||||
|
|
||||||
if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context,
|
|
||||||
hdr->args.lock_context, FMODE_WRITE) == -EIO)
|
|
||||||
rpc_exit(task, -EIO); /* lost lock, terminate I/O */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ff_layout_write_call_done(struct rpc_task *task, void *data)
|
static void ff_layout_write_call_done(struct rpc_task *task, void *data)
|
||||||
@ -1742,6 +1732,10 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr)
|
|||||||
fh = nfs4_ff_layout_select_ds_fh(lseg, idx);
|
fh = nfs4_ff_layout_select_ds_fh(lseg, idx);
|
||||||
if (fh)
|
if (fh)
|
||||||
hdr->args.fh = fh;
|
hdr->args.fh = fh;
|
||||||
|
|
||||||
|
if (!nfs4_ff_layout_select_ds_stateid(lseg, idx, &hdr->args.stateid))
|
||||||
|
goto out_failed;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that if we ever decide to split across DSes,
|
* Note that if we ever decide to split across DSes,
|
||||||
* then we may need to handle dense-like offsets.
|
* then we may need to handle dense-like offsets.
|
||||||
@ -1804,6 +1798,9 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
|
|||||||
if (fh)
|
if (fh)
|
||||||
hdr->args.fh = fh;
|
hdr->args.fh = fh;
|
||||||
|
|
||||||
|
if (!nfs4_ff_layout_select_ds_stateid(lseg, idx, &hdr->args.stateid))
|
||||||
|
goto out_failed;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that if we ever decide to split across DSes,
|
* Note that if we ever decide to split across DSes,
|
||||||
* then we may need to handle dense-like offsets.
|
* then we may need to handle dense-like offsets.
|
||||||
|
@ -215,6 +215,10 @@ unsigned int ff_layout_fetch_ds_ioerr(struct pnfs_layout_hdr *lo,
|
|||||||
unsigned int maxnum);
|
unsigned int maxnum);
|
||||||
struct nfs_fh *
|
struct nfs_fh *
|
||||||
nfs4_ff_layout_select_ds_fh(struct pnfs_layout_segment *lseg, u32 mirror_idx);
|
nfs4_ff_layout_select_ds_fh(struct pnfs_layout_segment *lseg, u32 mirror_idx);
|
||||||
|
int
|
||||||
|
nfs4_ff_layout_select_ds_stateid(struct pnfs_layout_segment *lseg,
|
||||||
|
u32 mirror_idx,
|
||||||
|
nfs4_stateid *stateid);
|
||||||
|
|
||||||
struct nfs4_pnfs_ds *
|
struct nfs4_pnfs_ds *
|
||||||
nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
|
nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
|
||||||
|
@ -370,6 +370,25 @@ out:
|
|||||||
return fh;
|
return fh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nfs4_ff_layout_select_ds_stateid(struct pnfs_layout_segment *lseg,
|
||||||
|
u32 mirror_idx,
|
||||||
|
nfs4_stateid *stateid)
|
||||||
|
{
|
||||||
|
struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, mirror_idx);
|
||||||
|
|
||||||
|
if (!ff_layout_mirror_valid(lseg, mirror, false)) {
|
||||||
|
pr_err_ratelimited("NFS: %s: No data server for mirror offset index %d\n",
|
||||||
|
__func__, mirror_idx);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfs4_stateid_copy(stateid, &mirror->stateid);
|
||||||
|
return 1;
|
||||||
|
out:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nfs4_ff_layout_prepare_ds - prepare a DS connection for an RPC call
|
* nfs4_ff_layout_prepare_ds - prepare a DS connection for an RPC call
|
||||||
* @lseg: the layout segment we're operating on
|
* @lseg: the layout segment we're operating on
|
||||||
|
@ -137,31 +137,32 @@ static int handle_async_copy(struct nfs42_copy_res *res,
|
|||||||
struct file *dst,
|
struct file *dst,
|
||||||
nfs4_stateid *src_stateid)
|
nfs4_stateid *src_stateid)
|
||||||
{
|
{
|
||||||
struct nfs4_copy_state *copy;
|
struct nfs4_copy_state *copy, *tmp_copy;
|
||||||
int status = NFS4_OK;
|
int status = NFS4_OK;
|
||||||
bool found_pending = false;
|
bool found_pending = false;
|
||||||
struct nfs_open_context *ctx = nfs_file_open_context(dst);
|
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);
|
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) {
|
copies) {
|
||||||
if (memcmp(&res->write_res.stateid, ©->stateid,
|
if (memcmp(&res->write_res.stateid, &tmp_copy->stateid,
|
||||||
NFS4_STATEID_SIZE))
|
NFS4_STATEID_SIZE))
|
||||||
continue;
|
continue;
|
||||||
found_pending = true;
|
found_pending = true;
|
||||||
list_del(©->copies);
|
list_del(&tmp_copy->copies);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (found_pending) {
|
if (found_pending) {
|
||||||
spin_unlock(&server->nfs_client->cl_lock);
|
spin_unlock(&server->nfs_client->cl_lock);
|
||||||
|
kfree(copy);
|
||||||
|
copy = tmp_copy;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
|
|
||||||
if (!copy) {
|
|
||||||
spin_unlock(&server->nfs_client->cl_lock);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
|
memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
|
||||||
init_completion(©->completion);
|
init_completion(©->completion);
|
||||||
copy->parent_state = ctx->state;
|
copy->parent_state = ctx->state;
|
||||||
|
@ -41,6 +41,8 @@ enum nfs4_client_state {
|
|||||||
NFS4CLNT_MOVED,
|
NFS4CLNT_MOVED,
|
||||||
NFS4CLNT_LEASE_MOVED,
|
NFS4CLNT_LEASE_MOVED,
|
||||||
NFS4CLNT_DELEGATION_EXPIRED,
|
NFS4CLNT_DELEGATION_EXPIRED,
|
||||||
|
NFS4CLNT_RUN_MANAGER,
|
||||||
|
NFS4CLNT_DELEGRETURN_RUNNING,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NFS4_RENEW_TIMEOUT 0x01
|
#define NFS4_RENEW_TIMEOUT 0x01
|
||||||
|
@ -1210,6 +1210,7 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
|
|||||||
struct task_struct *task;
|
struct task_struct *task;
|
||||||
char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
|
char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
|
||||||
|
|
||||||
|
set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
|
||||||
if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
|
if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
|
||||||
return;
|
return;
|
||||||
__module_get(THIS_MODULE);
|
__module_get(THIS_MODULE);
|
||||||
@ -2503,6 +2504,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
|
|||||||
|
|
||||||
/* Ensure exclusive access to NFSv4 state */
|
/* Ensure exclusive access to NFSv4 state */
|
||||||
do {
|
do {
|
||||||
|
clear_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
|
||||||
if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
|
if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
|
||||||
section = "purge state";
|
section = "purge state";
|
||||||
status = nfs4_purge_lease(clp);
|
status = nfs4_purge_lease(clp);
|
||||||
@ -2593,14 +2595,18 @@ static void nfs4_state_manager(struct nfs_client *clp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nfs4_end_drain_session(clp);
|
nfs4_end_drain_session(clp);
|
||||||
if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
|
nfs4_clear_state_manager_bit(clp);
|
||||||
nfs_client_return_marked_delegations(clp);
|
|
||||||
continue;
|
if (!test_and_set_bit(NFS4CLNT_DELEGRETURN_RUNNING, &clp->cl_state)) {
|
||||||
|
if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
|
||||||
|
nfs_client_return_marked_delegations(clp);
|
||||||
|
set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
|
||||||
|
}
|
||||||
|
clear_bit(NFS4CLNT_DELEGRETURN_RUNNING, &clp->cl_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
nfs4_clear_state_manager_bit(clp);
|
|
||||||
/* Did we race with an attempt to give us more work? */
|
/* Did we race with an attempt to give us more work? */
|
||||||
if (clp->cl_state == 0)
|
if (!test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state))
|
||||||
return;
|
return;
|
||||||
if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
|
if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user