Commit ad746be96941ddd2fb31fad7a629de7912051c8d
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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
Showing 17 changed files Side-by-side Diff
- fs/nfs/Makefile
- fs/nfs/client.c
- fs/nfs/idmap.c
- fs/nfs/nfs3proc.c
- fs/nfs/nfs4_fs.h
- fs/nfs/nfs4client.c
- fs/nfs/nfs4proc.c
- fs/nfs/nfs4super.c
- fs/nfs/nfs4xdr.c
- fs/nfs/objlayout/objio_osd.c
- fs/nfs/pagelist.c
- fs/nfs/pnfs.c
- fs/nfs/pnfs.h
- fs/nfs/super.c
- fs/nfs/write.c
- include/linux/nfs_page.h
- include/linux/nfs_xdr.h
fs/nfs/Makefile
... | ... | @@ -12,19 +12,19 @@ |
12 | 12 | nfs-$(CONFIG_SYSCTL) += sysctl.o |
13 | 13 | nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o |
14 | 14 | |
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 | |
17 | 17 | |
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 | |
21 | 21 | |
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 \ | |
24 | 24 | delegation.o idmap.o callback.o callback_xdr.o callback_proc.o \ |
25 | 25 | 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 | |
28 | 28 | |
29 | 29 | obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o |
30 | 30 | nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o |
fs/nfs/client.c
fs/nfs/idmap.c
... | ... | @@ -61,6 +61,12 @@ |
61 | 61 | struct mutex idmap_mutex; |
62 | 62 | }; |
63 | 63 | |
64 | +struct idmap_legacy_upcalldata { | |
65 | + struct rpc_pipe_msg pipe_msg; | |
66 | + struct idmap_msg idmap_msg; | |
67 | + struct idmap *idmap; | |
68 | +}; | |
69 | + | |
64 | 70 | /** |
65 | 71 | * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields |
66 | 72 | * @fattr: fully initialised struct nfs_fattr |
... | ... | @@ -324,6 +330,7 @@ |
324 | 330 | ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, |
325 | 331 | name, namelen, type, data, |
326 | 332 | data_size, idmap); |
333 | + idmap->idmap_key_cons = NULL; | |
327 | 334 | mutex_unlock(&idmap->idmap_mutex); |
328 | 335 | } |
329 | 336 | return ret; |
330 | 337 | |
... | ... | @@ -380,11 +387,13 @@ |
380 | 387 | static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *); |
381 | 388 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, |
382 | 389 | size_t); |
390 | +static void idmap_release_pipe(struct inode *); | |
383 | 391 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); |
384 | 392 | |
385 | 393 | static const struct rpc_pipe_ops idmap_upcall_ops = { |
386 | 394 | .upcall = rpc_pipe_generic_upcall, |
387 | 395 | .downcall = idmap_pipe_downcall, |
396 | + .release_pipe = idmap_release_pipe, | |
388 | 397 | .destroy_msg = idmap_pipe_destroy_msg, |
389 | 398 | }; |
390 | 399 | |
... | ... | @@ -616,7 +625,8 @@ |
616 | 625 | nfs_idmap_quit_keyring(); |
617 | 626 | } |
618 | 627 | |
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, | |
620 | 630 | struct rpc_pipe_msg *msg) |
621 | 631 | { |
622 | 632 | substring_t substr; |
... | ... | @@ -659,6 +669,7 @@ |
659 | 669 | const char *op, |
660 | 670 | void *aux) |
661 | 671 | { |
672 | + struct idmap_legacy_upcalldata *data; | |
662 | 673 | struct rpc_pipe_msg *msg; |
663 | 674 | struct idmap_msg *im; |
664 | 675 | struct idmap *idmap = (struct idmap *)aux; |
665 | 676 | |
... | ... | @@ -666,15 +677,15 @@ |
666 | 677 | int ret = -ENOMEM; |
667 | 678 | |
668 | 679 | /* 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) | |
675 | 682 | goto out1; |
676 | 683 | |
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); | |
678 | 689 | if (ret < 0) |
679 | 690 | goto out2; |
680 | 691 | |
681 | 692 | |
682 | 693 | |
683 | 694 | |
... | ... | @@ -683,15 +694,15 @@ |
683 | 694 | |
684 | 695 | ret = rpc_queue_upcall(idmap->idmap_pipe, msg); |
685 | 696 | if (ret < 0) |
686 | - goto out2; | |
697 | + goto out3; | |
687 | 698 | |
688 | 699 | return ret; |
689 | 700 | |
701 | +out3: | |
702 | + idmap->idmap_key_cons = NULL; | |
690 | 703 | out2: |
691 | - kfree(im); | |
704 | + kfree(data); | |
692 | 705 | out1: |
693 | - kfree(msg); | |
694 | -out0: | |
695 | 706 | complete_request_key(cons, ret); |
696 | 707 | return ret; |
697 | 708 | } |
... | ... | @@ -749,9 +760,8 @@ |
749 | 760 | } |
750 | 761 | |
751 | 762 | 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; | |
755 | 765 | } |
756 | 766 | |
757 | 767 | namelen_in = strnlen(im.im_name, IDMAP_NAMESZ); |
758 | 768 | |
759 | 769 | |
... | ... | @@ -768,16 +778,32 @@ |
768 | 778 | |
769 | 779 | out: |
770 | 780 | complete_request_key(cons, ret); |
771 | -out_incomplete: | |
772 | 781 | return ret; |
773 | 782 | } |
774 | 783 | |
775 | 784 | static void |
776 | 785 | idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) |
777 | 786 | { |
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 | + } | |
778 | 797 | /* 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; | |
781 | 807 | } |
782 | 808 | |
783 | 809 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) |
fs/nfs/nfs3proc.c
... | ... | @@ -69,7 +69,7 @@ |
69 | 69 | nfs_fattr_init(info->fattr); |
70 | 70 | status = rpc_call_sync(client, &msg, 0); |
71 | 71 | 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)) { | |
73 | 73 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; |
74 | 74 | msg.rpc_resp = info->fattr; |
75 | 75 | status = rpc_call_sync(client, &msg, 0); |
fs/nfs/nfs4_fs.h
... | ... | @@ -205,6 +205,9 @@ |
205 | 205 | int nfs_atomic_open(struct inode *, struct dentry *, struct file *, |
206 | 206 | unsigned, umode_t, int *); |
207 | 207 | |
208 | +/* super.c */ | |
209 | +extern struct file_system_type nfs4_fs_type; | |
210 | + | |
208 | 211 | /* nfs4namespace.c */ |
209 | 212 | rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *); |
210 | 213 | struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *); |
fs/nfs/nfs4client.c
fs/nfs/nfs4proc.c
... | ... | @@ -3737,9 +3737,10 @@ |
3737 | 3737 | static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len) |
3738 | 3738 | { |
3739 | 3739 | struct nfs4_cached_acl *acl; |
3740 | + size_t buflen = sizeof(*acl) + acl_len; | |
3740 | 3741 | |
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); | |
3743 | 3744 | if (acl == NULL) |
3744 | 3745 | goto out; |
3745 | 3746 | acl->cached = 1; |
... | ... | @@ -3819,7 +3820,7 @@ |
3819 | 3820 | if (ret) |
3820 | 3821 | goto out_free; |
3821 | 3822 | |
3822 | - acl_len = res.acl_len - res.acl_data_offset; | |
3823 | + acl_len = res.acl_len; | |
3823 | 3824 | if (acl_len > args.acl_len) |
3824 | 3825 | nfs4_write_cached_acl(inode, NULL, 0, acl_len); |
3825 | 3826 | else |
3826 | 3827 | |
3827 | 3828 | |
... | ... | @@ -6223,11 +6224,58 @@ |
6223 | 6224 | dprintk("<-- %s\n", __func__); |
6224 | 6225 | } |
6225 | 6226 | |
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 | + | |
6226 | 6271 | static void nfs4_layoutget_release(void *calldata) |
6227 | 6272 | { |
6228 | 6273 | struct nfs4_layoutget *lgp = calldata; |
6274 | + struct nfs_server *server = NFS_SERVER(lgp->args.inode); | |
6275 | + size_t max_pages = max_response_pages(server); | |
6229 | 6276 | |
6230 | 6277 | dprintk("--> %s\n", __func__); |
6278 | + nfs4_free_pages(lgp->args.layout.pages, max_pages); | |
6231 | 6279 | put_nfs_open_context(lgp->args.ctx); |
6232 | 6280 | kfree(calldata); |
6233 | 6281 | dprintk("<-- %s\n", __func__); |
6234 | 6282 | |
... | ... | @@ -6239,9 +6287,10 @@ |
6239 | 6287 | .rpc_release = nfs4_layoutget_release, |
6240 | 6288 | }; |
6241 | 6289 | |
6242 | -int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) | |
6290 | +void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) | |
6243 | 6291 | { |
6244 | 6292 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); |
6293 | + size_t max_pages = max_response_pages(server); | |
6245 | 6294 | struct rpc_task *task; |
6246 | 6295 | struct rpc_message msg = { |
6247 | 6296 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET], |
6248 | 6297 | |
... | ... | @@ -6259,12 +6308,19 @@ |
6259 | 6308 | |
6260 | 6309 | dprintk("--> %s\n", __func__); |
6261 | 6310 | |
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 | + | |
6262 | 6318 | lgp->res.layoutp = &lgp->args.layout; |
6263 | 6319 | lgp->res.seq_res.sr_slot = NULL; |
6264 | 6320 | nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); |
6265 | 6321 | task = rpc_run_task(&task_setup_data); |
6266 | 6322 | if (IS_ERR(task)) |
6267 | - return PTR_ERR(task); | |
6323 | + return; | |
6268 | 6324 | status = nfs4_wait_for_completion_rpc_task(task); |
6269 | 6325 | if (status == 0) |
6270 | 6326 | status = task->tk_status; |
... | ... | @@ -6272,7 +6328,7 @@ |
6272 | 6328 | status = pnfs_layout_process(lgp); |
6273 | 6329 | rpc_put_task(task); |
6274 | 6330 | dprintk("<-- %s status=%d\n", __func__, status); |
6275 | - return status; | |
6331 | + return; | |
6276 | 6332 | } |
6277 | 6333 | |
6278 | 6334 | static void |
... | ... | @@ -6304,12 +6360,8 @@ |
6304 | 6360 | return; |
6305 | 6361 | } |
6306 | 6362 | 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); | |
6313 | 6365 | lo->plh_block_lgets--; |
6314 | 6366 | spin_unlock(&lo->plh_inode->i_lock); |
6315 | 6367 | dprintk("<-- %s\n", __func__); |
fs/nfs/nfs4super.c
... | ... | @@ -23,14 +23,6 @@ |
23 | 23 | static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, |
24 | 24 | int flags, const char *dev_name, void *raw_data); |
25 | 25 | |
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 | - | |
34 | 26 | static struct file_system_type nfs4_remote_fs_type = { |
35 | 27 | .owner = THIS_MODULE, |
36 | 28 | .name = "nfs4", |
37 | 29 | |
... | ... | @@ -344,14 +336,8 @@ |
344 | 336 | if (err) |
345 | 337 | goto out1; |
346 | 338 | |
347 | - err = register_filesystem(&nfs4_fs_type); | |
348 | - if (err < 0) | |
349 | - goto out2; | |
350 | - | |
351 | 339 | register_nfs_version(&nfs_v4); |
352 | 340 | return 0; |
353 | -out2: | |
354 | - nfs4_unregister_sysctl(); | |
355 | 341 | out1: |
356 | 342 | nfs_idmap_quit(); |
357 | 343 | out: |
... | ... | @@ -361,7 +347,6 @@ |
361 | 347 | static void __exit exit_nfs_v4(void) |
362 | 348 | { |
363 | 349 | unregister_nfs_version(&nfs_v4); |
364 | - unregister_filesystem(&nfs4_fs_type); | |
365 | 350 | nfs4_unregister_sysctl(); |
366 | 351 | nfs_idmap_quit(); |
367 | 352 | } |
fs/nfs/nfs4xdr.c
... | ... | @@ -5045,23 +5045,20 @@ |
5045 | 5045 | struct nfs_getaclres *res) |
5046 | 5046 | { |
5047 | 5047 | unsigned int savep; |
5048 | - __be32 *bm_p; | |
5049 | 5048 | uint32_t attrlen, |
5050 | 5049 | bitmap[3] = {0}; |
5051 | 5050 | int status; |
5052 | - size_t page_len = xdr->buf->page_len; | |
5051 | + unsigned int pg_offset; | |
5053 | 5052 | |
5054 | 5053 | res->acl_len = 0; |
5055 | 5054 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) |
5056 | 5055 | goto out; |
5057 | 5056 | |
5058 | - bm_p = xdr->p; | |
5059 | - res->acl_data_offset = be32_to_cpup(bm_p) + 2; | |
5060 | - res->acl_data_offset <<= 2; | |
5061 | - /* Check if the acl data starts beyond the allocated buffer */ | |
5062 | - if (res->acl_data_offset > page_len) | |
5063 | - return -ERANGE; | |
5057 | + xdr_enter_page(xdr, xdr->buf->page_len); | |
5064 | 5058 | |
5059 | + /* Calculate the offset of the page data */ | |
5060 | + pg_offset = xdr->buf->head[0].iov_len; | |
5061 | + | |
5065 | 5062 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) |
5066 | 5063 | goto out; |
5067 | 5064 | if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) |
5068 | 5065 | |
5069 | 5066 | |
5070 | 5067 | |
5071 | 5068 | |
... | ... | @@ -5074,23 +5071,20 @@ |
5074 | 5071 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words |
5075 | 5072 | * are stored with the acl data to handle the problem of |
5076 | 5073 | * variable length bitmaps.*/ |
5077 | - xdr->p = bm_p; | |
5074 | + res->acl_data_offset = xdr_stream_pos(xdr) - pg_offset; | |
5078 | 5075 | |
5079 | 5076 | /* We ignore &savep and don't do consistency checks on |
5080 | 5077 | * the attr length. Let userspace figure it out.... */ |
5081 | - attrlen += res->acl_data_offset; | |
5082 | - if (attrlen > page_len) { | |
5078 | + res->acl_len = attrlen; | |
5079 | + if (attrlen > (xdr->nwords << 2)) { | |
5083 | 5080 | if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { |
5084 | 5081 | /* getxattr interface called with a NULL buf */ |
5085 | - res->acl_len = attrlen; | |
5086 | 5082 | goto out; |
5087 | 5083 | } |
5088 | - dprintk("NFS: acl reply: attrlen %u > page_len %zu\n", | |
5089 | - attrlen, page_len); | |
5084 | + dprintk("NFS: acl reply: attrlen %u > page_len %u\n", | |
5085 | + attrlen, xdr->nwords << 2); | |
5090 | 5086 | return -EINVAL; |
5091 | 5087 | } |
5092 | - xdr_read_pages(xdr, attrlen); | |
5093 | - res->acl_len = attrlen; | |
5094 | 5088 | } else |
5095 | 5089 | status = -EOPNOTSUPP; |
5096 | 5090 |
fs/nfs/objlayout/objio_osd.c
... | ... | @@ -570,17 +570,66 @@ |
570 | 570 | return false; |
571 | 571 | |
572 | 572 | return pgio->pg_count + req->wb_bytes <= |
573 | - OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length; | |
573 | + (unsigned long)pgio->pg_layout_private; | |
574 | 574 | } |
575 | 575 | |
576 | +void objio_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) | |
577 | +{ | |
578 | + pnfs_generic_pg_init_read(pgio, req); | |
579 | + if (unlikely(pgio->pg_lseg == NULL)) | |
580 | + return; /* Not pNFS */ | |
581 | + | |
582 | + pgio->pg_layout_private = (void *) | |
583 | + OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length; | |
584 | +} | |
585 | + | |
586 | +static bool aligned_on_raid_stripe(u64 offset, struct ore_layout *layout, | |
587 | + unsigned long *stripe_end) | |
588 | +{ | |
589 | + u32 stripe_off; | |
590 | + unsigned stripe_size; | |
591 | + | |
592 | + if (layout->raid_algorithm == PNFS_OSD_RAID_0) | |
593 | + return true; | |
594 | + | |
595 | + stripe_size = layout->stripe_unit * | |
596 | + (layout->group_width - layout->parity); | |
597 | + | |
598 | + div_u64_rem(offset, stripe_size, &stripe_off); | |
599 | + if (!stripe_off) | |
600 | + return true; | |
601 | + | |
602 | + *stripe_end = stripe_size - stripe_off; | |
603 | + return false; | |
604 | +} | |
605 | + | |
606 | +void objio_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) | |
607 | +{ | |
608 | + unsigned long stripe_end = 0; | |
609 | + | |
610 | + pnfs_generic_pg_init_write(pgio, req); | |
611 | + if (unlikely(pgio->pg_lseg == NULL)) | |
612 | + return; /* Not pNFS */ | |
613 | + | |
614 | + if (req->wb_offset || | |
615 | + !aligned_on_raid_stripe(req->wb_index * PAGE_SIZE, | |
616 | + &OBJIO_LSEG(pgio->pg_lseg)->layout, | |
617 | + &stripe_end)) { | |
618 | + pgio->pg_layout_private = (void *)stripe_end; | |
619 | + } else { | |
620 | + pgio->pg_layout_private = (void *) | |
621 | + OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length; | |
622 | + } | |
623 | +} | |
624 | + | |
576 | 625 | static const struct nfs_pageio_ops objio_pg_read_ops = { |
577 | - .pg_init = pnfs_generic_pg_init_read, | |
626 | + .pg_init = objio_init_read, | |
578 | 627 | .pg_test = objio_pg_test, |
579 | 628 | .pg_doio = pnfs_generic_pg_readpages, |
580 | 629 | }; |
581 | 630 | |
582 | 631 | static const struct nfs_pageio_ops objio_pg_write_ops = { |
583 | - .pg_init = pnfs_generic_pg_init_write, | |
632 | + .pg_init = objio_init_write, | |
584 | 633 | .pg_test = objio_pg_test, |
585 | 634 | .pg_doio = pnfs_generic_pg_writepages, |
586 | 635 | }; |
fs/nfs/pagelist.c
... | ... | @@ -49,6 +49,7 @@ |
49 | 49 | hdr->io_start = req_offset(hdr->req); |
50 | 50 | hdr->good_bytes = desc->pg_count; |
51 | 51 | hdr->dreq = desc->pg_dreq; |
52 | + hdr->layout_private = desc->pg_layout_private; | |
52 | 53 | hdr->release = release; |
53 | 54 | hdr->completion_ops = desc->pg_completion_ops; |
54 | 55 | if (hdr->completion_ops->init_hdr) |
... | ... | @@ -268,6 +269,7 @@ |
268 | 269 | desc->pg_error = 0; |
269 | 270 | desc->pg_lseg = NULL; |
270 | 271 | desc->pg_dreq = NULL; |
272 | + desc->pg_layout_private = NULL; | |
271 | 273 | } |
272 | 274 | EXPORT_SYMBOL_GPL(nfs_pageio_init); |
273 | 275 |
fs/nfs/pnfs.c
... | ... | @@ -583,9 +583,6 @@ |
583 | 583 | struct nfs_server *server = NFS_SERVER(ino); |
584 | 584 | struct nfs4_layoutget *lgp; |
585 | 585 | struct pnfs_layout_segment *lseg = NULL; |
586 | - struct page **pages = NULL; | |
587 | - int i; | |
588 | - u32 max_resp_sz, max_pages; | |
589 | 586 | |
590 | 587 | dprintk("--> %s\n", __func__); |
591 | 588 | |
... | ... | @@ -594,20 +591,6 @@ |
594 | 591 | if (lgp == NULL) |
595 | 592 | return NULL; |
596 | 593 | |
597 | - /* allocate pages for xdr post processing */ | |
598 | - max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | |
599 | - max_pages = nfs_page_array_len(0, max_resp_sz); | |
600 | - | |
601 | - pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags); | |
602 | - if (!pages) | |
603 | - goto out_err_free; | |
604 | - | |
605 | - for (i = 0; i < max_pages; i++) { | |
606 | - pages[i] = alloc_page(gfp_flags); | |
607 | - if (!pages[i]) | |
608 | - goto out_err_free; | |
609 | - } | |
610 | - | |
611 | 594 | lgp->args.minlength = PAGE_CACHE_SIZE; |
612 | 595 | if (lgp->args.minlength > range->length) |
613 | 596 | lgp->args.minlength = range->length; |
614 | 597 | |
615 | 598 | |
616 | 599 | |
... | ... | @@ -616,39 +599,19 @@ |
616 | 599 | lgp->args.type = server->pnfs_curr_ld->id; |
617 | 600 | lgp->args.inode = ino; |
618 | 601 | lgp->args.ctx = get_nfs_open_context(ctx); |
619 | - lgp->args.layout.pages = pages; | |
620 | - lgp->args.layout.pglen = max_pages * PAGE_SIZE; | |
621 | 602 | lgp->lsegpp = &lseg; |
622 | 603 | lgp->gfp_flags = gfp_flags; |
623 | 604 | |
624 | 605 | /* Synchronously retrieve layout information from server and |
625 | 606 | * store in lseg. |
626 | 607 | */ |
627 | - nfs4_proc_layoutget(lgp); | |
608 | + nfs4_proc_layoutget(lgp, gfp_flags); | |
628 | 609 | if (!lseg) { |
629 | 610 | /* remember that LAYOUTGET failed and suspend trying */ |
630 | 611 | set_bit(lo_fail_bit(range->iomode), &lo->plh_flags); |
631 | 612 | } |
632 | 613 | |
633 | - /* free xdr pages */ | |
634 | - for (i = 0; i < max_pages; i++) | |
635 | - __free_page(pages[i]); | |
636 | - kfree(pages); | |
637 | - | |
638 | 614 | return lseg; |
639 | - | |
640 | -out_err_free: | |
641 | - /* free any allocated xdr pages, lgp as it's not used */ | |
642 | - if (pages) { | |
643 | - for (i = 0; i < max_pages; i++) { | |
644 | - if (!pages[i]) | |
645 | - break; | |
646 | - __free_page(pages[i]); | |
647 | - } | |
648 | - kfree(pages); | |
649 | - } | |
650 | - kfree(lgp); | |
651 | - return NULL; | |
652 | 615 | } |
653 | 616 | |
654 | 617 | /* |
fs/nfs/pnfs.h
... | ... | @@ -172,7 +172,7 @@ |
172 | 172 | struct pnfs_devicelist *devlist); |
173 | 173 | extern int nfs4_proc_getdeviceinfo(struct nfs_server *server, |
174 | 174 | struct pnfs_device *dev); |
175 | -extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp); | |
175 | +extern void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags); | |
176 | 176 | extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp); |
177 | 177 | |
178 | 178 | /* pnfs.c */ |
fs/nfs/super.c
... | ... | @@ -319,6 +319,34 @@ |
319 | 319 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *); |
320 | 320 | static int nfs4_validate_mount_data(void *options, |
321 | 321 | struct nfs_parsed_mount_data *args, const char *dev_name); |
322 | + | |
323 | +struct file_system_type nfs4_fs_type = { | |
324 | + .owner = THIS_MODULE, | |
325 | + .name = "nfs4", | |
326 | + .mount = nfs_fs_mount, | |
327 | + .kill_sb = nfs_kill_super, | |
328 | + .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | |
329 | +}; | |
330 | +EXPORT_SYMBOL_GPL(nfs4_fs_type); | |
331 | + | |
332 | +static int __init register_nfs4_fs(void) | |
333 | +{ | |
334 | + return register_filesystem(&nfs4_fs_type); | |
335 | +} | |
336 | + | |
337 | +static void unregister_nfs4_fs(void) | |
338 | +{ | |
339 | + unregister_filesystem(&nfs4_fs_type); | |
340 | +} | |
341 | +#else | |
342 | +static int __init register_nfs4_fs(void) | |
343 | +{ | |
344 | + return 0; | |
345 | +} | |
346 | + | |
347 | +static void unregister_nfs4_fs(void) | |
348 | +{ | |
349 | +} | |
322 | 350 | #endif |
323 | 351 | |
324 | 352 | static struct shrinker acl_shrinker = { |
325 | 353 | |
326 | 354 | |
... | ... | @@ -337,12 +365,18 @@ |
337 | 365 | if (ret < 0) |
338 | 366 | goto error_0; |
339 | 367 | |
340 | - ret = nfs_register_sysctl(); | |
368 | + ret = register_nfs4_fs(); | |
341 | 369 | if (ret < 0) |
342 | 370 | goto error_1; |
371 | + | |
372 | + ret = nfs_register_sysctl(); | |
373 | + if (ret < 0) | |
374 | + goto error_2; | |
343 | 375 | register_shrinker(&acl_shrinker); |
344 | 376 | return 0; |
345 | 377 | |
378 | +error_2: | |
379 | + unregister_nfs4_fs(); | |
346 | 380 | error_1: |
347 | 381 | unregister_filesystem(&nfs_fs_type); |
348 | 382 | error_0: |
... | ... | @@ -356,6 +390,7 @@ |
356 | 390 | { |
357 | 391 | unregister_shrinker(&acl_shrinker); |
358 | 392 | nfs_unregister_sysctl(); |
393 | + unregister_nfs4_fs(); | |
359 | 394 | unregister_filesystem(&nfs_fs_type); |
360 | 395 | } |
361 | 396 | |
... | ... | @@ -2645,5 +2680,7 @@ |
2645 | 2680 | module_param(send_implementation_id, ushort, 0644); |
2646 | 2681 | MODULE_PARM_DESC(send_implementation_id, |
2647 | 2682 | "Send implementation ID with NFSv4.1 exchange_id"); |
2683 | +MODULE_ALIAS("nfs4"); | |
2684 | + | |
2648 | 2685 | #endif /* CONFIG_NFS_V4 */ |
fs/nfs/write.c
... | ... | @@ -1814,19 +1814,19 @@ |
1814 | 1814 | nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE, |
1815 | 1815 | nfs_wdata_cachep); |
1816 | 1816 | if (nfs_wdata_mempool == NULL) |
1817 | - return -ENOMEM; | |
1817 | + goto out_destroy_write_cache; | |
1818 | 1818 | |
1819 | 1819 | nfs_cdata_cachep = kmem_cache_create("nfs_commit_data", |
1820 | 1820 | sizeof(struct nfs_commit_data), |
1821 | 1821 | 0, SLAB_HWCACHE_ALIGN, |
1822 | 1822 | NULL); |
1823 | 1823 | if (nfs_cdata_cachep == NULL) |
1824 | - return -ENOMEM; | |
1824 | + goto out_destroy_write_mempool; | |
1825 | 1825 | |
1826 | 1826 | nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT, |
1827 | 1827 | nfs_wdata_cachep); |
1828 | 1828 | if (nfs_commit_mempool == NULL) |
1829 | - return -ENOMEM; | |
1829 | + goto out_destroy_commit_cache; | |
1830 | 1830 | |
1831 | 1831 | /* |
1832 | 1832 | * NFS congestion size, scale with available memory. |
1833 | 1833 | |
... | ... | @@ -1849,11 +1849,20 @@ |
1849 | 1849 | nfs_congestion_kb = 256*1024; |
1850 | 1850 | |
1851 | 1851 | return 0; |
1852 | + | |
1853 | +out_destroy_commit_cache: | |
1854 | + kmem_cache_destroy(nfs_cdata_cachep); | |
1855 | +out_destroy_write_mempool: | |
1856 | + mempool_destroy(nfs_wdata_mempool); | |
1857 | +out_destroy_write_cache: | |
1858 | + kmem_cache_destroy(nfs_wdata_cachep); | |
1859 | + return -ENOMEM; | |
1852 | 1860 | } |
1853 | 1861 | |
1854 | 1862 | void nfs_destroy_writepagecache(void) |
1855 | 1863 | { |
1856 | 1864 | mempool_destroy(nfs_commit_mempool); |
1865 | + kmem_cache_destroy(nfs_cdata_cachep); | |
1857 | 1866 | mempool_destroy(nfs_wdata_mempool); |
1858 | 1867 | kmem_cache_destroy(nfs_wdata_cachep); |
1859 | 1868 | } |
include/linux/nfs_page.h
include/linux/nfs_xdr.h
... | ... | @@ -1248,6 +1248,7 @@ |
1248 | 1248 | void (*release) (struct nfs_pgio_header *hdr); |
1249 | 1249 | const struct nfs_pgio_completion_ops *completion_ops; |
1250 | 1250 | struct nfs_direct_req *dreq; |
1251 | + void *layout_private; | |
1251 | 1252 | spinlock_t lock; |
1252 | 1253 | /* fields protected by lock */ |
1253 | 1254 | int pnfs_error; |