Commit fe9ea91c authored by Linus Torvalds's avatar Linus Torvalds

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
parents cf8bf7cd 2ca310fc
...@@ -659,16 +659,19 @@ int nfs_async_inode_return_delegation(struct inode *inode, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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(&current_stateid, ctx, l_ctx, fmode)) /* If the current stateid represents a lost lock, then exit */
return false; if (nfs4_set_rw_stateid(&current_stateid, ctx, l_ctx, fmode) == -EIO)
return true;
return nfs4_stateid_match(stateid, &current_stateid); return nfs4_stateid_match(stateid, &current_stateid);
} }
...@@ -5828,8 +5832,7 @@ struct nfs_release_lockowner_data { ...@@ -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 ...@@ -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) ...@@ -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 ...@@ -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 ...@@ -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, ...@@ -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 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst, ...@@ -984,10 +981,9 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
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) ...@@ -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, ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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,
......
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