Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe9ea91c authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+7 −4
Original line number Original line Diff line number Diff line
@@ -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 *
+6 −4
Original line number Original line Diff line number Diff line
@@ -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)
+14 −10
Original line number Original line Diff line number Diff line
@@ -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(&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 {
	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;
}
}
+3 −11
Original line number Original line Diff line number Diff line
@@ -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,
	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;
+5 −0
Original line number Original line Diff line number Diff line
@@ -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;
Loading