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

Commit 8cbc95ee authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull more NFS client bugfixes from Trond Myklebust:

 - Ensure that we match the 'sec=' mount flavour against the server list

 - Fix the NFSv4 byte range locking in the presence of delegations

 - Ensure that we conform to the NFSv4.1 spec w.r.t.  freeing lock
   stateids

 - Fix a pNFS data server connection race

* tag 'nfs-for-3.10-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFS4.1 Fix data server connection race
  NFSv3: match sec= flavor against server list
  NFSv4.1: Ensure that we free the lock stateid on the server
  NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call
  SUNRPC: Don't spam syslog with "Pseudoflavor not found" messages
  NFSv4.x: Fix handling of partially delegated locks
parents ea44083a c23266d5
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -47,6 +47,8 @@ struct nfs4_minor_version_ops {
			const nfs4_stateid *);
			const nfs4_stateid *);
	int	(*find_root_sec)(struct nfs_server *, struct nfs_fh *,
	int	(*find_root_sec)(struct nfs_server *, struct nfs_fh *,
			struct nfs_fsinfo *);
			struct nfs_fsinfo *);
	int	(*free_lock_state)(struct nfs_server *,
			struct nfs4_lock_state *);
	const struct nfs4_state_recovery_ops *reboot_recovery_ops;
	const struct nfs4_state_recovery_ops *reboot_recovery_ops;
	const struct nfs4_state_recovery_ops *nograce_recovery_ops;
	const struct nfs4_state_recovery_ops *nograce_recovery_ops;
	const struct nfs4_state_maintenance_ops *state_renewal_ops;
	const struct nfs4_state_maintenance_ops *state_renewal_ops;
@@ -234,7 +236,6 @@ extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struc
extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *,
extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *,
			    struct nfs_fh *, struct nfs_fattr *);
			    struct nfs_fh *, struct nfs_fattr *);
extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *);
extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *);
extern int nfs4_release_lockowner(struct nfs4_lock_state *);
extern const struct xattr_handler *nfs4_xattr_handlers[];
extern const struct xattr_handler *nfs4_xattr_handlers[];
extern int nfs4_set_rw_stateid(nfs4_stateid *stateid,
extern int nfs4_set_rw_stateid(nfs4_stateid *stateid,
		const struct nfs_open_context *ctx,
		const struct nfs_open_context *ctx,
+2 −0
Original line number Original line Diff line number Diff line
@@ -70,6 +70,8 @@ struct nfs4_pnfs_ds {
	struct list_head	ds_addrs;
	struct list_head	ds_addrs;
	struct nfs_client	*ds_clp;
	struct nfs_client	*ds_clp;
	atomic_t		ds_count;
	atomic_t		ds_count;
	unsigned long		ds_state;
#define NFS4DS_CONNECTING	0	/* ds is establishing connection */
};
};


struct nfs4_file_layout_dsaddr {
struct nfs4_file_layout_dsaddr {
+24 −2
Original line number Original line Diff line number Diff line
@@ -775,6 +775,22 @@ nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j)
	return flseg->fh_array[i];
	return flseg->fh_array[i];
}
}


static void nfs4_wait_ds_connect(struct nfs4_pnfs_ds *ds)
{
	might_sleep();
	wait_on_bit(&ds->ds_state, NFS4DS_CONNECTING,
			nfs_wait_bit_killable, TASK_KILLABLE);
}

static void nfs4_clear_ds_conn_bit(struct nfs4_pnfs_ds *ds)
{
	smp_mb__before_clear_bit();
	clear_bit(NFS4DS_CONNECTING, &ds->ds_state);
	smp_mb__after_clear_bit();
	wake_up_bit(&ds->ds_state, NFS4DS_CONNECTING);
}


struct nfs4_pnfs_ds *
struct nfs4_pnfs_ds *
nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
{
{
@@ -791,16 +807,22 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
		filelayout_mark_devid_invalid(devid);
		filelayout_mark_devid_invalid(devid);
		return NULL;
		return NULL;
	}
	}
	if (ds->ds_clp)
		return ds;


	if (!ds->ds_clp) {
	if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) {
		struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode);
		struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode);
		int err;
		int err;


		err = nfs4_ds_connect(s, ds);
		err = nfs4_ds_connect(s, ds);
		if (err) {
		if (err) {
			nfs4_mark_deviceid_unavailable(devid);
			nfs4_mark_deviceid_unavailable(devid);
			return NULL;
			ds = NULL;
		}
		}
		nfs4_clear_ds_conn_bit(ds);
	} else {
		/* Either ds is connected, or ds is NULL */
		nfs4_wait_ds_connect(ds);
	}
	}
	return ds;
	return ds;
}
}
+92 −27
Original line number Original line Diff line number Diff line
@@ -4766,9 +4766,9 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
	if (status != 0)
	if (status != 0)
		goto out;
		goto out;
	/* Is this a delegated lock? */
	/* Is this a delegated lock? */
	if (test_bit(NFS_DELEGATED_STATE, &state->flags))
		goto out;
	lsp = request->fl_u.nfs4_fl.owner;
	lsp = request->fl_u.nfs4_fl.owner;
	if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) == 0)
		goto out;
	seqid = nfs_alloc_seqid(&lsp->ls_seqid, GFP_KERNEL);
	seqid = nfs_alloc_seqid(&lsp->ls_seqid, GFP_KERNEL);
	status = -ENOMEM;
	status = -ENOMEM;
	if (seqid == NULL)
	if (seqid == NULL)
@@ -5238,9 +5238,8 @@ static const struct rpc_call_ops nfs4_release_lockowner_ops = {
	.rpc_release = nfs4_release_lockowner_release,
	.rpc_release = nfs4_release_lockowner_release,
};
};


int nfs4_release_lockowner(struct nfs4_lock_state *lsp)
static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp)
{
{
	struct nfs_server *server = lsp->ls_state->owner->so_server;
	struct nfs_release_lockowner_data *data;
	struct nfs_release_lockowner_data *data;
	struct rpc_message msg = {
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER],
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER],
@@ -6783,26 +6782,76 @@ static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
	return err;
	return err;
}
}


static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
struct nfs_free_stateid_data {
	struct nfs_server *server;
	struct nfs41_free_stateid_args args;
	struct nfs41_free_stateid_res res;
};

static void nfs41_free_stateid_prepare(struct rpc_task *task, void *calldata)
{
{
	struct nfs41_free_stateid_args args = {
	struct nfs_free_stateid_data *data = calldata;
		.stateid = stateid,
	nfs41_setup_sequence(nfs4_get_session(data->server),
			&data->args.seq_args,
			&data->res.seq_res,
			task);
}

static void nfs41_free_stateid_done(struct rpc_task *task, void *calldata)
{
	struct nfs_free_stateid_data *data = calldata;

	nfs41_sequence_done(task, &data->res.seq_res);

	switch (task->tk_status) {
	case -NFS4ERR_DELAY:
		if (nfs4_async_handle_error(task, data->server, NULL) == -EAGAIN)
			rpc_restart_call_prepare(task);
	}
}

static void nfs41_free_stateid_release(void *calldata)
{
	kfree(calldata);
}

const struct rpc_call_ops nfs41_free_stateid_ops = {
	.rpc_call_prepare = nfs41_free_stateid_prepare,
	.rpc_call_done = nfs41_free_stateid_done,
	.rpc_release = nfs41_free_stateid_release,
};
};
	struct nfs41_free_stateid_res res;

static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server,
		nfs4_stateid *stateid,
		bool privileged)
{
	struct rpc_message msg = {
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID],
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID],
		.rpc_argp = &args,
		.rpc_resp = &res,
	};
	};
	int status;
	struct rpc_task_setup task_setup = {
		.rpc_client = server->client,
		.rpc_message = &msg,
		.callback_ops = &nfs41_free_stateid_ops,
		.flags = RPC_TASK_ASYNC,
	};
	struct nfs_free_stateid_data *data;


	dprintk("NFS call  free_stateid %p\n", stateid);
	dprintk("NFS call  free_stateid %p\n", stateid);
	nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
	data = kmalloc(sizeof(*data), GFP_NOFS);
	nfs4_set_sequence_privileged(&args.seq_args);
	if (!data)
	status = nfs4_call_sync_sequence(server->client, server, &msg,
		return ERR_PTR(-ENOMEM);
			&args.seq_args, &res.seq_res);
	data->server = server;
	dprintk("NFS reply free_stateid: %d\n", status);
	nfs4_stateid_copy(&data->args.stateid, stateid);
	return status;

	task_setup.callback_data = data;

	msg.rpc_argp = &data->args;
	msg.rpc_resp = &data->res;
	nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
	if (privileged)
		nfs4_set_sequence_privileged(&data->args.seq_args);

	return rpc_run_task(&task_setup);
}
}


/**
/**
@@ -6816,15 +6865,29 @@ static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 */
 */
static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
{
{
	struct nfs4_exception exception = { };
	struct rpc_task *task;
	int err;
	int ret;
	do {

		err = _nfs4_free_stateid(server, stateid);
	task = _nfs41_free_stateid(server, stateid, true);
		if (err != -NFS4ERR_DELAY)
	if (IS_ERR(task))
			break;
		return PTR_ERR(task);
		nfs4_handle_exception(server, err, &exception);
	ret = rpc_wait_for_completion_task(task);
	} while (exception.retry);
	if (!ret)
	return err;
		ret = task->tk_status;
	rpc_put_task(task);
	return ret;
}

static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
{
	struct rpc_task *task;

	task = _nfs41_free_stateid(server, &lsp->ls_stateid, false);
	nfs4_free_lock_state(server, lsp);
	if (IS_ERR(task))
		return PTR_ERR(task);
	rpc_put_task(task);
	return 0;
}
}


static bool nfs41_match_stateid(const nfs4_stateid *s1,
static bool nfs41_match_stateid(const nfs4_stateid *s1,
@@ -6916,6 +6979,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
	.call_sync = _nfs4_call_sync,
	.call_sync = _nfs4_call_sync,
	.match_stateid = nfs4_match_stateid,
	.match_stateid = nfs4_match_stateid,
	.find_root_sec = nfs4_find_root_sec,
	.find_root_sec = nfs4_find_root_sec,
	.free_lock_state = nfs4_release_lockowner,
	.reboot_recovery_ops = &nfs40_reboot_recovery_ops,
	.reboot_recovery_ops = &nfs40_reboot_recovery_ops,
	.nograce_recovery_ops = &nfs40_nograce_recovery_ops,
	.nograce_recovery_ops = &nfs40_nograce_recovery_ops,
	.state_renewal_ops = &nfs40_state_renewal_ops,
	.state_renewal_ops = &nfs40_state_renewal_ops,
@@ -6933,6 +6997,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
	.call_sync = nfs4_call_sync_sequence,
	.call_sync = nfs4_call_sync_sequence,
	.match_stateid = nfs41_match_stateid,
	.match_stateid = nfs41_match_stateid,
	.find_root_sec = nfs41_find_root_sec,
	.find_root_sec = nfs41_find_root_sec,
	.free_lock_state = nfs41_free_lock_state,
	.reboot_recovery_ops = &nfs41_reboot_recovery_ops,
	.reboot_recovery_ops = &nfs41_reboot_recovery_ops,
	.nograce_recovery_ops = &nfs41_nograce_recovery_ops,
	.nograce_recovery_ops = &nfs41_nograce_recovery_ops,
	.state_renewal_ops = &nfs41_state_renewal_ops,
	.state_renewal_ops = &nfs41_state_renewal_ops,
+7 −4
Original line number Original line Diff line number Diff line
@@ -921,6 +921,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_
 */
 */
void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
{
{
	struct nfs_server *server;
	struct nfs4_state *state;
	struct nfs4_state *state;


	if (lsp == NULL)
	if (lsp == NULL)
@@ -932,11 +933,13 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
	if (list_empty(&state->lock_states))
	if (list_empty(&state->lock_states))
		clear_bit(LK_STATE_IN_USE, &state->flags);
		clear_bit(LK_STATE_IN_USE, &state->flags);
	spin_unlock(&state->state_lock);
	spin_unlock(&state->state_lock);
	server = state->owner->so_server;
	if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
	if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
		if (nfs4_release_lockowner(lsp) == 0)
		struct nfs_client *clp = server->nfs_client;
			return;

	}
		clp->cl_mvops->free_lock_state(server, lsp);
	nfs4_free_lock_state(lsp->ls_state->owner->so_server, lsp);
	} else
		nfs4_free_lock_state(server, lsp);
}
}


static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
Loading