Skip to content

Commit ad746be

Browse files
committed
Merge tag 'nfs-for-3.6-3' of git://git.linux-nfs.org/projects/trondmy/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
2 parents 467e9e5 + 0866004 commit ad746be

File tree

17 files changed

+241
-119
lines changed

17 files changed

+241
-119
lines changed

fs/nfs/Makefile

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@ nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
1212
nfs-$(CONFIG_SYSCTL) += sysctl.o
1313
nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
1414

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

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

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

2929
obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
3030
nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o

fs/nfs/client.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ struct nfs_subversion *get_nfs_version(unsigned int version)
105105

106106
if (IS_ERR(nfs)) {
107107
mutex_lock(&nfs_version_mutex);
108-
request_module("nfs%d", version);
108+
request_module("nfsv%d", version);
109109
nfs = find_nfs_version(version);
110110
mutex_unlock(&nfs_version_mutex);
111111
}

fs/nfs/idmap.c

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ struct idmap {
6161
struct mutex idmap_mutex;
6262
};
6363

64+
struct idmap_legacy_upcalldata {
65+
struct rpc_pipe_msg pipe_msg;
66+
struct idmap_msg idmap_msg;
67+
struct idmap *idmap;
68+
};
69+
6470
/**
6571
* nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
6672
* @fattr: fully initialised struct nfs_fattr
@@ -324,6 +330,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
324330
ret = nfs_idmap_request_key(&key_type_id_resolver_legacy,
325331
name, namelen, type, data,
326332
data_size, idmap);
333+
idmap->idmap_key_cons = NULL;
327334
mutex_unlock(&idmap->idmap_mutex);
328335
}
329336
return ret;
@@ -380,11 +387,13 @@ static const match_table_t nfs_idmap_tokens = {
380387
static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *);
381388
static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
382389
size_t);
390+
static void idmap_release_pipe(struct inode *);
383391
static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
384392

385393
static const struct rpc_pipe_ops idmap_upcall_ops = {
386394
.upcall = rpc_pipe_generic_upcall,
387395
.downcall = idmap_pipe_downcall,
396+
.release_pipe = idmap_release_pipe,
388397
.destroy_msg = idmap_pipe_destroy_msg,
389398
};
390399

@@ -616,7 +625,8 @@ void nfs_idmap_quit(void)
616625
nfs_idmap_quit_keyring();
617626
}
618627

619-
static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im,
628+
static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
629+
struct idmap_msg *im,
620630
struct rpc_pipe_msg *msg)
621631
{
622632
substring_t substr;
@@ -659,22 +669,23 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
659669
const char *op,
660670
void *aux)
661671
{
672+
struct idmap_legacy_upcalldata *data;
662673
struct rpc_pipe_msg *msg;
663674
struct idmap_msg *im;
664675
struct idmap *idmap = (struct idmap *)aux;
665676
struct key *key = cons->key;
666677
int ret = -ENOMEM;
667678

668679
/* msg and im are freed in idmap_pipe_destroy_msg */
669-
msg = kmalloc(sizeof(*msg), GFP_KERNEL);
670-
if (!msg)
671-
goto out0;
672-
673-
im = kmalloc(sizeof(*im), GFP_KERNEL);
674-
if (!im)
680+
data = kmalloc(sizeof(*data), GFP_KERNEL);
681+
if (!data)
675682
goto out1;
676683

677-
ret = nfs_idmap_prepare_message(key->description, im, msg);
684+
msg = &data->pipe_msg;
685+
im = &data->idmap_msg;
686+
data->idmap = idmap;
687+
688+
ret = nfs_idmap_prepare_message(key->description, idmap, im, msg);
678689
if (ret < 0)
679690
goto out2;
680691

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

684695
ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
685696
if (ret < 0)
686-
goto out2;
697+
goto out3;
687698

688699
return ret;
689700

701+
out3:
702+
idmap->idmap_key_cons = NULL;
690703
out2:
691-
kfree(im);
704+
kfree(data);
692705
out1:
693-
kfree(msg);
694-
out0:
695706
complete_request_key(cons, ret);
696707
return ret;
697708
}
@@ -749,9 +760,8 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
749760
}
750761

751762
if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
752-
ret = mlen;
753-
complete_request_key(cons, -ENOKEY);
754-
goto out_incomplete;
763+
ret = -ENOKEY;
764+
goto out;
755765
}
756766

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

769779
out:
770780
complete_request_key(cons, ret);
771-
out_incomplete:
772781
return ret;
773782
}
774783

775784
static void
776785
idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
777786
{
787+
struct idmap_legacy_upcalldata *data = container_of(msg,
788+
struct idmap_legacy_upcalldata,
789+
pipe_msg);
790+
struct idmap *idmap = data->idmap;
791+
struct key_construction *cons;
792+
if (msg->errno) {
793+
cons = ACCESS_ONCE(idmap->idmap_key_cons);
794+
idmap->idmap_key_cons = NULL;
795+
complete_request_key(cons, msg->errno);
796+
}
778797
/* Free memory allocated in nfs_idmap_legacy_upcall() */
779-
kfree(msg->data);
780-
kfree(msg);
798+
kfree(data);
799+
}
800+
801+
static void
802+
idmap_release_pipe(struct inode *inode)
803+
{
804+
struct rpc_inode *rpci = RPC_I(inode);
805+
struct idmap *idmap = (struct idmap *)rpci->private;
806+
idmap->idmap_key_cons = NULL;
781807
}
782808

783809
int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)

fs/nfs/nfs3proc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle,
6969
nfs_fattr_init(info->fattr);
7070
status = rpc_call_sync(client, &msg, 0);
7171
dprintk("%s: reply fsinfo: %d\n", __func__, status);
72-
if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
72+
if (status == 0 && !(info->fattr->valid & NFS_ATTR_FATTR)) {
7373
msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
7474
msg.rpc_resp = info->fattr;
7575
status = rpc_call_sync(client, &msg, 0);

fs/nfs/nfs4_fs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,9 @@ extern const struct dentry_operations nfs4_dentry_operations;
205205
int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
206206
unsigned, umode_t, int *);
207207

208+
/* super.c */
209+
extern struct file_system_type nfs4_fs_type;
210+
208211
/* nfs4namespace.c */
209212
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *);
210213
struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *);

fs/nfs/nfs4client.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
7474
return clp;
7575

7676
error:
77-
kfree(clp);
77+
nfs_free_client(clp);
7878
return ERR_PTR(err);
7979
}
8080

fs/nfs/nfs4proc.c

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3737,9 +3737,10 @@ static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_
37373737
static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len)
37383738
{
37393739
struct nfs4_cached_acl *acl;
3740+
size_t buflen = sizeof(*acl) + acl_len;
37403741

3741-
if (pages && acl_len <= PAGE_SIZE) {
3742-
acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL);
3742+
if (pages && buflen <= PAGE_SIZE) {
3743+
acl = kmalloc(buflen, GFP_KERNEL);
37433744
if (acl == NULL)
37443745
goto out;
37453746
acl->cached = 1;
@@ -3819,7 +3820,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
38193820
if (ret)
38203821
goto out_free;
38213822

3822-
acl_len = res.acl_len - res.acl_data_offset;
3823+
acl_len = res.acl_len;
38233824
if (acl_len > args.acl_len)
38243825
nfs4_write_cached_acl(inode, NULL, 0, acl_len);
38253826
else
@@ -6223,11 +6224,58 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
62236224
dprintk("<-- %s\n", __func__);
62246225
}
62256226

6227+
static size_t max_response_pages(struct nfs_server *server)
6228+
{
6229+
u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
6230+
return nfs_page_array_len(0, max_resp_sz);
6231+
}
6232+
6233+
static void nfs4_free_pages(struct page **pages, size_t size)
6234+
{
6235+
int i;
6236+
6237+
if (!pages)
6238+
return;
6239+
6240+
for (i = 0; i < size; i++) {
6241+
if (!pages[i])
6242+
break;
6243+
__free_page(pages[i]);
6244+
}
6245+
kfree(pages);
6246+
}
6247+
6248+
static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags)
6249+
{
6250+
struct page **pages;
6251+
int i;
6252+
6253+
pages = kcalloc(size, sizeof(struct page *), gfp_flags);
6254+
if (!pages) {
6255+
dprintk("%s: can't alloc array of %zu pages\n", __func__, size);
6256+
return NULL;
6257+
}
6258+
6259+
for (i = 0; i < size; i++) {
6260+
pages[i] = alloc_page(gfp_flags);
6261+
if (!pages[i]) {
6262+
dprintk("%s: failed to allocate page\n", __func__);
6263+
nfs4_free_pages(pages, size);
6264+
return NULL;
6265+
}
6266+
}
6267+
6268+
return pages;
6269+
}
6270+
62266271
static void nfs4_layoutget_release(void *calldata)
62276272
{
62286273
struct nfs4_layoutget *lgp = calldata;
6274+
struct nfs_server *server = NFS_SERVER(lgp->args.inode);
6275+
size_t max_pages = max_response_pages(server);
62296276

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

6242-
int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
6290+
void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
62436291
{
62446292
struct nfs_server *server = NFS_SERVER(lgp->args.inode);
6293+
size_t max_pages = max_response_pages(server);
62456294
struct rpc_task *task;
62466295
struct rpc_message msg = {
62476296
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
@@ -6259,20 +6308,27 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
62596308

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

6311+
lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags);
6312+
if (!lgp->args.layout.pages) {
6313+
nfs4_layoutget_release(lgp);
6314+
return;
6315+
}
6316+
lgp->args.layout.pglen = max_pages * PAGE_SIZE;
6317+
62626318
lgp->res.layoutp = &lgp->args.layout;
62636319
lgp->res.seq_res.sr_slot = NULL;
62646320
nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
62656321
task = rpc_run_task(&task_setup_data);
62666322
if (IS_ERR(task))
6267-
return PTR_ERR(task);
6323+
return;
62686324
status = nfs4_wait_for_completion_rpc_task(task);
62696325
if (status == 0)
62706326
status = task->tk_status;
62716327
if (status == 0)
62726328
status = pnfs_layout_process(lgp);
62736329
rpc_put_task(task);
62746330
dprintk("<-- %s status=%d\n", __func__, status);
6275-
return status;
6331+
return;
62766332
}
62776333

62786334
static void
@@ -6304,12 +6360,8 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
63046360
return;
63056361
}
63066362
spin_lock(&lo->plh_inode->i_lock);
6307-
if (task->tk_status == 0) {
6308-
if (lrp->res.lrs_present) {
6309-
pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
6310-
} else
6311-
BUG_ON(!list_empty(&lo->plh_segs));
6312-
}
6363+
if (task->tk_status == 0 && lrp->res.lrs_present)
6364+
pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
63136365
lo->plh_block_lgets--;
63146366
spin_unlock(&lo->plh_inode->i_lock);
63156367
dprintk("<-- %s\n", __func__);

fs/nfs/nfs4super.c

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,6 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
2323
static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
2424
int flags, const char *dev_name, void *raw_data);
2525

26-
static struct file_system_type nfs4_fs_type = {
27-
.owner = THIS_MODULE,
28-
.name = "nfs4",
29-
.mount = nfs_fs_mount,
30-
.kill_sb = nfs_kill_super,
31-
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
32-
};
33-
3426
static struct file_system_type nfs4_remote_fs_type = {
3527
.owner = THIS_MODULE,
3628
.name = "nfs4",
@@ -344,14 +336,8 @@ static int __init init_nfs_v4(void)
344336
if (err)
345337
goto out1;
346338

347-
err = register_filesystem(&nfs4_fs_type);
348-
if (err < 0)
349-
goto out2;
350-
351339
register_nfs_version(&nfs_v4);
352340
return 0;
353-
out2:
354-
nfs4_unregister_sysctl();
355341
out1:
356342
nfs_idmap_quit();
357343
out:
@@ -361,7 +347,6 @@ static int __init init_nfs_v4(void)
361347
static void __exit exit_nfs_v4(void)
362348
{
363349
unregister_nfs_version(&nfs_v4);
364-
unregister_filesystem(&nfs4_fs_type);
365350
nfs4_unregister_sysctl();
366351
nfs_idmap_quit();
367352
}

0 commit comments

Comments
 (0)