NFS client bugfixes for Linux 3.14
Highlights include: - Fix another nfs4_sequence corruptor in RELEASE_LOCKOWNER - Fix an Oopsable delegation callback race - Fix another bad stateid infinite loop - Fail the data server I/O is the stateid represents a lost lock - Fix an Oopsable sunrpc trace event -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJTHJSVAAoJEGcL54qWCgDyVRkP/2t43gjMF6P+Yc7VUW2e5uTv rHhPGFLuDVs9oS3WUYegzvThZMs//ovTaYgUSDNpOYztEB6P8bDRm41q/VgUIixY zWFoEplDgAZZE7gP2EJuXJv3bEdhJqXuCG2KUysqMsaIGlahrlQdHmqGTz6Y931o WROyMWVvnL4IoEtQHVR7DwyqkvSmifPJ8MZZv3Liy82wuw1fCsh8uy8mkYYSbdvN OK4JmHqdJ+CbAZ0WmE4Xe3Itqy/aIMBL9Jyrq4Zl1QX0p7ez3Xpy4XwmtlZXn2KP bKMfK2vP9RggagIpjUL+dhCqxlsyjlF6EzTnQRe7jXqlJ/vJ9pQF8X294jwRysfp 80jDqsTSND4JQiZuBISID23N1nL0TzrP2tWqipR9zx5JJMRVzYZWTzEq4w2uAHgg aW2vTdRNRLZWydlfFNQ8FiuEPIFoQaJFmOCQisec2LtfffLZZBz7JPofjNH9CgU8 mcbPhv75m2imXDOylydiVoD4x/myCGheYw2hpqhb1ZeuQxdN9lnwa0JzjPiP1h38 XIYwzM7TE8WayrdkMDCeIem1dz/VexknfKmXmFXlMfn3GRKxowCSrggxKG92k0eP L35cJj91a9AoxMz/ej0erv0iI1flLeoYP9aJzIRtZf+SB1BZkKhmWlFRQKqnlIOA BzjYui4mUoEQEa5Sk7Th =JfQx -----END PGP SIGNATURE----- Merge tag 'nfs-for-3.14-5' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client bugfixes from Trond Myklebust: "Highlights include: - Fix another nfs4_sequence corruptor in RELEASE_LOCKOWNER - Fix an Oopsable delegation callback race - Fix another bad stateid infinite loop - Fail the data server I/O is the stateid represents a lost lock - Fix an Oopsable sunrpc trace event" * tag 'nfs-for-3.14-5' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: SUNRPC: Fix oops when trace sunrpc_task events in nfs client NFSv4: Fail the truncate() if the lock/open stateid is invalid NFSv4.1 Fail data server I/O if stateid represents a lost lock NFSv4: Fix the return value of nfs4_select_rw_stateid NFSv4: nfs4_stateid_is_current should return 'true' for an invalid stateid NFS: Fix a delegation callback race NFSv4: Fix another nfs4_sequence corruptor
This commit is contained in:
commit
fe9ea91cde
6 changed files with 37 additions and 31 deletions
|
@ -659,16 +659,19 @@ int nfs_async_inode_return_delegation(struct inode *inode,
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
delegation = rcu_dereference(NFS_I(inode)->delegation);
|
delegation = rcu_dereference(NFS_I(inode)->delegation);
|
||||||
|
if (delegation == NULL)
|
||||||
|
goto out_enoent;
|
||||||
|
|
||||||
if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
|
if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid))
|
||||||
rcu_read_unlock();
|
goto out_enoent;
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
nfs_mark_return_delegation(server, delegation);
|
nfs_mark_return_delegation(server, delegation);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
nfs_delegation_run_state_manager(clp);
|
nfs_delegation_run_state_manager(clp);
|
||||||
return 0;
|
return 0;
|
||||||
|
out_enoent:
|
||||||
|
rcu_read_unlock();
|
||||||
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct inode *
|
static struct inode *
|
||||||
|
|
|
@ -324,8 +324,9 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
|
||||||
&rdata->res.seq_res,
|
&rdata->res.seq_res,
|
||||||
task))
|
task))
|
||||||
return;
|
return;
|
||||||
nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context,
|
if (nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context,
|
||||||
rdata->args.lock_context, FMODE_READ);
|
rdata->args.lock_context, FMODE_READ) == -EIO)
|
||||||
|
rpc_exit(task, -EIO); /* lost lock, terminate I/O */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void filelayout_read_call_done(struct rpc_task *task, void *data)
|
static void filelayout_read_call_done(struct rpc_task *task, void *data)
|
||||||
|
@ -435,8 +436,9 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data)
|
||||||
&wdata->res.seq_res,
|
&wdata->res.seq_res,
|
||||||
task))
|
task))
|
||||||
return;
|
return;
|
||||||
nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context,
|
if (nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context,
|
||||||
wdata->args.lock_context, FMODE_WRITE);
|
wdata->args.lock_context, FMODE_WRITE) == -EIO)
|
||||||
|
rpc_exit(task, -EIO); /* lost lock, terminate I/O */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void filelayout_write_call_done(struct rpc_task *task, void *data)
|
static void filelayout_write_call_done(struct rpc_task *task, void *data)
|
||||||
|
|
|
@ -2398,13 +2398,16 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
||||||
|
|
||||||
if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) {
|
if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) {
|
||||||
/* Use that stateid */
|
/* Use that stateid */
|
||||||
} else if (truncate && state != NULL && nfs4_valid_open_stateid(state)) {
|
} else if (truncate && state != NULL) {
|
||||||
struct nfs_lockowner lockowner = {
|
struct nfs_lockowner lockowner = {
|
||||||
.l_owner = current->files,
|
.l_owner = current->files,
|
||||||
.l_pid = current->tgid,
|
.l_pid = current->tgid,
|
||||||
};
|
};
|
||||||
nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
|
if (!nfs4_valid_open_stateid(state))
|
||||||
&lockowner);
|
return -EBADF;
|
||||||
|
if (nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
|
||||||
|
&lockowner) == -EIO)
|
||||||
|
return -EBADF;
|
||||||
} else
|
} else
|
||||||
nfs4_stateid_copy(&arg.stateid, &zero_stateid);
|
nfs4_stateid_copy(&arg.stateid, &zero_stateid);
|
||||||
|
|
||||||
|
@ -4011,8 +4014,9 @@ static bool nfs4_stateid_is_current(nfs4_stateid *stateid,
|
||||||
{
|
{
|
||||||
nfs4_stateid current_stateid;
|
nfs4_stateid current_stateid;
|
||||||
|
|
||||||
if (nfs4_set_rw_stateid(¤t_stateid, ctx, l_ctx, fmode))
|
/* If the current stateid represents a lost lock, then exit */
|
||||||
return false;
|
if (nfs4_set_rw_stateid(¤t_stateid, ctx, l_ctx, fmode) == -EIO)
|
||||||
|
return true;
|
||||||
return nfs4_stateid_match(stateid, ¤t_stateid);
|
return nfs4_stateid_match(stateid, ¤t_stateid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5828,8 +5832,7 @@ struct nfs_release_lockowner_data {
|
||||||
struct nfs4_lock_state *lsp;
|
struct nfs4_lock_state *lsp;
|
||||||
struct nfs_server *server;
|
struct nfs_server *server;
|
||||||
struct nfs_release_lockowner_args args;
|
struct nfs_release_lockowner_args args;
|
||||||
struct nfs4_sequence_args seq_args;
|
struct nfs_release_lockowner_res res;
|
||||||
struct nfs4_sequence_res seq_res;
|
|
||||||
unsigned long timestamp;
|
unsigned long timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5837,7 +5840,7 @@ static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata
|
||||||
{
|
{
|
||||||
struct nfs_release_lockowner_data *data = calldata;
|
struct nfs_release_lockowner_data *data = calldata;
|
||||||
nfs40_setup_sequence(data->server,
|
nfs40_setup_sequence(data->server,
|
||||||
&data->seq_args, &data->seq_res, task);
|
&data->args.seq_args, &data->res.seq_res, task);
|
||||||
data->timestamp = jiffies;
|
data->timestamp = jiffies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5846,7 +5849,7 @@ static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata)
|
||||||
struct nfs_release_lockowner_data *data = calldata;
|
struct nfs_release_lockowner_data *data = calldata;
|
||||||
struct nfs_server *server = data->server;
|
struct nfs_server *server = data->server;
|
||||||
|
|
||||||
nfs40_sequence_done(task, &data->seq_res);
|
nfs40_sequence_done(task, &data->res.seq_res);
|
||||||
|
|
||||||
switch (task->tk_status) {
|
switch (task->tk_status) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -5887,7 +5890,6 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
|
||||||
data = kmalloc(sizeof(*data), GFP_NOFS);
|
data = kmalloc(sizeof(*data), GFP_NOFS);
|
||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
nfs4_init_sequence(&data->seq_args, &data->seq_res, 0);
|
|
||||||
data->lsp = lsp;
|
data->lsp = lsp;
|
||||||
data->server = server;
|
data->server = server;
|
||||||
data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
|
data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
|
||||||
|
@ -5895,6 +5897,8 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
|
||||||
data->args.lock_owner.s_dev = server->s_dev;
|
data->args.lock_owner.s_dev = server->s_dev;
|
||||||
|
|
||||||
msg.rpc_argp = &data->args;
|
msg.rpc_argp = &data->args;
|
||||||
|
msg.rpc_resp = &data->res;
|
||||||
|
nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
|
||||||
rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
|
rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -974,9 +974,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
|
||||||
else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
|
else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
|
||||||
nfs4_stateid_copy(dst, &lsp->ls_stateid);
|
nfs4_stateid_copy(dst, &lsp->ls_stateid);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
smp_rmb();
|
|
||||||
if (!list_empty(&lsp->ls_seqid.list))
|
|
||||||
ret = -EWOULDBLOCK;
|
|
||||||
}
|
}
|
||||||
spin_unlock(&state->state_lock);
|
spin_unlock(&state->state_lock);
|
||||||
nfs4_put_lock_state(lsp);
|
nfs4_put_lock_state(lsp);
|
||||||
|
@ -984,10 +981,9 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
|
static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
|
||||||
{
|
{
|
||||||
const nfs4_stateid *src;
|
const nfs4_stateid *src;
|
||||||
int ret;
|
|
||||||
int seq;
|
int seq;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -996,12 +992,7 @@ static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
|
||||||
if (test_bit(NFS_OPEN_STATE, &state->flags))
|
if (test_bit(NFS_OPEN_STATE, &state->flags))
|
||||||
src = &state->open_stateid;
|
src = &state->open_stateid;
|
||||||
nfs4_stateid_copy(dst, src);
|
nfs4_stateid_copy(dst, src);
|
||||||
ret = 0;
|
|
||||||
smp_rmb();
|
|
||||||
if (!list_empty(&state->owner->so_seqid.list))
|
|
||||||
ret = -EWOULDBLOCK;
|
|
||||||
} while (read_seqretry(&state->seqlock, seq));
|
} while (read_seqretry(&state->seqlock, seq));
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1026,7 +1017,8 @@ int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
|
||||||
* choose to use.
|
* choose to use.
|
||||||
*/
|
*/
|
||||||
goto out;
|
goto out;
|
||||||
ret = nfs4_copy_open_stateid(dst, state);
|
nfs4_copy_open_stateid(dst, state);
|
||||||
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
if (nfs_server_capable(state->inode, NFS_CAP_STATEID_NFSV41))
|
if (nfs_server_capable(state->inode, NFS_CAP_STATEID_NFSV41))
|
||||||
dst->seqid = 0;
|
dst->seqid = 0;
|
||||||
|
|
|
@ -467,9 +467,14 @@ struct nfs_lockt_res {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nfs_release_lockowner_args {
|
struct nfs_release_lockowner_args {
|
||||||
|
struct nfs4_sequence_args seq_args;
|
||||||
struct nfs_lowner lock_owner;
|
struct nfs_lowner lock_owner;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nfs_release_lockowner_res {
|
||||||
|
struct nfs4_sequence_res seq_res;
|
||||||
|
};
|
||||||
|
|
||||||
struct nfs4_delegreturnargs {
|
struct nfs4_delegreturnargs {
|
||||||
struct nfs4_sequence_args seq_args;
|
struct nfs4_sequence_args seq_args;
|
||||||
const struct nfs_fh *fhandle;
|
const struct nfs_fh *fhandle;
|
||||||
|
|
|
@ -83,7 +83,7 @@ DECLARE_EVENT_CLASS(rpc_task_running,
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
__entry->client_id = clnt->cl_clid;
|
__entry->client_id = clnt ? clnt->cl_clid : -1;
|
||||||
__entry->task_id = task->tk_pid;
|
__entry->task_id = task->tk_pid;
|
||||||
__entry->action = action;
|
__entry->action = action;
|
||||||
__entry->runstate = task->tk_runstate;
|
__entry->runstate = task->tk_runstate;
|
||||||
|
@ -91,7 +91,7 @@ DECLARE_EVENT_CLASS(rpc_task_running,
|
||||||
__entry->flags = task->tk_flags;
|
__entry->flags = task->tk_flags;
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk("task:%u@%u flags=%4.4x state=%4.4lx status=%d action=%pf",
|
TP_printk("task:%u@%d flags=%4.4x state=%4.4lx status=%d action=%pf",
|
||||||
__entry->task_id, __entry->client_id,
|
__entry->task_id, __entry->client_id,
|
||||||
__entry->flags,
|
__entry->flags,
|
||||||
__entry->runstate,
|
__entry->runstate,
|
||||||
|
|
Loading…
Add table
Reference in a new issue