Skip to content

Commit

Permalink
Merge tag 'nfs-for-3.6-3' of git://git.linux-nfs.org/projects/trondmy…
Browse files Browse the repository at this point in the history
…/linux-nfs

Pull NFS client bugfixes from Trond Myklebust:
 - NFSv3 mounts need to fail if the FSINFO rpc call fails
 - Ensure that the NFS commit cache gets torn down when we unload the
   NFS module.
 - Fix memory scribble issues when interrupting a LAYOUTGET rpc call
 - Fix NFSv4 legacy idmapper regressions
 - Fix issues with the NFSv4 getacl command
 - Fix a regression when using the legacy "mount -t nfs4"

* tag 'nfs-for-3.6-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFSv3: Ensure that do_proc_get_root() reports errors correctly
  NFSv4: Ensure that nfs4_alloc_client cleans up on error.
  NFS: return -ENOKEY when the upcall fails to map the name
  NFS: Clear key construction data if the idmap upcall fails
  NFSv4: Don't use private xdr_stream fields in decode_getacl
  NFSv4: Fix the acl cache size calculation
  NFSv4: Fix pointer arithmetic in decode_getacl
  NFS: Alias the nfs module to nfs4
  NFS: Fix a regression when loading the NFS v4 module
  NFSv4.1: Remove a bogus BUG_ON() in nfs4_layoutreturn_done
  pnfs-obj: Better IO pattern in case of unaligned offset
  NFS41: add pg_layout_private to nfs_pageio_descriptor
  pnfs: nfs4_proc_layoutget returns void
  pnfs: defer release of pages in layoutget
  nfs: tear down caches in nfs_init_writepagecache when allocation fails
  • Loading branch information
Linus Torvalds committed Aug 22, 2012
2 parents 467e9e5 + 0866004 commit ad746be
Show file tree
Hide file tree
Showing 17 changed files with 241 additions and 119 deletions.
18 changes: 9 additions & 9 deletions fs/nfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
nfs-$(CONFIG_SYSCTL) += sysctl.o
nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o

obj-$(CONFIG_NFS_V2) += nfs2.o
nfs2-y := nfs2super.o proc.o nfs2xdr.o
obj-$(CONFIG_NFS_V2) += nfsv2.o
nfsv2-y := nfs2super.o proc.o nfs2xdr.o

obj-$(CONFIG_NFS_V3) += nfs3.o
nfs3-y := nfs3super.o nfs3client.o nfs3proc.o nfs3xdr.o
nfs3-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
obj-$(CONFIG_NFS_V3) += nfsv3.o
nfsv3-y := nfs3super.o nfs3client.o nfs3proc.o nfs3xdr.o
nfsv3-$(CONFIG_NFS_V3_ACL) += nfs3acl.o

obj-$(CONFIG_NFS_V4) += nfs4.o
nfs4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o \
obj-$(CONFIG_NFS_V4) += nfsv4.o
nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o \
delegation.o idmap.o callback.o callback_xdr.o callback_proc.o \
nfs4namespace.o nfs4getroot.o nfs4client.o
nfs4-$(CONFIG_SYSCTL) += nfs4sysctl.o
nfs4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o
nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o
nfsv4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o

obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o
Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ struct nfs_subversion *get_nfs_version(unsigned int version)

if (IS_ERR(nfs)) {
mutex_lock(&nfs_version_mutex);
request_module("nfs%d", version);
request_module("nfsv%d", version);
nfs = find_nfs_version(version);
mutex_unlock(&nfs_version_mutex);
}
Expand Down
62 changes: 44 additions & 18 deletions fs/nfs/idmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ struct idmap {
struct mutex idmap_mutex;
};

struct idmap_legacy_upcalldata {
struct rpc_pipe_msg pipe_msg;
struct idmap_msg idmap_msg;
struct idmap *idmap;
};

/**
* nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
* @fattr: fully initialised struct nfs_fattr
Expand Down Expand Up @@ -324,6 +330,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
ret = nfs_idmap_request_key(&key_type_id_resolver_legacy,
name, namelen, type, data,
data_size, idmap);
idmap->idmap_key_cons = NULL;
mutex_unlock(&idmap->idmap_mutex);
}
return ret;
Expand Down Expand Up @@ -380,11 +387,13 @@ static const match_table_t nfs_idmap_tokens = {
static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *);
static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
size_t);
static void idmap_release_pipe(struct inode *);
static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);

static const struct rpc_pipe_ops idmap_upcall_ops = {
.upcall = rpc_pipe_generic_upcall,
.downcall = idmap_pipe_downcall,
.release_pipe = idmap_release_pipe,
.destroy_msg = idmap_pipe_destroy_msg,
};

Expand Down Expand Up @@ -616,7 +625,8 @@ void nfs_idmap_quit(void)
nfs_idmap_quit_keyring();
}

static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im,
static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
struct idmap_msg *im,
struct rpc_pipe_msg *msg)
{
substring_t substr;
Expand Down Expand Up @@ -659,22 +669,23 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
const char *op,
void *aux)
{
struct idmap_legacy_upcalldata *data;
struct rpc_pipe_msg *msg;
struct idmap_msg *im;
struct idmap *idmap = (struct idmap *)aux;
struct key *key = cons->key;
int ret = -ENOMEM;

/* msg and im are freed in idmap_pipe_destroy_msg */
msg = kmalloc(sizeof(*msg), GFP_KERNEL);
if (!msg)
goto out0;

im = kmalloc(sizeof(*im), GFP_KERNEL);
if (!im)
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
goto out1;

ret = nfs_idmap_prepare_message(key->description, im, msg);
msg = &data->pipe_msg;
im = &data->idmap_msg;
data->idmap = idmap;

ret = nfs_idmap_prepare_message(key->description, idmap, im, msg);
if (ret < 0)
goto out2;

Expand All @@ -683,15 +694,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,

ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
if (ret < 0)
goto out2;
goto out3;

return ret;

out3:
idmap->idmap_key_cons = NULL;
out2:
kfree(im);
kfree(data);
out1:
kfree(msg);
out0:
complete_request_key(cons, ret);
return ret;
}
Expand Down Expand Up @@ -749,9 +760,8 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
}

if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
ret = mlen;
complete_request_key(cons, -ENOKEY);
goto out_incomplete;
ret = -ENOKEY;
goto out;
}

namelen_in = strnlen(im.im_name, IDMAP_NAMESZ);
Expand All @@ -768,16 +778,32 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)

out:
complete_request_key(cons, ret);
out_incomplete:
return ret;
}

static void
idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
{
struct idmap_legacy_upcalldata *data = container_of(msg,
struct idmap_legacy_upcalldata,
pipe_msg);
struct idmap *idmap = data->idmap;
struct key_construction *cons;
if (msg->errno) {
cons = ACCESS_ONCE(idmap->idmap_key_cons);
idmap->idmap_key_cons = NULL;
complete_request_key(cons, msg->errno);
}
/* Free memory allocated in nfs_idmap_legacy_upcall() */
kfree(msg->data);
kfree(msg);
kfree(data);
}

static void
idmap_release_pipe(struct inode *inode)
{
struct rpc_inode *rpci = RPC_I(inode);
struct idmap *idmap = (struct idmap *)rpci->private;
idmap->idmap_key_cons = NULL;
}

int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/nfs3proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle,
nfs_fattr_init(info->fattr);
status = rpc_call_sync(client, &msg, 0);
dprintk("%s: reply fsinfo: %d\n", __func__, status);
if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
if (status == 0 && !(info->fattr->valid & NFS_ATTR_FATTR)) {
msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
msg.rpc_resp = info->fattr;
status = rpc_call_sync(client, &msg, 0);
Expand Down
3 changes: 3 additions & 0 deletions fs/nfs/nfs4_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ extern const struct dentry_operations nfs4_dentry_operations;
int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
unsigned, umode_t, int *);

/* super.c */
extern struct file_system_type nfs4_fs_type;

/* nfs4namespace.c */
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *);
struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *);
Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/nfs4client.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
return clp;

error:
kfree(clp);
nfs_free_client(clp);
return ERR_PTR(err);
}

Expand Down
76 changes: 64 additions & 12 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3737,9 +3737,10 @@ static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_
static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len)
{
struct nfs4_cached_acl *acl;
size_t buflen = sizeof(*acl) + acl_len;

if (pages && acl_len <= PAGE_SIZE) {
acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL);
if (pages && buflen <= PAGE_SIZE) {
acl = kmalloc(buflen, GFP_KERNEL);
if (acl == NULL)
goto out;
acl->cached = 1;
Expand Down Expand Up @@ -3819,7 +3820,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
if (ret)
goto out_free;

acl_len = res.acl_len - res.acl_data_offset;
acl_len = res.acl_len;
if (acl_len > args.acl_len)
nfs4_write_cached_acl(inode, NULL, 0, acl_len);
else
Expand Down Expand Up @@ -6223,11 +6224,58 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
dprintk("<-- %s\n", __func__);
}

static size_t max_response_pages(struct nfs_server *server)
{
u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
return nfs_page_array_len(0, max_resp_sz);
}

static void nfs4_free_pages(struct page **pages, size_t size)
{
int i;

if (!pages)
return;

for (i = 0; i < size; i++) {
if (!pages[i])
break;
__free_page(pages[i]);
}
kfree(pages);
}

static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags)
{
struct page **pages;
int i;

pages = kcalloc(size, sizeof(struct page *), gfp_flags);
if (!pages) {
dprintk("%s: can't alloc array of %zu pages\n", __func__, size);
return NULL;
}

for (i = 0; i < size; i++) {
pages[i] = alloc_page(gfp_flags);
if (!pages[i]) {
dprintk("%s: failed to allocate page\n", __func__);
nfs4_free_pages(pages, size);
return NULL;
}
}

return pages;
}

static void nfs4_layoutget_release(void *calldata)
{
struct nfs4_layoutget *lgp = calldata;
struct nfs_server *server = NFS_SERVER(lgp->args.inode);
size_t max_pages = max_response_pages(server);

dprintk("--> %s\n", __func__);
nfs4_free_pages(lgp->args.layout.pages, max_pages);
put_nfs_open_context(lgp->args.ctx);
kfree(calldata);
dprintk("<-- %s\n", __func__);
Expand All @@ -6239,9 +6287,10 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = {
.rpc_release = nfs4_layoutget_release,
};

int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
{
struct nfs_server *server = NFS_SERVER(lgp->args.inode);
size_t max_pages = max_response_pages(server);
struct rpc_task *task;
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
Expand All @@ -6259,20 +6308,27 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)

dprintk("--> %s\n", __func__);

lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags);
if (!lgp->args.layout.pages) {
nfs4_layoutget_release(lgp);
return;
}
lgp->args.layout.pglen = max_pages * PAGE_SIZE;

lgp->res.layoutp = &lgp->args.layout;
lgp->res.seq_res.sr_slot = NULL;
nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
task = rpc_run_task(&task_setup_data);
if (IS_ERR(task))
return PTR_ERR(task);
return;
status = nfs4_wait_for_completion_rpc_task(task);
if (status == 0)
status = task->tk_status;
if (status == 0)
status = pnfs_layout_process(lgp);
rpc_put_task(task);
dprintk("<-- %s status=%d\n", __func__, status);
return status;
return;
}

static void
Expand Down Expand Up @@ -6304,12 +6360,8 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
return;
}
spin_lock(&lo->plh_inode->i_lock);
if (task->tk_status == 0) {
if (lrp->res.lrs_present) {
pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
} else
BUG_ON(!list_empty(&lo->plh_segs));
}
if (task->tk_status == 0 && lrp->res.lrs_present)
pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
lo->plh_block_lgets--;
spin_unlock(&lo->plh_inode->i_lock);
dprintk("<-- %s\n", __func__);
Expand Down
15 changes: 0 additions & 15 deletions fs/nfs/nfs4super.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,6 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data);

static struct file_system_type nfs4_fs_type = {
.owner = THIS_MODULE,
.name = "nfs4",
.mount = nfs_fs_mount,
.kill_sb = nfs_kill_super,
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
};

static struct file_system_type nfs4_remote_fs_type = {
.owner = THIS_MODULE,
.name = "nfs4",
Expand Down Expand Up @@ -344,14 +336,8 @@ static int __init init_nfs_v4(void)
if (err)
goto out1;

err = register_filesystem(&nfs4_fs_type);
if (err < 0)
goto out2;

register_nfs_version(&nfs_v4);
return 0;
out2:
nfs4_unregister_sysctl();
out1:
nfs_idmap_quit();
out:
Expand All @@ -361,7 +347,6 @@ static int __init init_nfs_v4(void)
static void __exit exit_nfs_v4(void)
{
unregister_nfs_version(&nfs_v4);
unregister_filesystem(&nfs4_fs_type);
nfs4_unregister_sysctl();
nfs_idmap_quit();
}
Expand Down
Loading

0 comments on commit ad746be

Please sign in to comment.