Commit f9273188 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-3.12-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

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
...@@ -1458,7 +1458,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -1458,7 +1458,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
trace_nfs_atomic_open_enter(dir, ctx, open_flags); trace_nfs_atomic_open_enter(dir, ctx, open_flags);
nfs_block_sillyrename(dentry->d_parent); 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); nfs_unblock_sillyrename(dentry->d_parent);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
err = PTR_ERR(inode); err = PTR_ERR(inode);
......
...@@ -19,6 +19,7 @@ nfs4_file_open(struct inode *inode, struct file *filp) ...@@ -19,6 +19,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
struct inode *dir; struct inode *dir;
unsigned openflags = filp->f_flags; unsigned openflags = filp->f_flags;
struct iattr attr; struct iattr attr;
int opened = 0;
int err; int err;
/* /*
...@@ -55,7 +56,7 @@ nfs4_file_open(struct inode *inode, struct file *filp) ...@@ -55,7 +56,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
nfs_wb_all(inode); 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)) { if (IS_ERR(inode)) {
err = PTR_ERR(inode); err = PTR_ERR(inode);
switch (err) { switch (err) {
......
...@@ -185,6 +185,7 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds) ...@@ -185,6 +185,7 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
if (status) if (status)
goto out_put; goto out_put;
smp_wmb();
ds->ds_clp = clp; ds->ds_clp = clp;
dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr); dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
out: out:
...@@ -801,34 +802,35 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) ...@@ -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_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr;
struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx]; struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg); struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
struct nfs4_pnfs_ds *ret = ds;
if (filelayout_test_devid_unavailable(devid))
return NULL;
if (ds == NULL) { if (ds == NULL) {
printk(KERN_ERR "NFS: %s: No data server for offset index %d\n", printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
__func__, ds_idx); __func__, ds_idx);
filelayout_mark_devid_invalid(devid); filelayout_mark_devid_invalid(devid);
return NULL; goto out;
} }
smp_rmb();
if (ds->ds_clp) if (ds->ds_clp)
return ds; goto out_test_devid;
if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) { 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);
ds = NULL;
}
nfs4_clear_ds_conn_bit(ds); nfs4_clear_ds_conn_bit(ds);
} else { } else {
/* Either ds is connected, or ds is NULL */ /* Either ds is connected, or ds is NULL */
nfs4_wait_ds_connect(ds); 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); module_param(dataserver_retrans, uint, 0644);
......
...@@ -912,6 +912,7 @@ struct nfs4_opendata { ...@@ -912,6 +912,7 @@ struct nfs4_opendata {
struct iattr attrs; struct iattr attrs;
unsigned long timestamp; unsigned long timestamp;
unsigned int rpc_done : 1; unsigned int rpc_done : 1;
unsigned int file_created : 1;
unsigned int is_recover : 1; unsigned int is_recover : 1;
int rpc_status; int rpc_status;
int cancelled; int cancelled;
...@@ -1946,8 +1947,13 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) ...@@ -1946,8 +1947,13 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
nfs_fattr_map_and_free_names(server, &data->f_attr); 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); 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) if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
server->caps &= ~NFS_CAP_POSIX_LOCK; server->caps &= ~NFS_CAP_POSIX_LOCK;
if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
...@@ -2191,7 +2197,8 @@ static int _nfs4_do_open(struct inode *dir, ...@@ -2191,7 +2197,8 @@ static int _nfs4_do_open(struct inode *dir,
struct nfs_open_context *ctx, struct nfs_open_context *ctx,
int flags, int flags,
struct iattr *sattr, struct iattr *sattr,
struct nfs4_label *label) struct nfs4_label *label,
int *opened)
{ {
struct nfs4_state_owner *sp; struct nfs4_state_owner *sp;
struct nfs4_state *state = NULL; struct nfs4_state *state = NULL;
...@@ -2261,6 +2268,8 @@ static int _nfs4_do_open(struct inode *dir, ...@@ -2261,6 +2268,8 @@ static int _nfs4_do_open(struct inode *dir,
nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel); 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)) if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server))
*ctx_th = opendata->f_attr.mdsthreshold; *ctx_th = opendata->f_attr.mdsthreshold;
...@@ -2289,7 +2298,8 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, ...@@ -2289,7 +2298,8 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
struct nfs_open_context *ctx, struct nfs_open_context *ctx,
int flags, int flags,
struct iattr *sattr, struct iattr *sattr,
struct nfs4_label *label) struct nfs4_label *label,
int *opened)
{ {
struct nfs_server *server = NFS_SERVER(dir); struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_exception exception = { }; struct nfs4_exception exception = { };
...@@ -2297,7 +2307,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, ...@@ -2297,7 +2307,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
int status; int status;
do { do {
status = _nfs4_do_open(dir, ctx, flags, sattr, label); status = _nfs4_do_open(dir, ctx, flags, sattr, label, opened);
res = ctx->state; res = ctx->state;
trace_nfs4_open_file(ctx, flags, status); trace_nfs4_open_file(ctx, flags, status);
if (status == 0) if (status == 0)
...@@ -2659,7 +2669,8 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait) ...@@ -2659,7 +2669,8 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
} }
static struct inode * 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_state *state;
struct nfs4_label l = {0, 0, 0, NULL}, *label = NULL; 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 ...@@ -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); label = nfs4_label_init_security(dir, ctx->dentry, attr, &l);
/* Protect against concurrent sillydeletes */ /* 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); nfs4_label_release_security(label);
...@@ -3332,6 +3343,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, ...@@ -3332,6 +3343,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
struct nfs4_label l, *ilabel = NULL; struct nfs4_label l, *ilabel = NULL;
struct nfs_open_context *ctx; struct nfs_open_context *ctx;
struct nfs4_state *state; struct nfs4_state *state;
int opened = 0;
int status = 0; int status = 0;
ctx = alloc_nfs_open_context(dentry, FMODE_READ); ctx = alloc_nfs_open_context(dentry, FMODE_READ);
...@@ -3341,7 +3353,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, ...@@ -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); ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);
sattr->ia_mode &= ~current_umask(); 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)) { if (IS_ERR(state)) {
status = PTR_ERR(state); status = PTR_ERR(state);
goto out; goto out;
...@@ -7564,8 +7576,10 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -7564,8 +7576,10 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
{ {
int err; int err;
struct page *page; struct page *page;
rpc_authflavor_t flavor; rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR;
struct nfs4_secinfo_flavors *flavors; struct nfs4_secinfo_flavors *flavors;
struct nfs4_secinfo4 *secinfo;
int i;
page = alloc_page(GFP_KERNEL); page = alloc_page(GFP_KERNEL);
if (!page) { if (!page) {
...@@ -7587,9 +7601,31 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -7587,9 +7601,31 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
if (err) if (err)
goto out_freepage; goto out_freepage;
flavor = nfs_find_best_sec(flavors); for (i = 0; i < flavors->num_flavors; i++) {
if (err == 0) secinfo = &flavors->flavors[i];
err = nfs4_lookup_root_sec(server, fhandle, info, flavor);
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: out_freepage:
put_page(page); put_page(page);
......
...@@ -1455,7 +1455,8 @@ struct nfs_rpc_ops { ...@@ -1455,7 +1455,8 @@ struct nfs_rpc_ops {
struct inode * (*open_context) (struct inode *dir, struct inode * (*open_context) (struct inode *dir,
struct nfs_open_context *ctx, struct nfs_open_context *ctx,
int open_flags, int open_flags,
struct iattr *iattr); struct iattr *iattr,
int *);
int (*have_delegation)(struct inode *, fmode_t); int (*have_delegation)(struct inode *, fmode_t);
int (*return_delegation)(struct inode *); int (*return_delegation)(struct inode *);
struct nfs_client *(*alloc_client) (const struct nfs_client_initdata *); struct nfs_client *(*alloc_client) (const struct nfs_client_initdata *);
......
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