diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-22 12:57:25 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-22 12:57:25 -0400 |
| commit | ad746be96941ddd2fb31fad7a629de7912051c8d (patch) | |
| tree | c94cc4d13d7595973c72e95dc093ef5404cb3b43 | |
| parent | 467e9e51d07d43d32a1dd8b6ead2351e28fff084 (diff) | |
| parent | 086600430493e04b802bee6e5b3ce0458e4eb77f (diff) | |
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
| -rw-r--r-- | fs/nfs/Makefile | 18 | ||||
| -rw-r--r-- | fs/nfs/client.c | 2 | ||||
| -rw-r--r-- | fs/nfs/idmap.c | 62 | ||||
| -rw-r--r-- | fs/nfs/nfs3proc.c | 2 | ||||
| -rw-r--r-- | fs/nfs/nfs4_fs.h | 3 | ||||
| -rw-r--r-- | fs/nfs/nfs4client.c | 2 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 76 | ||||
| -rw-r--r-- | fs/nfs/nfs4super.c | 15 | ||||
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 26 | ||||
| -rw-r--r-- | fs/nfs/objlayout/objio_osd.c | 55 | ||||
| -rw-r--r-- | fs/nfs/pagelist.c | 2 | ||||
| -rw-r--r-- | fs/nfs/pnfs.c | 39 | ||||
| -rw-r--r-- | fs/nfs/pnfs.h | 2 | ||||
| -rw-r--r-- | fs/nfs/super.c | 39 | ||||
| -rw-r--r-- | fs/nfs/write.c | 15 | ||||
| -rw-r--r-- | include/linux/nfs_page.h | 1 | ||||
| -rw-r--r-- | include/linux/nfs_xdr.h | 1 |
17 files changed, 241 insertions, 119 deletions
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index 8bf3a3f6925a..b7db60897f91 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
| @@ -12,19 +12,19 @@ nfs-$(CONFIG_ROOT_NFS) += nfsroot.o | |||
| 12 | nfs-$(CONFIG_SYSCTL) += sysctl.o | 12 | nfs-$(CONFIG_SYSCTL) += sysctl.o |
| 13 | nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o | 13 | nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o |
| 14 | 14 | ||
| 15 | obj-$(CONFIG_NFS_V2) += nfs2.o | 15 | obj-$(CONFIG_NFS_V2) += nfsv2.o |
| 16 | nfs2-y := nfs2super.o proc.o nfs2xdr.o | 16 | nfsv2-y := nfs2super.o proc.o nfs2xdr.o |
| 17 | 17 | ||
| 18 | obj-$(CONFIG_NFS_V3) += nfs3.o | 18 | obj-$(CONFIG_NFS_V3) += nfsv3.o |
| 19 | nfs3-y := nfs3super.o nfs3client.o nfs3proc.o nfs3xdr.o | 19 | nfsv3-y := nfs3super.o nfs3client.o nfs3proc.o nfs3xdr.o |
| 20 | nfs3-$(CONFIG_NFS_V3_ACL) += nfs3acl.o | 20 | nfsv3-$(CONFIG_NFS_V3_ACL) += nfs3acl.o |
| 21 | 21 | ||
| 22 | obj-$(CONFIG_NFS_V4) += nfs4.o | 22 | obj-$(CONFIG_NFS_V4) += nfsv4.o |
| 23 | nfs4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o \ | 23 | nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o \ |
| 24 | delegation.o idmap.o callback.o callback_xdr.o callback_proc.o \ | 24 | delegation.o idmap.o callback.o callback_xdr.o callback_proc.o \ |
| 25 | nfs4namespace.o nfs4getroot.o nfs4client.o | 25 | nfs4namespace.o nfs4getroot.o nfs4client.o |
| 26 | nfs4-$(CONFIG_SYSCTL) += nfs4sysctl.o | 26 | nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o |
| 27 | nfs4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o | 27 | nfsv4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o |
| 28 | 28 | ||
| 29 | obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o | 29 | obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o |
| 30 | nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o | 30 | nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 9fc0d9dfc91b..99694442b93f 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -105,7 +105,7 @@ struct nfs_subversion *get_nfs_version(unsigned int version) | |||
| 105 | 105 | ||
| 106 | if (IS_ERR(nfs)) { | 106 | if (IS_ERR(nfs)) { |
| 107 | mutex_lock(&nfs_version_mutex); | 107 | mutex_lock(&nfs_version_mutex); |
| 108 | request_module("nfs%d", version); | 108 | request_module("nfsv%d", version); |
| 109 | nfs = find_nfs_version(version); | 109 | nfs = find_nfs_version(version); |
| 110 | mutex_unlock(&nfs_version_mutex); | 110 | mutex_unlock(&nfs_version_mutex); |
| 111 | } | 111 | } |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index b701358c39c3..a850079467d8 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
| @@ -61,6 +61,12 @@ struct idmap { | |||
| 61 | struct mutex idmap_mutex; | 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 | * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields | 71 | * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields |
| 66 | * @fattr: fully initialised struct nfs_fattr | 72 | * @fattr: fully initialised struct nfs_fattr |
| @@ -324,6 +330,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, | |||
| 324 | ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, | 330 | ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, |
| 325 | name, namelen, type, data, | 331 | name, namelen, type, data, |
| 326 | data_size, idmap); | 332 | data_size, idmap); |
| 333 | idmap->idmap_key_cons = NULL; | ||
| 327 | mutex_unlock(&idmap->idmap_mutex); | 334 | mutex_unlock(&idmap->idmap_mutex); |
| 328 | } | 335 | } |
| 329 | return ret; | 336 | return ret; |
| @@ -380,11 +387,13 @@ static const match_table_t nfs_idmap_tokens = { | |||
| 380 | static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *); | 387 | static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *); |
| 381 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, | 388 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, |
| 382 | size_t); | 389 | size_t); |
| 390 | static void idmap_release_pipe(struct inode *); | ||
| 383 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); | 391 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); |
| 384 | 392 | ||
| 385 | static const struct rpc_pipe_ops idmap_upcall_ops = { | 393 | static const struct rpc_pipe_ops idmap_upcall_ops = { |
| 386 | .upcall = rpc_pipe_generic_upcall, | 394 | .upcall = rpc_pipe_generic_upcall, |
| 387 | .downcall = idmap_pipe_downcall, | 395 | .downcall = idmap_pipe_downcall, |
| 396 | .release_pipe = idmap_release_pipe, | ||
| 388 | .destroy_msg = idmap_pipe_destroy_msg, | 397 | .destroy_msg = idmap_pipe_destroy_msg, |
| 389 | }; | 398 | }; |
| 390 | 399 | ||
| @@ -616,7 +625,8 @@ void nfs_idmap_quit(void) | |||
| 616 | nfs_idmap_quit_keyring(); | 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 | struct rpc_pipe_msg *msg) | 630 | struct rpc_pipe_msg *msg) |
| 621 | { | 631 | { |
| 622 | substring_t substr; | 632 | substring_t substr; |
| @@ -659,6 +669,7 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, | |||
| 659 | const char *op, | 669 | const char *op, |
| 660 | void *aux) | 670 | void *aux) |
| 661 | { | 671 | { |
| 672 | struct idmap_legacy_upcalldata *data; | ||
| 662 | struct rpc_pipe_msg *msg; | 673 | struct rpc_pipe_msg *msg; |
| 663 | struct idmap_msg *im; | 674 | struct idmap_msg *im; |
| 664 | struct idmap *idmap = (struct idmap *)aux; | 675 | struct idmap *idmap = (struct idmap *)aux; |
| @@ -666,15 +677,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, | |||
| 666 | int ret = -ENOMEM; | 677 | int ret = -ENOMEM; |
| 667 | 678 | ||
| 668 | /* msg and im are freed in idmap_pipe_destroy_msg */ | 679 | /* msg and im are freed in idmap_pipe_destroy_msg */ |
| 669 | msg = kmalloc(sizeof(*msg), GFP_KERNEL); | 680 | data = kmalloc(sizeof(*data), GFP_KERNEL); |
| 670 | if (!msg) | 681 | if (!data) |
| 671 | goto out0; | ||
| 672 | |||
| 673 | im = kmalloc(sizeof(*im), GFP_KERNEL); | ||
| 674 | if (!im) | ||
| 675 | goto out1; | 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 | if (ret < 0) | 689 | if (ret < 0) |
| 679 | goto out2; | 690 | goto out2; |
| 680 | 691 | ||
| @@ -683,15 +694,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, | |||
| 683 | 694 | ||
| 684 | ret = rpc_queue_upcall(idmap->idmap_pipe, msg); | 695 | ret = rpc_queue_upcall(idmap->idmap_pipe, msg); |
| 685 | if (ret < 0) | 696 | if (ret < 0) |
| 686 | goto out2; | 697 | goto out3; |
| 687 | 698 | ||
| 688 | return ret; | 699 | return ret; |
| 689 | 700 | ||
| 701 | out3: | ||
| 702 | idmap->idmap_key_cons = NULL; | ||
| 690 | out2: | 703 | out2: |
| 691 | kfree(im); | 704 | kfree(data); |
| 692 | out1: | 705 | out1: |
| 693 | kfree(msg); | ||
| 694 | out0: | ||
| 695 | complete_request_key(cons, ret); | 706 | complete_request_key(cons, ret); |
| 696 | return ret; | 707 | return ret; |
| 697 | } | 708 | } |
| @@ -749,9 +760,8 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
| 749 | } | 760 | } |
| 750 | 761 | ||
| 751 | if (!(im.im_status & IDMAP_STATUS_SUCCESS)) { | 762 | if (!(im.im_status & IDMAP_STATUS_SUCCESS)) { |
| 752 | ret = mlen; | 763 | ret = -ENOKEY; |
| 753 | complete_request_key(cons, -ENOKEY); | 764 | goto out; |
| 754 | goto out_incomplete; | ||
| 755 | } | 765 | } |
| 756 | 766 | ||
| 757 | namelen_in = strnlen(im.im_name, IDMAP_NAMESZ); | 767 | 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) | |||
| 768 | 778 | ||
| 769 | out: | 779 | out: |
| 770 | complete_request_key(cons, ret); | 780 | complete_request_key(cons, ret); |
| 771 | out_incomplete: | ||
| 772 | return ret; | 781 | return ret; |
| 773 | } | 782 | } |
| 774 | 783 | ||
| 775 | static void | 784 | static void |
| 776 | idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) | 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 | /* Free memory allocated in nfs_idmap_legacy_upcall() */ | 797 | /* Free memory allocated in nfs_idmap_legacy_upcall() */ |
| 779 | kfree(msg->data); | 798 | kfree(data); |
| 780 | kfree(msg); | 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 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) | 809 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 0952c791df36..d6b3b5f2d779 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
| @@ -69,7 +69,7 @@ do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle, | |||
| 69 | nfs_fattr_init(info->fattr); | 69 | nfs_fattr_init(info->fattr); |
| 70 | status = rpc_call_sync(client, &msg, 0); | 70 | status = rpc_call_sync(client, &msg, 0); |
| 71 | dprintk("%s: reply fsinfo: %d\n", __func__, status); | 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 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; | 73 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; |
| 74 | msg.rpc_resp = info->fattr; | 74 | msg.rpc_resp = info->fattr; |
| 75 | status = rpc_call_sync(client, &msg, 0); | 75 | status = rpc_call_sync(client, &msg, 0); |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 3b950dd81e81..da0618aeeadb 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
| @@ -205,6 +205,9 @@ extern const struct dentry_operations nfs4_dentry_operations; | |||
| 205 | int nfs_atomic_open(struct inode *, struct dentry *, struct file *, | 205 | int nfs_atomic_open(struct inode *, struct dentry *, struct file *, |
| 206 | unsigned, umode_t, int *); | 206 | unsigned, umode_t, int *); |
| 207 | 207 | ||
| 208 | /* super.c */ | ||
| 209 | extern struct file_system_type nfs4_fs_type; | ||
| 210 | |||
| 208 | /* nfs4namespace.c */ | 211 | /* nfs4namespace.c */ |
| 209 | rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *); | 212 | rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *); |
| 210 | struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *); | 213 | struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *); |
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index cbcdfaf32505..24eb663f8ed5 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
| @@ -74,7 +74,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init) | |||
| 74 | return clp; | 74 | return clp; |
| 75 | 75 | ||
| 76 | error: | 76 | error: |
| 77 | kfree(clp); | 77 | nfs_free_client(clp); |
| 78 | return ERR_PTR(err); | 78 | return ERR_PTR(err); |
| 79 | } | 79 | } |
| 80 | 80 | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a99a8d948721..635274140b18 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -3737,9 +3737,10 @@ out: | |||
| 3737 | static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len) | 3737 | static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len) |
| 3738 | { | 3738 | { |
| 3739 | struct nfs4_cached_acl *acl; | 3739 | struct nfs4_cached_acl *acl; |
| 3740 | size_t buflen = sizeof(*acl) + acl_len; | ||
| 3740 | 3741 | ||
| 3741 | if (pages && acl_len <= PAGE_SIZE) { | 3742 | if (pages && buflen <= PAGE_SIZE) { |
| 3742 | acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL); | 3743 | acl = kmalloc(buflen, GFP_KERNEL); |
| 3743 | if (acl == NULL) | 3744 | if (acl == NULL) |
| 3744 | goto out; | 3745 | goto out; |
| 3745 | acl->cached = 1; | 3746 | acl->cached = 1; |
| @@ -3819,7 +3820,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
| 3819 | if (ret) | 3820 | if (ret) |
| 3820 | goto out_free; | 3821 | goto out_free; |
| 3821 | 3822 | ||
| 3822 | acl_len = res.acl_len - res.acl_data_offset; | 3823 | acl_len = res.acl_len; |
| 3823 | if (acl_len > args.acl_len) | 3824 | if (acl_len > args.acl_len) |
| 3824 | nfs4_write_cached_acl(inode, NULL, 0, acl_len); | 3825 | nfs4_write_cached_acl(inode, NULL, 0, acl_len); |
| 3825 | else | 3826 | else |
| @@ -6223,11 +6224,58 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) | |||
| 6223 | dprintk("<-- %s\n", __func__); | 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 | static void nfs4_layoutget_release(void *calldata) | 6271 | static void nfs4_layoutget_release(void *calldata) |
| 6227 | { | 6272 | { |
| 6228 | struct nfs4_layoutget *lgp = calldata; | 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 | dprintk("--> %s\n", __func__); | 6277 | dprintk("--> %s\n", __func__); |
| 6278 | nfs4_free_pages(lgp->args.layout.pages, max_pages); | ||
| 6231 | put_nfs_open_context(lgp->args.ctx); | 6279 | put_nfs_open_context(lgp->args.ctx); |
| 6232 | kfree(calldata); | 6280 | kfree(calldata); |
| 6233 | dprintk("<-- %s\n", __func__); | 6281 | dprintk("<-- %s\n", __func__); |
| @@ -6239,9 +6287,10 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = { | |||
| 6239 | .rpc_release = nfs4_layoutget_release, | 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 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); | 6292 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); |
| 6293 | size_t max_pages = max_response_pages(server); | ||
| 6245 | struct rpc_task *task; | 6294 | struct rpc_task *task; |
| 6246 | struct rpc_message msg = { | 6295 | struct rpc_message msg = { |
| 6247 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET], | 6296 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET], |
| @@ -6259,12 +6308,19 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) | |||
| 6259 | 6308 | ||
| 6260 | dprintk("--> %s\n", __func__); | 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 | lgp->res.layoutp = &lgp->args.layout; | 6318 | lgp->res.layoutp = &lgp->args.layout; |
| 6263 | lgp->res.seq_res.sr_slot = NULL; | 6319 | lgp->res.seq_res.sr_slot = NULL; |
| 6264 | nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); | 6320 | nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); |
| 6265 | task = rpc_run_task(&task_setup_data); | 6321 | task = rpc_run_task(&task_setup_data); |
| 6266 | if (IS_ERR(task)) | 6322 | if (IS_ERR(task)) |
| 6267 | return PTR_ERR(task); | 6323 | return; |
| 6268 | status = nfs4_wait_for_completion_rpc_task(task); | 6324 | status = nfs4_wait_for_completion_rpc_task(task); |
| 6269 | if (status == 0) | 6325 | if (status == 0) |
| 6270 | status = task->tk_status; | 6326 | status = task->tk_status; |
| @@ -6272,7 +6328,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) | |||
| 6272 | status = pnfs_layout_process(lgp); | 6328 | status = pnfs_layout_process(lgp); |
| 6273 | rpc_put_task(task); | 6329 | rpc_put_task(task); |
| 6274 | dprintk("<-- %s status=%d\n", __func__, status); | 6330 | dprintk("<-- %s status=%d\n", __func__, status); |
| 6275 | return status; | 6331 | return; |
| 6276 | } | 6332 | } |
| 6277 | 6333 | ||
| 6278 | static void | 6334 | static void |
| @@ -6304,12 +6360,8 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) | |||
| 6304 | return; | 6360 | return; |
| 6305 | } | 6361 | } |
| 6306 | spin_lock(&lo->plh_inode->i_lock); | 6362 | spin_lock(&lo->plh_inode->i_lock); |
| 6307 | if (task->tk_status == 0) { | 6363 | if (task->tk_status == 0 && lrp->res.lrs_present) |
| 6308 | if (lrp->res.lrs_present) { | 6364 | pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); |
| 6309 | pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); | ||
| 6310 | } else | ||
| 6311 | BUG_ON(!list_empty(&lo->plh_segs)); | ||
| 6312 | } | ||
| 6313 | lo->plh_block_lgets--; | 6365 | lo->plh_block_lgets--; |
| 6314 | spin_unlock(&lo->plh_inode->i_lock); | 6366 | spin_unlock(&lo->plh_inode->i_lock); |
| 6315 | dprintk("<-- %s\n", __func__); | 6367 | dprintk("<-- %s\n", __func__); |
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index 12a31a9dbcdd..bd61221ad2c5 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c | |||
| @@ -23,14 +23,6 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | |||
| 23 | static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, | 23 | static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, |
| 24 | int flags, const char *dev_name, void *raw_data); | 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 | static struct file_system_type nfs4_remote_fs_type = { | 26 | static struct file_system_type nfs4_remote_fs_type = { |
| 35 | .owner = THIS_MODULE, | 27 | .owner = THIS_MODULE, |
| 36 | .name = "nfs4", | 28 | .name = "nfs4", |
| @@ -344,14 +336,8 @@ static int __init init_nfs_v4(void) | |||
| 344 | if (err) | 336 | if (err) |
| 345 | goto out1; | 337 | goto out1; |
| 346 | 338 | ||
| 347 | err = register_filesystem(&nfs4_fs_type); | ||
| 348 | if (err < 0) | ||
| 349 | goto out2; | ||
| 350 | |||
| 351 | register_nfs_version(&nfs_v4); | 339 | register_nfs_version(&nfs_v4); |
| 352 | return 0; | 340 | return 0; |
| 353 | out2: | ||
| 354 | nfs4_unregister_sysctl(); | ||
| 355 | out1: | 341 | out1: |
| 356 | nfs_idmap_quit(); | 342 | nfs_idmap_quit(); |
| 357 | out: | 343 | out: |
| @@ -361,7 +347,6 @@ out: | |||
| 361 | static void __exit exit_nfs_v4(void) | 347 | static void __exit exit_nfs_v4(void) |
| 362 | { | 348 | { |
| 363 | unregister_nfs_version(&nfs_v4); | 349 | unregister_nfs_version(&nfs_v4); |
| 364 | unregister_filesystem(&nfs4_fs_type); | ||
| 365 | nfs4_unregister_sysctl(); | 350 | nfs4_unregister_sysctl(); |
| 366 | nfs_idmap_quit(); | 351 | nfs_idmap_quit(); |
| 367 | } | 352 | } |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index ca13483edd60..1bfbd67c556d 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -5045,22 +5045,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
| 5045 | struct nfs_getaclres *res) | 5045 | struct nfs_getaclres *res) |
| 5046 | { | 5046 | { |
| 5047 | unsigned int savep; | 5047 | unsigned int savep; |
| 5048 | __be32 *bm_p; | ||
| 5049 | uint32_t attrlen, | 5048 | uint32_t attrlen, |
| 5050 | bitmap[3] = {0}; | 5049 | bitmap[3] = {0}; |
| 5051 | int status; | 5050 | int status; |
| 5052 | size_t page_len = xdr->buf->page_len; | 5051 | unsigned int pg_offset; |
| 5053 | 5052 | ||
| 5054 | res->acl_len = 0; | 5053 | res->acl_len = 0; |
| 5055 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) | 5054 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) |
| 5056 | goto out; | 5055 | goto out; |
| 5057 | 5056 | ||
| 5058 | bm_p = xdr->p; | 5057 | xdr_enter_page(xdr, xdr->buf->page_len); |
| 5059 | res->acl_data_offset = be32_to_cpup(bm_p) + 2; | 5058 | |
| 5060 | res->acl_data_offset <<= 2; | 5059 | /* Calculate the offset of the page data */ |
| 5061 | /* Check if the acl data starts beyond the allocated buffer */ | 5060 | pg_offset = xdr->buf->head[0].iov_len; |
| 5062 | if (res->acl_data_offset > page_len) | ||
| 5063 | return -ERANGE; | ||
| 5064 | 5061 | ||
| 5065 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) | 5062 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) |
| 5066 | goto out; | 5063 | goto out; |
| @@ -5074,23 +5071,20 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
| 5074 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words | 5071 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words |
| 5075 | * are stored with the acl data to handle the problem of | 5072 | * are stored with the acl data to handle the problem of |
| 5076 | * variable length bitmaps.*/ | 5073 | * variable length bitmaps.*/ |
| 5077 | xdr->p = bm_p; | 5074 | res->acl_data_offset = xdr_stream_pos(xdr) - pg_offset; |
| 5078 | 5075 | ||
| 5079 | /* We ignore &savep and don't do consistency checks on | 5076 | /* We ignore &savep and don't do consistency checks on |
| 5080 | * the attr length. Let userspace figure it out.... */ | 5077 | * the attr length. Let userspace figure it out.... */ |
| 5081 | attrlen += res->acl_data_offset; | 5078 | res->acl_len = attrlen; |
| 5082 | if (attrlen > page_len) { | 5079 | if (attrlen > (xdr->nwords << 2)) { |
| 5083 | if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { | 5080 | if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { |
| 5084 | /* getxattr interface called with a NULL buf */ | 5081 | /* getxattr interface called with a NULL buf */ |
| 5085 | res->acl_len = attrlen; | ||
| 5086 | goto out; | 5082 | goto out; |
| 5087 | } | 5083 | } |
| 5088 | dprintk("NFS: acl reply: attrlen %u > page_len %zu\n", | 5084 | dprintk("NFS: acl reply: attrlen %u > page_len %u\n", |
| 5089 | attrlen, page_len); | 5085 | attrlen, xdr->nwords << 2); |
| 5090 | return -EINVAL; | 5086 | return -EINVAL; |
| 5091 | } | 5087 | } |
| 5092 | xdr_read_pages(xdr, attrlen); | ||
| 5093 | res->acl_len = attrlen; | ||
| 5094 | } else | 5088 | } else |
| 5095 | status = -EOPNOTSUPP; | 5089 | status = -EOPNOTSUPP; |
| 5096 | 5090 | ||
diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c index f50d3e8d6f22..ea6d111b03e9 100644 --- a/fs/nfs/objlayout/objio_osd.c +++ b/fs/nfs/objlayout/objio_osd.c | |||
| @@ -570,17 +570,66 @@ static bool objio_pg_test(struct nfs_pageio_descriptor *pgio, | |||
| 570 | return false; | 570 | return false; |
| 571 | 571 | ||
| 572 | return pgio->pg_count + req->wb_bytes <= | 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 | } | ||
| 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 | } | ||
| 574 | } | 623 | } |
| 575 | 624 | ||
| 576 | static const struct nfs_pageio_ops objio_pg_read_ops = { | 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 | .pg_test = objio_pg_test, | 627 | .pg_test = objio_pg_test, |
| 579 | .pg_doio = pnfs_generic_pg_readpages, | 628 | .pg_doio = pnfs_generic_pg_readpages, |
| 580 | }; | 629 | }; |
| 581 | 630 | ||
| 582 | static const struct nfs_pageio_ops objio_pg_write_ops = { | 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 | .pg_test = objio_pg_test, | 633 | .pg_test = objio_pg_test, |
| 585 | .pg_doio = pnfs_generic_pg_writepages, | 634 | .pg_doio = pnfs_generic_pg_writepages, |
| 586 | }; | 635 | }; |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 1a6732ed04a4..311a79681e2b 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
| @@ -49,6 +49,7 @@ void nfs_pgheader_init(struct nfs_pageio_descriptor *desc, | |||
| 49 | hdr->io_start = req_offset(hdr->req); | 49 | hdr->io_start = req_offset(hdr->req); |
| 50 | hdr->good_bytes = desc->pg_count; | 50 | hdr->good_bytes = desc->pg_count; |
| 51 | hdr->dreq = desc->pg_dreq; | 51 | hdr->dreq = desc->pg_dreq; |
| 52 | hdr->layout_private = desc->pg_layout_private; | ||
| 52 | hdr->release = release; | 53 | hdr->release = release; |
| 53 | hdr->completion_ops = desc->pg_completion_ops; | 54 | hdr->completion_ops = desc->pg_completion_ops; |
| 54 | if (hdr->completion_ops->init_hdr) | 55 | if (hdr->completion_ops->init_hdr) |
| @@ -268,6 +269,7 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc, | |||
| 268 | desc->pg_error = 0; | 269 | desc->pg_error = 0; |
| 269 | desc->pg_lseg = NULL; | 270 | desc->pg_lseg = NULL; |
| 270 | desc->pg_dreq = NULL; | 271 | desc->pg_dreq = NULL; |
| 272 | desc->pg_layout_private = NULL; | ||
| 271 | } | 273 | } |
| 272 | EXPORT_SYMBOL_GPL(nfs_pageio_init); | 274 | EXPORT_SYMBOL_GPL(nfs_pageio_init); |
| 273 | 275 | ||
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 76875bfcf19c..2e00feacd4be 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
| @@ -583,9 +583,6 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
| 583 | struct nfs_server *server = NFS_SERVER(ino); | 583 | struct nfs_server *server = NFS_SERVER(ino); |
| 584 | struct nfs4_layoutget *lgp; | 584 | struct nfs4_layoutget *lgp; |
| 585 | struct pnfs_layout_segment *lseg = NULL; | 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 | dprintk("--> %s\n", __func__); | 587 | dprintk("--> %s\n", __func__); |
| 591 | 588 | ||
| @@ -594,20 +591,6 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
| 594 | if (lgp == NULL) | 591 | if (lgp == NULL) |
| 595 | return NULL; | 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 | lgp->args.minlength = PAGE_CACHE_SIZE; | 594 | lgp->args.minlength = PAGE_CACHE_SIZE; |
| 612 | if (lgp->args.minlength > range->length) | 595 | if (lgp->args.minlength > range->length) |
| 613 | lgp->args.minlength = range->length; | 596 | lgp->args.minlength = range->length; |
| @@ -616,39 +599,19 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
| 616 | lgp->args.type = server->pnfs_curr_ld->id; | 599 | lgp->args.type = server->pnfs_curr_ld->id; |
| 617 | lgp->args.inode = ino; | 600 | lgp->args.inode = ino; |
| 618 | lgp->args.ctx = get_nfs_open_context(ctx); | 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 | lgp->lsegpp = &lseg; | 602 | lgp->lsegpp = &lseg; |
| 622 | lgp->gfp_flags = gfp_flags; | 603 | lgp->gfp_flags = gfp_flags; |
| 623 | 604 | ||
| 624 | /* Synchronously retrieve layout information from server and | 605 | /* Synchronously retrieve layout information from server and |
| 625 | * store in lseg. | 606 | * store in lseg. |
| 626 | */ | 607 | */ |
| 627 | nfs4_proc_layoutget(lgp); | 608 | nfs4_proc_layoutget(lgp, gfp_flags); |
| 628 | if (!lseg) { | 609 | if (!lseg) { |
| 629 | /* remember that LAYOUTGET failed and suspend trying */ | 610 | /* remember that LAYOUTGET failed and suspend trying */ |
| 630 | set_bit(lo_fail_bit(range->iomode), &lo->plh_flags); | 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 | return lseg; | 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 | /* |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 2c6c80503ba4..745aa1b39e7c 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
| @@ -172,7 +172,7 @@ extern int nfs4_proc_getdevicelist(struct nfs_server *server, | |||
| 172 | struct pnfs_devicelist *devlist); | 172 | struct pnfs_devicelist *devlist); |
| 173 | extern int nfs4_proc_getdeviceinfo(struct nfs_server *server, | 173 | extern int nfs4_proc_getdeviceinfo(struct nfs_server *server, |
| 174 | struct pnfs_device *dev); | 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 | extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp); | 176 | extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp); |
| 177 | 177 | ||
| 178 | /* pnfs.c */ | 178 | /* pnfs.c */ |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index ac6a3c55dce4..239aff7338eb 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -319,6 +319,34 @@ EXPORT_SYMBOL_GPL(nfs_sops); | |||
| 319 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *); | 319 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *); |
| 320 | static int nfs4_validate_mount_data(void *options, | 320 | static int nfs4_validate_mount_data(void *options, |
| 321 | struct nfs_parsed_mount_data *args, const char *dev_name); | 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 | #endif | 350 | #endif |
| 323 | 351 | ||
| 324 | static struct shrinker acl_shrinker = { | 352 | static struct shrinker acl_shrinker = { |
| @@ -337,12 +365,18 @@ int __init register_nfs_fs(void) | |||
| 337 | if (ret < 0) | 365 | if (ret < 0) |
| 338 | goto error_0; | 366 | goto error_0; |
| 339 | 367 | ||
| 340 | ret = nfs_register_sysctl(); | 368 | ret = register_nfs4_fs(); |
| 341 | if (ret < 0) | 369 | if (ret < 0) |
| 342 | goto error_1; | 370 | goto error_1; |
| 371 | |||
| 372 | ret = nfs_register_sysctl(); | ||
| 373 | if (ret < 0) | ||
| 374 | goto error_2; | ||
| 343 | register_shrinker(&acl_shrinker); | 375 | register_shrinker(&acl_shrinker); |
| 344 | return 0; | 376 | return 0; |
| 345 | 377 | ||
| 378 | error_2: | ||
| 379 | unregister_nfs4_fs(); | ||
| 346 | error_1: | 380 | error_1: |
| 347 | unregister_filesystem(&nfs_fs_type); | 381 | unregister_filesystem(&nfs_fs_type); |
| 348 | error_0: | 382 | error_0: |
| @@ -356,6 +390,7 @@ void __exit unregister_nfs_fs(void) | |||
| 356 | { | 390 | { |
| 357 | unregister_shrinker(&acl_shrinker); | 391 | unregister_shrinker(&acl_shrinker); |
| 358 | nfs_unregister_sysctl(); | 392 | nfs_unregister_sysctl(); |
| 393 | unregister_nfs4_fs(); | ||
| 359 | unregister_filesystem(&nfs_fs_type); | 394 | unregister_filesystem(&nfs_fs_type); |
| 360 | } | 395 | } |
| 361 | 396 | ||
| @@ -2645,4 +2680,6 @@ MODULE_PARM_DESC(max_session_slots, "Maximum number of outstanding NFSv4.1 " | |||
| 2645 | module_param(send_implementation_id, ushort, 0644); | 2680 | module_param(send_implementation_id, ushort, 0644); |
| 2646 | MODULE_PARM_DESC(send_implementation_id, | 2681 | MODULE_PARM_DESC(send_implementation_id, |
| 2647 | "Send implementation ID with NFSv4.1 exchange_id"); | 2682 | "Send implementation ID with NFSv4.1 exchange_id"); |
| 2683 | MODULE_ALIAS("nfs4"); | ||
| 2684 | |||
| 2648 | #endif /* CONFIG_NFS_V4 */ | 2685 | #endif /* CONFIG_NFS_V4 */ |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 5829d0ce7cfb..e3b55372726c 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -1814,19 +1814,19 @@ int __init nfs_init_writepagecache(void) | |||
| 1814 | nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE, | 1814 | nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE, |
| 1815 | nfs_wdata_cachep); | 1815 | nfs_wdata_cachep); |
| 1816 | if (nfs_wdata_mempool == NULL) | 1816 | if (nfs_wdata_mempool == NULL) |
| 1817 | return -ENOMEM; | 1817 | goto out_destroy_write_cache; |
| 1818 | 1818 | ||
| 1819 | nfs_cdata_cachep = kmem_cache_create("nfs_commit_data", | 1819 | nfs_cdata_cachep = kmem_cache_create("nfs_commit_data", |
| 1820 | sizeof(struct nfs_commit_data), | 1820 | sizeof(struct nfs_commit_data), |
| 1821 | 0, SLAB_HWCACHE_ALIGN, | 1821 | 0, SLAB_HWCACHE_ALIGN, |
| 1822 | NULL); | 1822 | NULL); |
| 1823 | if (nfs_cdata_cachep == NULL) | 1823 | if (nfs_cdata_cachep == NULL) |
| 1824 | return -ENOMEM; | 1824 | goto out_destroy_write_mempool; |
| 1825 | 1825 | ||
| 1826 | nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT, | 1826 | nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT, |
| 1827 | nfs_wdata_cachep); | 1827 | nfs_wdata_cachep); |
| 1828 | if (nfs_commit_mempool == NULL) | 1828 | if (nfs_commit_mempool == NULL) |
| 1829 | return -ENOMEM; | 1829 | goto out_destroy_commit_cache; |
| 1830 | 1830 | ||
| 1831 | /* | 1831 | /* |
| 1832 | * NFS congestion size, scale with available memory. | 1832 | * NFS congestion size, scale with available memory. |
| @@ -1849,11 +1849,20 @@ int __init nfs_init_writepagecache(void) | |||
| 1849 | nfs_congestion_kb = 256*1024; | 1849 | nfs_congestion_kb = 256*1024; |
| 1850 | 1850 | ||
| 1851 | return 0; | 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 | void nfs_destroy_writepagecache(void) | 1862 | void nfs_destroy_writepagecache(void) |
| 1855 | { | 1863 | { |
| 1856 | mempool_destroy(nfs_commit_mempool); | 1864 | mempool_destroy(nfs_commit_mempool); |
| 1865 | kmem_cache_destroy(nfs_cdata_cachep); | ||
| 1857 | mempool_destroy(nfs_wdata_mempool); | 1866 | mempool_destroy(nfs_wdata_mempool); |
| 1858 | kmem_cache_destroy(nfs_wdata_cachep); | 1867 | kmem_cache_destroy(nfs_wdata_cachep); |
| 1859 | } | 1868 | } |
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 880805774f9f..92ce5783b707 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h | |||
| @@ -69,6 +69,7 @@ struct nfs_pageio_descriptor { | |||
| 69 | const struct nfs_pgio_completion_ops *pg_completion_ops; | 69 | const struct nfs_pgio_completion_ops *pg_completion_ops; |
| 70 | struct pnfs_layout_segment *pg_lseg; | 70 | struct pnfs_layout_segment *pg_lseg; |
| 71 | struct nfs_direct_req *pg_dreq; | 71 | struct nfs_direct_req *pg_dreq; |
| 72 | void *pg_layout_private; | ||
| 72 | }; | 73 | }; |
| 73 | 74 | ||
| 74 | #define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags)) | 75 | #define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags)) |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 00485e084394..ac7c8ae254f2 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
| @@ -1248,6 +1248,7 @@ struct nfs_pgio_header { | |||
| 1248 | void (*release) (struct nfs_pgio_header *hdr); | 1248 | void (*release) (struct nfs_pgio_header *hdr); |
| 1249 | const struct nfs_pgio_completion_ops *completion_ops; | 1249 | const struct nfs_pgio_completion_ops *completion_ops; |
| 1250 | struct nfs_direct_req *dreq; | 1250 | struct nfs_direct_req *dreq; |
| 1251 | void *layout_private; | ||
| 1251 | spinlock_t lock; | 1252 | spinlock_t lock; |
| 1252 | /* fields protected by lock */ | 1253 | /* fields protected by lock */ |
| 1253 | int pnfs_error; | 1254 | int pnfs_error; |
