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

Commit f9273188 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull NFS client bugfixes from Trond Myklebust:
 - Stable fix for Oopses in the pNFS files layout driver
 - Fix a regression when doing a non-exclusive file create on NFSv4.x
 - NFSv4.1 security negotiation fixes when looking up the root
   filesystem
 - Fix a memory ordering issue in the pNFS files layout driver

* tag 'nfs-for-3.12-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFS: Give "flavor" an initial value to fix a compile warning
  NFSv4.1: try SECINFO_NO_NAME flavs until one works
  NFSv4.1: Ensure memory ordering between nfs4_ds_connect and nfs4_fl_prepare_ds
  NFSv4.1: nfs4_fl_prepare_ds - fix bugs when the connect attempt fails
  NFSv4: Honour the 'opened' parameter in the atomic_open() filesystem method
parents 522d6d38 367156d9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1458,7 +1458,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,

	trace_nfs_atomic_open_enter(dir, ctx, open_flags);
	nfs_block_sillyrename(dentry->d_parent);
	inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr);
	inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr, opened);
	nfs_unblock_sillyrename(dentry->d_parent);
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
+2 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
	struct inode *dir;
	unsigned openflags = filp->f_flags;
	struct iattr attr;
	int opened = 0;
	int err;

	/*
@@ -55,7 +56,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
		nfs_wb_all(inode);
	}

	inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
	inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, &opened);
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
		switch (err) {
+11 −9
Original line number Diff line number Diff line
@@ -185,6 +185,7 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
	if (status)
		goto out_put;

	smp_wmb();
	ds->ds_clp = clp;
	dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
out:
@@ -801,34 +802,35 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
	struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr;
	struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
	struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);

	if (filelayout_test_devid_unavailable(devid))
		return NULL;
	struct nfs4_pnfs_ds *ret = ds;

	if (ds == NULL) {
		printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
			__func__, ds_idx);
		filelayout_mark_devid_invalid(devid);
		return NULL;
		goto out;
	}
	smp_rmb();
	if (ds->ds_clp)
		return ds;
		goto out_test_devid;

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

		err = nfs4_ds_connect(s, ds);
		if (err) {
		if (err)
			nfs4_mark_deviceid_unavailable(devid);
			ds = NULL;
		}
		nfs4_clear_ds_conn_bit(ds);
	} else {
		/* Either ds is connected, or ds is NULL */
		nfs4_wait_ds_connect(ds);
	}
	return ds;
out_test_devid:
	if (filelayout_test_devid_unavailable(devid))
		ret = NULL;
out:
	return ret;
}

module_param(dataserver_retrans, uint, 0644);
+47 −11
Original line number Diff line number Diff line
@@ -912,6 +912,7 @@ struct nfs4_opendata {
	struct iattr attrs;
	unsigned long timestamp;
	unsigned int rpc_done : 1;
	unsigned int file_created : 1;
	unsigned int is_recover : 1;
	int rpc_status;
	int cancelled;
@@ -1946,8 +1947,13 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)

	nfs_fattr_map_and_free_names(server, &data->f_attr);

	if (o_arg->open_flags & O_CREAT)
	if (o_arg->open_flags & O_CREAT) {
		update_changeattr(dir, &o_res->cinfo);
		if (o_arg->open_flags & O_EXCL)
			data->file_created = 1;
		else if (o_res->cinfo.before != o_res->cinfo.after)
			data->file_created = 1;
	}
	if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
		server->caps &= ~NFS_CAP_POSIX_LOCK;
	if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
@@ -2191,7 +2197,8 @@ static int _nfs4_do_open(struct inode *dir,
			struct nfs_open_context *ctx,
			int flags,
			struct iattr *sattr,
			struct nfs4_label *label)
			struct nfs4_label *label,
			int *opened)
{
	struct nfs4_state_owner  *sp;
	struct nfs4_state     *state = NULL;
@@ -2261,6 +2268,8 @@ static int _nfs4_do_open(struct inode *dir,
			nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
		}
	}
	if (opendata->file_created)
		*opened |= FILE_CREATED;

	if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server))
		*ctx_th = opendata->f_attr.mdsthreshold;
@@ -2289,7 +2298,8 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
					struct nfs_open_context *ctx,
					int flags,
					struct iattr *sattr,
					struct nfs4_label *label)
					struct nfs4_label *label,
					int *opened)
{
	struct nfs_server *server = NFS_SERVER(dir);
	struct nfs4_exception exception = { };
@@ -2297,7 +2307,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
	int status;

	do {
		status = _nfs4_do_open(dir, ctx, flags, sattr, label);
		status = _nfs4_do_open(dir, ctx, flags, sattr, label, opened);
		res = ctx->state;
		trace_nfs4_open_file(ctx, flags, status);
		if (status == 0)
@@ -2659,7 +2669,8 @@ out:
}

static struct inode *
nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx,
		int open_flags, struct iattr *attr, int *opened)
{
	struct nfs4_state *state;
	struct nfs4_label l = {0, 0, 0, NULL}, *label = NULL;
@@ -2667,7 +2678,7 @@ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags
	label = nfs4_label_init_security(dir, ctx->dentry, attr, &l);

	/* Protect against concurrent sillydeletes */
	state = nfs4_do_open(dir, ctx, open_flags, attr, label);
	state = nfs4_do_open(dir, ctx, open_flags, attr, label, opened);

	nfs4_label_release_security(label);

@@ -3332,6 +3343,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
	struct nfs4_label l, *ilabel = NULL;
	struct nfs_open_context *ctx;
	struct nfs4_state *state;
	int opened = 0;
	int status = 0;

	ctx = alloc_nfs_open_context(dentry, FMODE_READ);
@@ -3341,7 +3353,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
	ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);

	sattr->ia_mode &= ~current_umask();
	state = nfs4_do_open(dir, ctx, flags, sattr, ilabel);
	state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, &opened);
	if (IS_ERR(state)) {
		status = PTR_ERR(state);
		goto out;
@@ -7564,8 +7576,10 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
{
	int err;
	struct page *page;
	rpc_authflavor_t flavor;
	rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR;
	struct nfs4_secinfo_flavors *flavors;
	struct nfs4_secinfo4 *secinfo;
	int i;

	page = alloc_page(GFP_KERNEL);
	if (!page) {
@@ -7587,9 +7601,31 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
	if (err)
		goto out_freepage;

	flavor = nfs_find_best_sec(flavors);
	if (err == 0)
		err = nfs4_lookup_root_sec(server, fhandle, info, flavor);
	for (i = 0; i < flavors->num_flavors; i++) {
		secinfo = &flavors->flavors[i];

		switch (secinfo->flavor) {
		case RPC_AUTH_NULL:
		case RPC_AUTH_UNIX:
		case RPC_AUTH_GSS:
			flavor = rpcauth_get_pseudoflavor(secinfo->flavor,
					&secinfo->flavor_info);
			break;
		default:
			flavor = RPC_AUTH_MAXFLAVOR;
			break;
		}

		if (flavor != RPC_AUTH_MAXFLAVOR) {
			err = nfs4_lookup_root_sec(server, fhandle,
						   info, flavor);
			if (!err)
				break;
		}
	}

	if (flavor == RPC_AUTH_MAXFLAVOR)
		err = -EPERM;

out_freepage:
	put_page(page);
+2 −1
Original line number Diff line number Diff line
@@ -1455,7 +1455,8 @@ struct nfs_rpc_ops {
	struct inode * (*open_context) (struct inode *dir,
				struct nfs_open_context *ctx,
				int open_flags,
				struct iattr *iattr);
				struct iattr *iattr,
				int *);
	int (*have_delegation)(struct inode *, fmode_t);
	int (*return_delegation)(struct inode *);
	struct nfs_client *(*alloc_client) (const struct nfs_client_initdata *);