diff options
Diffstat (limited to 'fs/nfs')
38 files changed, 1358 insertions, 525 deletions
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index 13ca196385f5..b5e80b0af315 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
@@ -104,6 +104,15 @@ config NFS_V4_1 | |||
104 | 104 | ||
105 | If unsure, say N. | 105 | If unsure, say N. |
106 | 106 | ||
107 | config NFS_V4_2 | ||
108 | bool "NFS client support for NFSv4.2" | ||
109 | depends on NFS_V4_1 | ||
110 | help | ||
111 | This option enables support for minor version 2 of the NFSv4 protocol | ||
112 | in the kernel's NFS client. | ||
113 | |||
114 | If unsure, say N. | ||
115 | |||
107 | config PNFS_FILE_LAYOUT | 116 | config PNFS_FILE_LAYOUT |
108 | tristate | 117 | tristate |
109 | depends on NFS_V4_1 | 118 | depends on NFS_V4_1 |
@@ -131,6 +140,11 @@ config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN | |||
131 | If the NFS client is unchanged from the upstream kernel, this | 140 | If the NFS client is unchanged from the upstream kernel, this |
132 | option should be set to the default "kernel.org". | 141 | option should be set to the default "kernel.org". |
133 | 142 | ||
143 | config NFS_V4_SECURITY_LABEL | ||
144 | bool | ||
145 | depends on NFS_V4_2 && SECURITY | ||
146 | default y | ||
147 | |||
134 | config ROOT_NFS | 148 | config ROOT_NFS |
135 | bool "Root file system on NFS" | 149 | bool "Root file system on NFS" |
136 | depends on NFS_FS=y && IP_PNP | 150 | depends on NFS_FS=y && IP_PNP |
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index cce2c057bd2d..e0bb048e9576 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -6,8 +6,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o | |||
6 | 6 | ||
7 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o \ | 7 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o \ |
8 | direct.o pagelist.o read.o symlink.o unlink.o \ | 8 | direct.o pagelist.o read.o symlink.o unlink.o \ |
9 | write.o namespace.o mount_clnt.o \ | 9 | write.o namespace.o mount_clnt.o |
10 | dns_resolve.o cache_lib.o | ||
11 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o | 10 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o |
12 | nfs-$(CONFIG_SYSCTL) += sysctl.o | 11 | nfs-$(CONFIG_SYSCTL) += sysctl.o |
13 | nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o | 12 | nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o |
@@ -22,7 +21,8 @@ nfsv3-$(CONFIG_NFS_V3_ACL) += nfs3acl.o | |||
22 | obj-$(CONFIG_NFS_V4) += nfsv4.o | 21 | obj-$(CONFIG_NFS_V4) += nfsv4.o |
23 | nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o \ | 22 | 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 \ | 23 | delegation.o idmap.o callback.o callback_xdr.o callback_proc.o \ |
25 | nfs4namespace.o nfs4getroot.o nfs4client.o | 24 | nfs4namespace.o nfs4getroot.o nfs4client.o dns_resolve.o |
25 | nfsv4-$(CONFIG_NFS_USE_LEGACY_DNS) += cache_lib.o | ||
26 | nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o | 26 | nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o |
27 | nfsv4-$(CONFIG_NFS_V4_1) += nfs4session.o pnfs.o pnfs_dev.o | 27 | nfsv4-$(CONFIG_NFS_V4_1) += nfs4session.o pnfs.o pnfs_dev.o |
28 | 28 | ||
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 434b93ec0970..e242bbf72972 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
@@ -1089,9 +1089,10 @@ nfs4_blk_get_deviceinfo(struct nfs_server *server, const struct nfs_fh *fh, | |||
1089 | dev->pgbase = 0; | 1089 | dev->pgbase = 0; |
1090 | dev->pglen = PAGE_SIZE * max_pages; | 1090 | dev->pglen = PAGE_SIZE * max_pages; |
1091 | dev->mincount = 0; | 1091 | dev->mincount = 0; |
1092 | dev->maxcount = max_resp_sz - nfs41_maxgetdevinfo_overhead; | ||
1092 | 1093 | ||
1093 | dprintk("%s: dev_id: %s\n", __func__, dev->dev_id.data); | 1094 | dprintk("%s: dev_id: %s\n", __func__, dev->dev_id.data); |
1094 | rc = nfs4_proc_getdeviceinfo(server, dev); | 1095 | rc = nfs4_proc_getdeviceinfo(server, dev, NULL); |
1095 | dprintk("%s getdevice info returns %d\n", __func__, rc); | 1096 | dprintk("%s getdevice info returns %d\n", __func__, rc); |
1096 | if (rc) { | 1097 | if (rc) { |
1097 | rv = ERR_PTR(rc); | 1098 | rv = ERR_PTR(rc); |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index cff089a412c7..67cd73213168 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -211,7 +211,6 @@ static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt, | |||
211 | struct svc_rqst *rqstp; | 211 | struct svc_rqst *rqstp; |
212 | int (*callback_svc)(void *vrqstp); | 212 | int (*callback_svc)(void *vrqstp); |
213 | struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; | 213 | struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; |
214 | char svc_name[12]; | ||
215 | int ret; | 214 | int ret; |
216 | 215 | ||
217 | nfs_callback_bc_serv(minorversion, xprt, serv); | 216 | nfs_callback_bc_serv(minorversion, xprt, serv); |
@@ -235,10 +234,10 @@ static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt, | |||
235 | 234 | ||
236 | svc_sock_update_bufs(serv); | 235 | svc_sock_update_bufs(serv); |
237 | 236 | ||
238 | sprintf(svc_name, "nfsv4.%u-svc", minorversion); | ||
239 | cb_info->serv = serv; | 237 | cb_info->serv = serv; |
240 | cb_info->rqst = rqstp; | 238 | cb_info->rqst = rqstp; |
241 | cb_info->task = kthread_run(callback_svc, cb_info->rqst, svc_name); | 239 | cb_info->task = kthread_run(callback_svc, cb_info->rqst, |
240 | "nfsv4.%u-svc", minorversion); | ||
242 | if (IS_ERR(cb_info->task)) { | 241 | if (IS_ERR(cb_info->task)) { |
243 | ret = PTR_ERR(cb_info->task); | 242 | ret = PTR_ERR(cb_info->task); |
244 | svc_exit_thread(cb_info->rqst); | 243 | svc_exit_thread(cb_info->rqst); |
@@ -282,6 +281,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, struct n | |||
282 | ret = nfs4_callback_up_net(serv, net); | 281 | ret = nfs4_callback_up_net(serv, net); |
283 | break; | 282 | break; |
284 | case 1: | 283 | case 1: |
284 | case 2: | ||
285 | ret = nfs41_callback_up_net(serv, net); | 285 | ret = nfs41_callback_up_net(serv, net); |
286 | break; | 286 | break; |
287 | default: | 287 | default: |
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index efd54f0a4c46..84326e9fb47a 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -32,6 +32,8 @@ enum nfs4_callback_opnum { | |||
32 | OP_CB_WANTS_CANCELLED = 12, | 32 | OP_CB_WANTS_CANCELLED = 12, |
33 | OP_CB_NOTIFY_LOCK = 13, | 33 | OP_CB_NOTIFY_LOCK = 13, |
34 | OP_CB_NOTIFY_DEVICEID = 14, | 34 | OP_CB_NOTIFY_DEVICEID = 14, |
35 | /* Callback operations new to NFSv4.2 */ | ||
36 | OP_CB_OFFLOAD = 15, | ||
35 | OP_CB_ILLEGAL = 10044, | 37 | OP_CB_ILLEGAL = 10044, |
36 | }; | 38 | }; |
37 | 39 | ||
@@ -39,6 +41,7 @@ struct cb_process_state { | |||
39 | __be32 drc_status; | 41 | __be32 drc_status; |
40 | struct nfs_client *clp; | 42 | struct nfs_client *clp; |
41 | u32 slotid; | 43 | u32 slotid; |
44 | u32 minorversion; | ||
42 | struct net *net; | 45 | struct net *net; |
43 | }; | 46 | }; |
44 | 47 | ||
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 0bc27684ebfa..e6ebc4c38c81 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -406,7 +406,8 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
406 | int i; | 406 | int i; |
407 | __be32 status = htonl(NFS4ERR_BADSESSION); | 407 | __be32 status = htonl(NFS4ERR_BADSESSION); |
408 | 408 | ||
409 | clp = nfs4_find_client_sessionid(cps->net, args->csa_addr, &args->csa_sessionid); | 409 | clp = nfs4_find_client_sessionid(cps->net, args->csa_addr, |
410 | &args->csa_sessionid, cps->minorversion); | ||
410 | if (clp == NULL) | 411 | if (clp == NULL) |
411 | goto out; | 412 | goto out; |
412 | 413 | ||
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index a35582c9d444..f4ccfe6521ec 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -166,9 +166,9 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound | |||
166 | if (unlikely(p == NULL)) | 166 | if (unlikely(p == NULL)) |
167 | return htonl(NFS4ERR_RESOURCE); | 167 | return htonl(NFS4ERR_RESOURCE); |
168 | hdr->minorversion = ntohl(*p++); | 168 | hdr->minorversion = ntohl(*p++); |
169 | /* Check minor version is zero or one. */ | 169 | /* Check for minor version support */ |
170 | if (hdr->minorversion <= 1) { | 170 | if (hdr->minorversion <= NFS4_MAX_MINOR_VERSION) { |
171 | hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */ | 171 | hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 and v4.2 */ |
172 | } else { | 172 | } else { |
173 | pr_warn_ratelimited("NFS: %s: NFSv4 server callback with " | 173 | pr_warn_ratelimited("NFS: %s: NFSv4 server callback with " |
174 | "illegal minor version %u!\n", | 174 | "illegal minor version %u!\n", |
@@ -786,6 +786,26 @@ static void nfs4_cb_free_slot(struct cb_process_state *cps) | |||
786 | } | 786 | } |
787 | #endif /* CONFIG_NFS_V4_1 */ | 787 | #endif /* CONFIG_NFS_V4_1 */ |
788 | 788 | ||
789 | #ifdef CONFIG_NFS_V4_2 | ||
790 | static __be32 | ||
791 | preprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op) | ||
792 | { | ||
793 | __be32 status = preprocess_nfs41_op(nop, op_nr, op); | ||
794 | if (status != htonl(NFS4ERR_OP_ILLEGAL)) | ||
795 | return status; | ||
796 | |||
797 | if (op_nr == OP_CB_OFFLOAD) | ||
798 | return htonl(NFS4ERR_NOTSUPP); | ||
799 | return htonl(NFS4ERR_OP_ILLEGAL); | ||
800 | } | ||
801 | #else /* CONFIG_NFS_V4_2 */ | ||
802 | static __be32 | ||
803 | preprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op) | ||
804 | { | ||
805 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | ||
806 | } | ||
807 | #endif /* CONFIG_NFS_V4_2 */ | ||
808 | |||
789 | static __be32 | 809 | static __be32 |
790 | preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) | 810 | preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) |
791 | { | 811 | { |
@@ -801,8 +821,7 @@ preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) | |||
801 | return htonl(NFS_OK); | 821 | return htonl(NFS_OK); |
802 | } | 822 | } |
803 | 823 | ||
804 | static __be32 process_op(uint32_t minorversion, int nop, | 824 | static __be32 process_op(int nop, struct svc_rqst *rqstp, |
805 | struct svc_rqst *rqstp, | ||
806 | struct xdr_stream *xdr_in, void *argp, | 825 | struct xdr_stream *xdr_in, void *argp, |
807 | struct xdr_stream *xdr_out, void *resp, | 826 | struct xdr_stream *xdr_out, void *resp, |
808 | struct cb_process_state *cps) | 827 | struct cb_process_state *cps) |
@@ -819,10 +838,22 @@ static __be32 process_op(uint32_t minorversion, int nop, | |||
819 | return status; | 838 | return status; |
820 | 839 | ||
821 | dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", | 840 | dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", |
822 | __func__, minorversion, nop, op_nr); | 841 | __func__, cps->minorversion, nop, op_nr); |
842 | |||
843 | switch (cps->minorversion) { | ||
844 | case 0: | ||
845 | status = preprocess_nfs4_op(op_nr, &op); | ||
846 | break; | ||
847 | case 1: | ||
848 | status = preprocess_nfs41_op(nop, op_nr, &op); | ||
849 | break; | ||
850 | case 2: | ||
851 | status = preprocess_nfs42_op(nop, op_nr, &op); | ||
852 | break; | ||
853 | default: | ||
854 | status = htonl(NFS4ERR_MINOR_VERS_MISMATCH); | ||
855 | } | ||
823 | 856 | ||
824 | status = minorversion ? preprocess_nfs41_op(nop, op_nr, &op) : | ||
825 | preprocess_nfs4_op(op_nr, &op); | ||
826 | if (status == htonl(NFS4ERR_OP_ILLEGAL)) | 857 | if (status == htonl(NFS4ERR_OP_ILLEGAL)) |
827 | op_nr = OP_CB_ILLEGAL; | 858 | op_nr = OP_CB_ILLEGAL; |
828 | if (status) | 859 | if (status) |
@@ -885,14 +916,15 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
885 | return rpc_drop_reply; | 916 | return rpc_drop_reply; |
886 | } | 917 | } |
887 | 918 | ||
919 | cps.minorversion = hdr_arg.minorversion; | ||
888 | hdr_res.taglen = hdr_arg.taglen; | 920 | hdr_res.taglen = hdr_arg.taglen; |
889 | hdr_res.tag = hdr_arg.tag; | 921 | hdr_res.tag = hdr_arg.tag; |
890 | if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) | 922 | if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) |
891 | return rpc_system_err; | 923 | return rpc_system_err; |
892 | 924 | ||
893 | while (status == 0 && nops != hdr_arg.nops) { | 925 | while (status == 0 && nops != hdr_arg.nops) { |
894 | status = process_op(hdr_arg.minorversion, nops, rqstp, | 926 | status = process_op(nops, rqstp, &xdr_in, |
895 | &xdr_in, argp, &xdr_out, resp, &cps); | 927 | argp, &xdr_out, resp, &cps); |
896 | nops++; | 928 | nops++; |
897 | } | 929 | } |
898 | 930 | ||
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index c513b0cc835f..340b1eff0267 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -753,8 +753,6 @@ static int nfs_init_server(struct nfs_server *server, | |||
753 | data->timeo, data->retrans); | 753 | data->timeo, data->retrans); |
754 | if (data->flags & NFS_MOUNT_NORESVPORT) | 754 | if (data->flags & NFS_MOUNT_NORESVPORT) |
755 | set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); | 755 | set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); |
756 | if (server->options & NFS_OPTION_MIGRATION) | ||
757 | set_bit(NFS_CS_MIGRATION, &cl_init.init_flags); | ||
758 | 756 | ||
759 | /* Allocate or find a client reference we can use */ | 757 | /* Allocate or find a client reference we can use */ |
760 | clp = nfs_get_client(&cl_init, &timeparms, NULL, RPC_AUTH_UNIX); | 758 | clp = nfs_get_client(&cl_init, &timeparms, NULL, RPC_AUTH_UNIX); |
@@ -1076,7 +1074,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info, | |||
1076 | } | 1074 | } |
1077 | 1075 | ||
1078 | if (!(fattr->valid & NFS_ATTR_FATTR)) { | 1076 | if (!(fattr->valid & NFS_ATTR_FATTR)) { |
1079 | error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr); | 1077 | error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr, NULL); |
1080 | if (error < 0) { | 1078 | if (error < 0) { |
1081 | dprintk("nfs_create_server: getattr error = %d\n", -error); | 1079 | dprintk("nfs_create_server: getattr error = %d\n", -error); |
1082 | goto error; | 1080 | goto error; |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 57db3244f4d9..7ec4814e298d 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -73,20 +73,20 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ | |||
73 | if (inode->i_flock == NULL) | 73 | if (inode->i_flock == NULL) |
74 | goto out; | 74 | goto out; |
75 | 75 | ||
76 | /* Protect inode->i_flock using the file locks lock */ | 76 | /* Protect inode->i_flock using the i_lock */ |
77 | lock_flocks(); | 77 | spin_lock(&inode->i_lock); |
78 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 78 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
79 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) | 79 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) |
80 | continue; | 80 | continue; |
81 | if (nfs_file_open_context(fl->fl_file) != ctx) | 81 | if (nfs_file_open_context(fl->fl_file) != ctx) |
82 | continue; | 82 | continue; |
83 | unlock_flocks(); | 83 | spin_unlock(&inode->i_lock); |
84 | status = nfs4_lock_delegation_recall(fl, state, stateid); | 84 | status = nfs4_lock_delegation_recall(fl, state, stateid); |
85 | if (status < 0) | 85 | if (status < 0) |
86 | goto out; | 86 | goto out; |
87 | lock_flocks(); | 87 | spin_lock(&inode->i_lock); |
88 | } | 88 | } |
89 | unlock_flocks(); | 89 | spin_unlock(&inode->i_lock); |
90 | out: | 90 | out: |
91 | return status; | 91 | return status; |
92 | } | 92 | } |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index e093e73178b7..e474ca2b2bfe 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/pagevec.h> | 33 | #include <linux/pagevec.h> |
34 | #include <linux/namei.h> | 34 | #include <linux/namei.h> |
35 | #include <linux/mount.h> | 35 | #include <linux/mount.h> |
36 | #include <linux/swap.h> | ||
36 | #include <linux/sched.h> | 37 | #include <linux/sched.h> |
37 | #include <linux/kmemleak.h> | 38 | #include <linux/kmemleak.h> |
38 | #include <linux/xattr.h> | 39 | #include <linux/xattr.h> |
@@ -46,7 +47,7 @@ | |||
46 | 47 | ||
47 | static int nfs_opendir(struct inode *, struct file *); | 48 | static int nfs_opendir(struct inode *, struct file *); |
48 | static int nfs_closedir(struct inode *, struct file *); | 49 | static int nfs_closedir(struct inode *, struct file *); |
49 | static int nfs_readdir(struct file *, void *, filldir_t); | 50 | static int nfs_readdir(struct file *, struct dir_context *); |
50 | static int nfs_fsync_dir(struct file *, loff_t, loff_t, int); | 51 | static int nfs_fsync_dir(struct file *, loff_t, loff_t, int); |
51 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | 52 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); |
52 | static void nfs_readdir_clear_array(struct page*); | 53 | static void nfs_readdir_clear_array(struct page*); |
@@ -54,7 +55,7 @@ static void nfs_readdir_clear_array(struct page*); | |||
54 | const struct file_operations nfs_dir_operations = { | 55 | const struct file_operations nfs_dir_operations = { |
55 | .llseek = nfs_llseek_dir, | 56 | .llseek = nfs_llseek_dir, |
56 | .read = generic_read_dir, | 57 | .read = generic_read_dir, |
57 | .readdir = nfs_readdir, | 58 | .iterate = nfs_readdir, |
58 | .open = nfs_opendir, | 59 | .open = nfs_opendir, |
59 | .release = nfs_closedir, | 60 | .release = nfs_closedir, |
60 | .fsync = nfs_fsync_dir, | 61 | .fsync = nfs_fsync_dir, |
@@ -147,6 +148,7 @@ typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, int); | |||
147 | typedef struct { | 148 | typedef struct { |
148 | struct file *file; | 149 | struct file *file; |
149 | struct page *page; | 150 | struct page *page; |
151 | struct dir_context *ctx; | ||
150 | unsigned long page_index; | 152 | unsigned long page_index; |
151 | u64 *dir_cookie; | 153 | u64 *dir_cookie; |
152 | u64 last_cookie; | 154 | u64 last_cookie; |
@@ -252,7 +254,7 @@ out: | |||
252 | static | 254 | static |
253 | int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) | 255 | int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) |
254 | { | 256 | { |
255 | loff_t diff = desc->file->f_pos - desc->current_index; | 257 | loff_t diff = desc->ctx->pos - desc->current_index; |
256 | unsigned int index; | 258 | unsigned int index; |
257 | 259 | ||
258 | if (diff < 0) | 260 | if (diff < 0) |
@@ -289,7 +291,7 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des | |||
289 | || (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))) { | 291 | || (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))) { |
290 | ctx->duped = 0; | 292 | ctx->duped = 0; |
291 | ctx->attr_gencount = nfsi->attr_gencount; | 293 | ctx->attr_gencount = nfsi->attr_gencount; |
292 | } else if (new_pos < desc->file->f_pos) { | 294 | } else if (new_pos < desc->ctx->pos) { |
293 | if (ctx->duped > 0 | 295 | if (ctx->duped > 0 |
294 | && ctx->dup_cookie == *desc->dir_cookie) { | 296 | && ctx->dup_cookie == *desc->dir_cookie) { |
295 | if (printk_ratelimit()) { | 297 | if (printk_ratelimit()) { |
@@ -307,7 +309,7 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des | |||
307 | ctx->dup_cookie = *desc->dir_cookie; | 309 | ctx->dup_cookie = *desc->dir_cookie; |
308 | ctx->duped = -1; | 310 | ctx->duped = -1; |
309 | } | 311 | } |
310 | desc->file->f_pos = new_pos; | 312 | desc->ctx->pos = new_pos; |
311 | desc->cache_entry_index = i; | 313 | desc->cache_entry_index = i; |
312 | return 0; | 314 | return 0; |
313 | } | 315 | } |
@@ -405,13 +407,13 @@ different: | |||
405 | } | 407 | } |
406 | 408 | ||
407 | static | 409 | static |
408 | bool nfs_use_readdirplus(struct inode *dir, struct file *filp) | 410 | bool nfs_use_readdirplus(struct inode *dir, struct dir_context *ctx) |
409 | { | 411 | { |
410 | if (!nfs_server_capable(dir, NFS_CAP_READDIRPLUS)) | 412 | if (!nfs_server_capable(dir, NFS_CAP_READDIRPLUS)) |
411 | return false; | 413 | return false; |
412 | if (test_and_clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags)) | 414 | if (test_and_clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags)) |
413 | return true; | 415 | return true; |
414 | if (filp->f_pos == 0) | 416 | if (ctx->pos == 0) |
415 | return true; | 417 | return true; |
416 | return false; | 418 | return false; |
417 | } | 419 | } |
@@ -435,6 +437,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) | |||
435 | struct dentry *alias; | 437 | struct dentry *alias; |
436 | struct inode *dir = parent->d_inode; | 438 | struct inode *dir = parent->d_inode; |
437 | struct inode *inode; | 439 | struct inode *inode; |
440 | int status; | ||
438 | 441 | ||
439 | if (filename.name[0] == '.') { | 442 | if (filename.name[0] == '.') { |
440 | if (filename.len == 1) | 443 | if (filename.len == 1) |
@@ -447,7 +450,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) | |||
447 | dentry = d_lookup(parent, &filename); | 450 | dentry = d_lookup(parent, &filename); |
448 | if (dentry != NULL) { | 451 | if (dentry != NULL) { |
449 | if (nfs_same_file(dentry, entry)) { | 452 | if (nfs_same_file(dentry, entry)) { |
450 | nfs_refresh_inode(dentry->d_inode, entry->fattr); | 453 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
454 | status = nfs_refresh_inode(dentry->d_inode, entry->fattr); | ||
455 | if (!status) | ||
456 | nfs_setsecurity(dentry->d_inode, entry->fattr, entry->label); | ||
451 | goto out; | 457 | goto out; |
452 | } else { | 458 | } else { |
453 | if (d_invalidate(dentry) != 0) | 459 | if (d_invalidate(dentry) != 0) |
@@ -460,7 +466,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) | |||
460 | if (dentry == NULL) | 466 | if (dentry == NULL) |
461 | return; | 467 | return; |
462 | 468 | ||
463 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); | 469 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr, entry->label); |
464 | if (IS_ERR(inode)) | 470 | if (IS_ERR(inode)) |
465 | goto out; | 471 | goto out; |
466 | 472 | ||
@@ -585,10 +591,16 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, | |||
585 | if (entry.fh == NULL || entry.fattr == NULL) | 591 | if (entry.fh == NULL || entry.fattr == NULL) |
586 | goto out; | 592 | goto out; |
587 | 593 | ||
594 | entry.label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT); | ||
595 | if (IS_ERR(entry.label)) { | ||
596 | status = PTR_ERR(entry.label); | ||
597 | goto out; | ||
598 | } | ||
599 | |||
588 | array = nfs_readdir_get_array(page); | 600 | array = nfs_readdir_get_array(page); |
589 | if (IS_ERR(array)) { | 601 | if (IS_ERR(array)) { |
590 | status = PTR_ERR(array); | 602 | status = PTR_ERR(array); |
591 | goto out; | 603 | goto out_label_free; |
592 | } | 604 | } |
593 | memset(array, 0, sizeof(struct nfs_cache_array)); | 605 | memset(array, 0, sizeof(struct nfs_cache_array)); |
594 | array->eof_index = -1; | 606 | array->eof_index = -1; |
@@ -614,6 +626,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, | |||
614 | nfs_readdir_free_large_page(pages_ptr, pages, array_size); | 626 | nfs_readdir_free_large_page(pages_ptr, pages, array_size); |
615 | out_release_array: | 627 | out_release_array: |
616 | nfs_readdir_release_array(page); | 628 | nfs_readdir_release_array(page); |
629 | out_label_free: | ||
630 | nfs4_label_free(entry.label); | ||
617 | out: | 631 | out: |
618 | nfs_free_fattr(entry.fattr); | 632 | nfs_free_fattr(entry.fattr); |
619 | nfs_free_fhandle(entry.fh); | 633 | nfs_free_fhandle(entry.fh); |
@@ -702,8 +716,7 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | |||
702 | * Once we've found the start of the dirent within a page: fill 'er up... | 716 | * Once we've found the start of the dirent within a page: fill 'er up... |
703 | */ | 717 | */ |
704 | static | 718 | static |
705 | int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | 719 | int nfs_do_filldir(nfs_readdir_descriptor_t *desc) |
706 | filldir_t filldir) | ||
707 | { | 720 | { |
708 | struct file *file = desc->file; | 721 | struct file *file = desc->file; |
709 | int i = 0; | 722 | int i = 0; |
@@ -721,13 +734,12 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
721 | struct nfs_cache_array_entry *ent; | 734 | struct nfs_cache_array_entry *ent; |
722 | 735 | ||
723 | ent = &array->array[i]; | 736 | ent = &array->array[i]; |
724 | if (filldir(dirent, ent->string.name, ent->string.len, | 737 | if (!dir_emit(desc->ctx, ent->string.name, ent->string.len, |
725 | file->f_pos, nfs_compat_user_ino64(ent->ino), | 738 | nfs_compat_user_ino64(ent->ino), ent->d_type)) { |
726 | ent->d_type) < 0) { | ||
727 | desc->eof = 1; | 739 | desc->eof = 1; |
728 | break; | 740 | break; |
729 | } | 741 | } |
730 | file->f_pos++; | 742 | desc->ctx->pos++; |
731 | if (i < (array->size-1)) | 743 | if (i < (array->size-1)) |
732 | *desc->dir_cookie = array->array[i+1].cookie; | 744 | *desc->dir_cookie = array->array[i+1].cookie; |
733 | else | 745 | else |
@@ -759,8 +771,7 @@ out: | |||
759 | * directory in the page cache by the time we get here. | 771 | * directory in the page cache by the time we get here. |
760 | */ | 772 | */ |
761 | static inline | 773 | static inline |
762 | int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | 774 | int uncached_readdir(nfs_readdir_descriptor_t *desc) |
763 | filldir_t filldir) | ||
764 | { | 775 | { |
765 | struct page *page = NULL; | 776 | struct page *page = NULL; |
766 | int status; | 777 | int status; |
@@ -785,7 +796,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
785 | if (status < 0) | 796 | if (status < 0) |
786 | goto out_release; | 797 | goto out_release; |
787 | 798 | ||
788 | status = nfs_do_filldir(desc, dirent, filldir); | 799 | status = nfs_do_filldir(desc); |
789 | 800 | ||
790 | out: | 801 | out: |
791 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", | 802 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", |
@@ -800,35 +811,37 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
800 | last cookie cache takes care of the common case of reading the | 811 | last cookie cache takes care of the common case of reading the |
801 | whole directory. | 812 | whole directory. |
802 | */ | 813 | */ |
803 | static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | 814 | static int nfs_readdir(struct file *file, struct dir_context *ctx) |
804 | { | 815 | { |
805 | struct dentry *dentry = filp->f_path.dentry; | 816 | struct dentry *dentry = file->f_path.dentry; |
806 | struct inode *inode = dentry->d_inode; | 817 | struct inode *inode = dentry->d_inode; |
807 | nfs_readdir_descriptor_t my_desc, | 818 | nfs_readdir_descriptor_t my_desc, |
808 | *desc = &my_desc; | 819 | *desc = &my_desc; |
809 | struct nfs_open_dir_context *dir_ctx = filp->private_data; | 820 | struct nfs_open_dir_context *dir_ctx = file->private_data; |
810 | int res; | 821 | int res = 0; |
811 | 822 | ||
812 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", | 823 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", |
813 | dentry->d_parent->d_name.name, dentry->d_name.name, | 824 | dentry->d_parent->d_name.name, dentry->d_name.name, |
814 | (long long)filp->f_pos); | 825 | (long long)ctx->pos); |
815 | nfs_inc_stats(inode, NFSIOS_VFSGETDENTS); | 826 | nfs_inc_stats(inode, NFSIOS_VFSGETDENTS); |
816 | 827 | ||
817 | /* | 828 | /* |
818 | * filp->f_pos points to the dirent entry number. | 829 | * ctx->pos points to the dirent entry number. |
819 | * *desc->dir_cookie has the cookie for the next entry. We have | 830 | * *desc->dir_cookie has the cookie for the next entry. We have |
820 | * to either find the entry with the appropriate number or | 831 | * to either find the entry with the appropriate number or |
821 | * revalidate the cookie. | 832 | * revalidate the cookie. |
822 | */ | 833 | */ |
823 | memset(desc, 0, sizeof(*desc)); | 834 | memset(desc, 0, sizeof(*desc)); |
824 | 835 | ||
825 | desc->file = filp; | 836 | desc->file = file; |
837 | desc->ctx = ctx; | ||
826 | desc->dir_cookie = &dir_ctx->dir_cookie; | 838 | desc->dir_cookie = &dir_ctx->dir_cookie; |
827 | desc->decode = NFS_PROTO(inode)->decode_dirent; | 839 | desc->decode = NFS_PROTO(inode)->decode_dirent; |
828 | desc->plus = nfs_use_readdirplus(inode, filp) ? 1 : 0; | 840 | desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0; |
829 | 841 | ||
830 | nfs_block_sillyrename(dentry); | 842 | nfs_block_sillyrename(dentry); |
831 | res = nfs_revalidate_mapping(inode, filp->f_mapping); | 843 | if (ctx->pos == 0 || nfs_attribute_cache_expired(inode)) |
844 | res = nfs_revalidate_mapping(inode, file->f_mapping); | ||
832 | if (res < 0) | 845 | if (res < 0) |
833 | goto out; | 846 | goto out; |
834 | 847 | ||
@@ -840,7 +853,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
840 | /* This means either end of directory */ | 853 | /* This means either end of directory */ |
841 | if (*desc->dir_cookie && desc->eof == 0) { | 854 | if (*desc->dir_cookie && desc->eof == 0) { |
842 | /* Or that the server has 'lost' a cookie */ | 855 | /* Or that the server has 'lost' a cookie */ |
843 | res = uncached_readdir(desc, dirent, filldir); | 856 | res = uncached_readdir(desc); |
844 | if (res == 0) | 857 | if (res == 0) |
845 | continue; | 858 | continue; |
846 | } | 859 | } |
@@ -857,7 +870,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
857 | if (res < 0) | 870 | if (res < 0) |
858 | break; | 871 | break; |
859 | 872 | ||
860 | res = nfs_do_filldir(desc, dirent, filldir); | 873 | res = nfs_do_filldir(desc); |
861 | if (res < 0) | 874 | if (res < 0) |
862 | break; | 875 | break; |
863 | } while (!desc->eof); | 876 | } while (!desc->eof); |
@@ -1040,6 +1053,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) | |||
1040 | struct dentry *parent; | 1053 | struct dentry *parent; |
1041 | struct nfs_fh *fhandle = NULL; | 1054 | struct nfs_fh *fhandle = NULL; |
1042 | struct nfs_fattr *fattr = NULL; | 1055 | struct nfs_fattr *fattr = NULL; |
1056 | struct nfs4_label *label = NULL; | ||
1043 | int error; | 1057 | int error; |
1044 | 1058 | ||
1045 | if (flags & LOOKUP_RCU) | 1059 | if (flags & LOOKUP_RCU) |
@@ -1082,7 +1096,11 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) | |||
1082 | if (fhandle == NULL || fattr == NULL) | 1096 | if (fhandle == NULL || fattr == NULL) |
1083 | goto out_error; | 1097 | goto out_error; |
1084 | 1098 | ||
1085 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | 1099 | label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT); |
1100 | if (IS_ERR(label)) | ||
1101 | goto out_error; | ||
1102 | |||
1103 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label); | ||
1086 | if (error) | 1104 | if (error) |
1087 | goto out_bad; | 1105 | goto out_bad; |
1088 | if (nfs_compare_fh(NFS_FH(inode), fhandle)) | 1106 | if (nfs_compare_fh(NFS_FH(inode), fhandle)) |
@@ -1090,8 +1108,12 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) | |||
1090 | if ((error = nfs_refresh_inode(inode, fattr)) != 0) | 1108 | if ((error = nfs_refresh_inode(inode, fattr)) != 0) |
1091 | goto out_bad; | 1109 | goto out_bad; |
1092 | 1110 | ||
1111 | nfs_setsecurity(inode, fattr, label); | ||
1112 | |||
1093 | nfs_free_fattr(fattr); | 1113 | nfs_free_fattr(fattr); |
1094 | nfs_free_fhandle(fhandle); | 1114 | nfs_free_fhandle(fhandle); |
1115 | nfs4_label_free(label); | ||
1116 | |||
1095 | out_set_verifier: | 1117 | out_set_verifier: |
1096 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 1118 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
1097 | out_valid: | 1119 | out_valid: |
@@ -1108,6 +1130,7 @@ out_zap_parent: | |||
1108 | out_bad: | 1130 | out_bad: |
1109 | nfs_free_fattr(fattr); | 1131 | nfs_free_fattr(fattr); |
1110 | nfs_free_fhandle(fhandle); | 1132 | nfs_free_fhandle(fhandle); |
1133 | nfs4_label_free(label); | ||
1111 | nfs_mark_for_revalidate(dir); | 1134 | nfs_mark_for_revalidate(dir); |
1112 | if (inode && S_ISDIR(inode->i_mode)) { | 1135 | if (inode && S_ISDIR(inode->i_mode)) { |
1113 | /* Purge readdir caches. */ | 1136 | /* Purge readdir caches. */ |
@@ -1128,6 +1151,7 @@ out_zap_parent: | |||
1128 | out_error: | 1151 | out_error: |
1129 | nfs_free_fattr(fattr); | 1152 | nfs_free_fattr(fattr); |
1130 | nfs_free_fhandle(fhandle); | 1153 | nfs_free_fhandle(fhandle); |
1154 | nfs4_label_free(label); | ||
1131 | dput(parent); | 1155 | dput(parent); |
1132 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n", | 1156 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n", |
1133 | __func__, dentry->d_parent->d_name.name, | 1157 | __func__, dentry->d_parent->d_name.name, |
@@ -1256,6 +1280,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in | |||
1256 | struct inode *inode = NULL; | 1280 | struct inode *inode = NULL; |
1257 | struct nfs_fh *fhandle = NULL; | 1281 | struct nfs_fh *fhandle = NULL; |
1258 | struct nfs_fattr *fattr = NULL; | 1282 | struct nfs_fattr *fattr = NULL; |
1283 | struct nfs4_label *label = NULL; | ||
1259 | int error; | 1284 | int error; |
1260 | 1285 | ||
1261 | dfprintk(VFS, "NFS: lookup(%s/%s)\n", | 1286 | dfprintk(VFS, "NFS: lookup(%s/%s)\n", |
@@ -1282,17 +1307,21 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in | |||
1282 | if (fhandle == NULL || fattr == NULL) | 1307 | if (fhandle == NULL || fattr == NULL) |
1283 | goto out; | 1308 | goto out; |
1284 | 1309 | ||
1310 | label = nfs4_label_alloc(NFS_SERVER(dir), GFP_NOWAIT); | ||
1311 | if (IS_ERR(label)) | ||
1312 | goto out; | ||
1313 | |||
1285 | parent = dentry->d_parent; | 1314 | parent = dentry->d_parent; |
1286 | /* Protect against concurrent sillydeletes */ | 1315 | /* Protect against concurrent sillydeletes */ |
1287 | nfs_block_sillyrename(parent); | 1316 | nfs_block_sillyrename(parent); |
1288 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | 1317 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label); |
1289 | if (error == -ENOENT) | 1318 | if (error == -ENOENT) |
1290 | goto no_entry; | 1319 | goto no_entry; |
1291 | if (error < 0) { | 1320 | if (error < 0) { |
1292 | res = ERR_PTR(error); | 1321 | res = ERR_PTR(error); |
1293 | goto out_unblock_sillyrename; | 1322 | goto out_unblock_sillyrename; |
1294 | } | 1323 | } |
1295 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); | 1324 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label); |
1296 | res = ERR_CAST(inode); | 1325 | res = ERR_CAST(inode); |
1297 | if (IS_ERR(res)) | 1326 | if (IS_ERR(res)) |
1298 | goto out_unblock_sillyrename; | 1327 | goto out_unblock_sillyrename; |
@@ -1310,6 +1339,7 @@ no_entry: | |||
1310 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 1339 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
1311 | out_unblock_sillyrename: | 1340 | out_unblock_sillyrename: |
1312 | nfs_unblock_sillyrename(parent); | 1341 | nfs_unblock_sillyrename(parent); |
1342 | nfs4_label_free(label); | ||
1313 | out: | 1343 | out: |
1314 | nfs_free_fattr(fattr); | 1344 | nfs_free_fattr(fattr); |
1315 | nfs_free_fhandle(fhandle); | 1345 | nfs_free_fhandle(fhandle); |
@@ -1357,18 +1387,6 @@ static int nfs_finish_open(struct nfs_open_context *ctx, | |||
1357 | { | 1387 | { |
1358 | int err; | 1388 | int err; |
1359 | 1389 | ||
1360 | if (ctx->dentry != dentry) { | ||
1361 | dput(ctx->dentry); | ||
1362 | ctx->dentry = dget(dentry); | ||
1363 | } | ||
1364 | |||
1365 | /* If the open_intent is for execute, we have an extra check to make */ | ||
1366 | if (ctx->mode & FMODE_EXEC) { | ||
1367 | err = nfs_may_open(dentry->d_inode, ctx->cred, open_flags); | ||
1368 | if (err < 0) | ||
1369 | goto out; | ||
1370 | } | ||
1371 | |||
1372 | err = finish_open(file, dentry, do_open, opened); | 1390 | err = finish_open(file, dentry, do_open, opened); |
1373 | if (err) | 1391 | if (err) |
1374 | goto out; | 1392 | goto out; |
@@ -1427,13 +1445,13 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, | |||
1427 | 1445 | ||
1428 | nfs_block_sillyrename(dentry->d_parent); | 1446 | nfs_block_sillyrename(dentry->d_parent); |
1429 | inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr); | 1447 | inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr); |
1430 | d_drop(dentry); | 1448 | nfs_unblock_sillyrename(dentry->d_parent); |
1431 | if (IS_ERR(inode)) { | 1449 | if (IS_ERR(inode)) { |
1432 | nfs_unblock_sillyrename(dentry->d_parent); | ||
1433 | put_nfs_open_context(ctx); | 1450 | put_nfs_open_context(ctx); |
1434 | err = PTR_ERR(inode); | 1451 | err = PTR_ERR(inode); |
1435 | switch (err) { | 1452 | switch (err) { |
1436 | case -ENOENT: | 1453 | case -ENOENT: |
1454 | d_drop(dentry); | ||
1437 | d_add(dentry, NULL); | 1455 | d_add(dentry, NULL); |
1438 | break; | 1456 | break; |
1439 | case -EISDIR: | 1457 | case -EISDIR: |
@@ -1449,16 +1467,8 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, | |||
1449 | } | 1467 | } |
1450 | goto out; | 1468 | goto out; |
1451 | } | 1469 | } |
1452 | res = d_add_unique(dentry, inode); | ||
1453 | if (res != NULL) | ||
1454 | dentry = res; | ||
1455 | |||
1456 | nfs_unblock_sillyrename(dentry->d_parent); | ||
1457 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
1458 | |||
1459 | err = nfs_finish_open(ctx, dentry, file, open_flags, opened); | ||
1460 | 1470 | ||
1461 | dput(res); | 1471 | err = nfs_finish_open(ctx, ctx->dentry, file, open_flags, opened); |
1462 | out: | 1472 | out: |
1463 | return err; | 1473 | return err; |
1464 | 1474 | ||
@@ -1528,7 +1538,8 @@ no_open: | |||
1528 | * Code common to create, mkdir, and mknod. | 1538 | * Code common to create, mkdir, and mknod. |
1529 | */ | 1539 | */ |
1530 | int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, | 1540 | int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, |
1531 | struct nfs_fattr *fattr) | 1541 | struct nfs_fattr *fattr, |
1542 | struct nfs4_label *label) | ||
1532 | { | 1543 | { |
1533 | struct dentry *parent = dget_parent(dentry); | 1544 | struct dentry *parent = dget_parent(dentry); |
1534 | struct inode *dir = parent->d_inode; | 1545 | struct inode *dir = parent->d_inode; |
@@ -1541,18 +1552,18 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, | |||
1541 | if (dentry->d_inode) | 1552 | if (dentry->d_inode) |
1542 | goto out; | 1553 | goto out; |
1543 | if (fhandle->size == 0) { | 1554 | if (fhandle->size == 0) { |
1544 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | 1555 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, NULL); |
1545 | if (error) | 1556 | if (error) |
1546 | goto out_error; | 1557 | goto out_error; |
1547 | } | 1558 | } |
1548 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 1559 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
1549 | if (!(fattr->valid & NFS_ATTR_FATTR)) { | 1560 | if (!(fattr->valid & NFS_ATTR_FATTR)) { |
1550 | struct nfs_server *server = NFS_SB(dentry->d_sb); | 1561 | struct nfs_server *server = NFS_SB(dentry->d_sb); |
1551 | error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr); | 1562 | error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr, NULL); |
1552 | if (error < 0) | 1563 | if (error < 0) |
1553 | goto out_error; | 1564 | goto out_error; |
1554 | } | 1565 | } |
1555 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); | 1566 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label); |
1556 | error = PTR_ERR(inode); | 1567 | error = PTR_ERR(inode); |
1557 | if (IS_ERR(inode)) | 1568 | if (IS_ERR(inode)) |
1558 | goto out_error; | 1569 | goto out_error; |
@@ -1721,7 +1732,7 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1721 | dir->i_ino, dentry->d_name.name); | 1732 | dir->i_ino, dentry->d_name.name); |
1722 | 1733 | ||
1723 | spin_lock(&dentry->d_lock); | 1734 | spin_lock(&dentry->d_lock); |
1724 | if (dentry->d_count > 1) { | 1735 | if (d_count(dentry) > 1) { |
1725 | spin_unlock(&dentry->d_lock); | 1736 | spin_unlock(&dentry->d_lock); |
1726 | /* Start asynchronous writeout of the inode */ | 1737 | /* Start asynchronous writeout of the inode */ |
1727 | write_inode_now(dentry->d_inode, 0); | 1738 | write_inode_now(dentry->d_inode, 0); |
@@ -1759,7 +1770,6 @@ EXPORT_SYMBOL_GPL(nfs_unlink); | |||
1759 | */ | 1770 | */ |
1760 | int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | 1771 | int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) |
1761 | { | 1772 | { |
1762 | struct pagevec lru_pvec; | ||
1763 | struct page *page; | 1773 | struct page *page; |
1764 | char *kaddr; | 1774 | char *kaddr; |
1765 | struct iattr attr; | 1775 | struct iattr attr; |
@@ -1799,11 +1809,8 @@ int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | |||
1799 | * No big deal if we can't add this page to the page cache here. | 1809 | * No big deal if we can't add this page to the page cache here. |
1800 | * READLINK will get the missing page from the server if needed. | 1810 | * READLINK will get the missing page from the server if needed. |
1801 | */ | 1811 | */ |
1802 | pagevec_init(&lru_pvec, 0); | 1812 | if (!add_to_page_cache_lru(page, dentry->d_inode->i_mapping, 0, |
1803 | if (!add_to_page_cache(page, dentry->d_inode->i_mapping, 0, | ||
1804 | GFP_KERNEL)) { | 1813 | GFP_KERNEL)) { |
1805 | pagevec_add(&lru_pvec, page); | ||
1806 | pagevec_lru_add_file(&lru_pvec); | ||
1807 | SetPageUptodate(page); | 1814 | SetPageUptodate(page); |
1808 | unlock_page(page); | 1815 | unlock_page(page); |
1809 | } else | 1816 | } else |
@@ -1870,7 +1877,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1870 | dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", | 1877 | dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", |
1871 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, | 1878 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, |
1872 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name, | 1879 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name, |
1873 | new_dentry->d_count); | 1880 | d_count(new_dentry)); |
1874 | 1881 | ||
1875 | /* | 1882 | /* |
1876 | * For non-directories, check whether the target is busy and if so, | 1883 | * For non-directories, check whether the target is busy and if so, |
@@ -1888,7 +1895,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1888 | rehash = new_dentry; | 1895 | rehash = new_dentry; |
1889 | } | 1896 | } |
1890 | 1897 | ||
1891 | if (new_dentry->d_count > 2) { | 1898 | if (d_count(new_dentry) > 2) { |
1892 | int err; | 1899 | int err; |
1893 | 1900 | ||
1894 | /* copy the target dentry's name */ | 1901 | /* copy the target dentry's name */ |
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index 945527092295..fc0f95ec7358 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c | |||
@@ -29,7 +29,6 @@ ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen, | |||
29 | kfree(ip_addr); | 29 | kfree(ip_addr); |
30 | return ret; | 30 | return ret; |
31 | } | 31 | } |
32 | EXPORT_SYMBOL_GPL(nfs_dns_resolve_name); | ||
33 | 32 | ||
34 | #else | 33 | #else |
35 | 34 | ||
@@ -351,7 +350,6 @@ ssize_t nfs_dns_resolve_name(struct net *net, char *name, | |||
351 | ret = -ESRCH; | 350 | ret = -ESRCH; |
352 | return ret; | 351 | return ret; |
353 | } | 352 | } |
354 | EXPORT_SYMBOL_GPL(nfs_dns_resolve_name); | ||
355 | 353 | ||
356 | static struct cache_detail nfs_dns_resolve_template = { | 354 | static struct cache_detail nfs_dns_resolve_template = { |
357 | .owner = THIS_MODULE, | 355 | .owner = THIS_MODULE, |
@@ -396,6 +394,21 @@ void nfs_dns_resolver_cache_destroy(struct net *net) | |||
396 | cache_destroy_net(nn->nfs_dns_resolve, net); | 394 | cache_destroy_net(nn->nfs_dns_resolve, net); |
397 | } | 395 | } |
398 | 396 | ||
397 | static int nfs4_dns_net_init(struct net *net) | ||
398 | { | ||
399 | return nfs_dns_resolver_cache_init(net); | ||
400 | } | ||
401 | |||
402 | static void nfs4_dns_net_exit(struct net *net) | ||
403 | { | ||
404 | nfs_dns_resolver_cache_destroy(net); | ||
405 | } | ||
406 | |||
407 | static struct pernet_operations nfs4_dns_resolver_ops = { | ||
408 | .init = nfs4_dns_net_init, | ||
409 | .exit = nfs4_dns_net_exit, | ||
410 | }; | ||
411 | |||
399 | static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, | 412 | static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, |
400 | void *ptr) | 413 | void *ptr) |
401 | { | 414 | { |
@@ -432,11 +445,24 @@ static struct notifier_block nfs_dns_resolver_block = { | |||
432 | 445 | ||
433 | int nfs_dns_resolver_init(void) | 446 | int nfs_dns_resolver_init(void) |
434 | { | 447 | { |
435 | return rpc_pipefs_notifier_register(&nfs_dns_resolver_block); | 448 | int err; |
449 | |||
450 | err = register_pernet_subsys(&nfs4_dns_resolver_ops); | ||
451 | if (err < 0) | ||
452 | goto out; | ||
453 | err = rpc_pipefs_notifier_register(&nfs_dns_resolver_block); | ||
454 | if (err < 0) | ||
455 | goto out1; | ||
456 | return 0; | ||
457 | out1: | ||
458 | unregister_pernet_subsys(&nfs4_dns_resolver_ops); | ||
459 | out: | ||
460 | return err; | ||
436 | } | 461 | } |
437 | 462 | ||
438 | void nfs_dns_resolver_destroy(void) | 463 | void nfs_dns_resolver_destroy(void) |
439 | { | 464 | { |
440 | rpc_pipefs_notifier_unregister(&nfs_dns_resolver_block); | 465 | rpc_pipefs_notifier_unregister(&nfs_dns_resolver_block); |
466 | unregister_pernet_subsys(&nfs4_dns_resolver_ops); | ||
441 | } | 467 | } |
442 | #endif | 468 | #endif |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index a87a44f84113..94e94bd11aae 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -451,11 +451,13 @@ static int nfs_write_end(struct file *file, struct address_space *mapping, | |||
451 | * - Called if either PG_private or PG_fscache is set on the page | 451 | * - Called if either PG_private or PG_fscache is set on the page |
452 | * - Caller holds page lock | 452 | * - Caller holds page lock |
453 | */ | 453 | */ |
454 | static void nfs_invalidate_page(struct page *page, unsigned long offset) | 454 | static void nfs_invalidate_page(struct page *page, unsigned int offset, |
455 | unsigned int length) | ||
455 | { | 456 | { |
456 | dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %lu)\n", page, offset); | 457 | dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %u, %u)\n", |
458 | page, offset, length); | ||
457 | 459 | ||
458 | if (offset != 0) | 460 | if (offset != 0 || length < PAGE_CACHE_SIZE) |
459 | return; | 461 | return; |
460 | /* Cancel any unstarted writes on this page */ | 462 | /* Cancel any unstarted writes on this page */ |
461 | nfs_wb_page_cancel(page_file_mapping(page)->host, page); | 463 | nfs_wb_page_cancel(page_file_mapping(page)->host, page); |
@@ -493,6 +495,35 @@ static int nfs_release_page(struct page *page, gfp_t gfp) | |||
493 | return nfs_fscache_release_page(page, gfp); | 495 | return nfs_fscache_release_page(page, gfp); |
494 | } | 496 | } |
495 | 497 | ||
498 | static void nfs_check_dirty_writeback(struct page *page, | ||
499 | bool *dirty, bool *writeback) | ||
500 | { | ||
501 | struct nfs_inode *nfsi; | ||
502 | struct address_space *mapping = page_file_mapping(page); | ||
503 | |||
504 | if (!mapping || PageSwapCache(page)) | ||
505 | return; | ||
506 | |||
507 | /* | ||
508 | * Check if an unstable page is currently being committed and | ||
509 | * if so, have the VM treat it as if the page is under writeback | ||
510 | * so it will not block due to pages that will shortly be freeable. | ||
511 | */ | ||
512 | nfsi = NFS_I(mapping->host); | ||
513 | if (test_bit(NFS_INO_COMMIT, &nfsi->flags)) { | ||
514 | *writeback = true; | ||
515 | return; | ||
516 | } | ||
517 | |||
518 | /* | ||
519 | * If PagePrivate() is set, then the page is not freeable and as the | ||
520 | * inode is not being committed, it's not going to be cleaned in the | ||
521 | * near future so treat it as dirty | ||
522 | */ | ||
523 | if (PagePrivate(page)) | ||
524 | *dirty = true; | ||
525 | } | ||
526 | |||
496 | /* | 527 | /* |
497 | * Attempt to clear the private state associated with a page when an error | 528 | * Attempt to clear the private state associated with a page when an error |
498 | * occurs that requires the cached contents of an inode to be written back or | 529 | * occurs that requires the cached contents of an inode to be written back or |
@@ -540,6 +571,7 @@ const struct address_space_operations nfs_file_aops = { | |||
540 | .direct_IO = nfs_direct_IO, | 571 | .direct_IO = nfs_direct_IO, |
541 | .migratepage = nfs_migrate_page, | 572 | .migratepage = nfs_migrate_page, |
542 | .launder_page = nfs_launder_page, | 573 | .launder_page = nfs_launder_page, |
574 | .is_dirty_writeback = nfs_check_dirty_writeback, | ||
543 | .error_remove_page = generic_error_remove_page, | 575 | .error_remove_page = generic_error_remove_page, |
544 | #ifdef CONFIG_NFS_SWAP | 576 | #ifdef CONFIG_NFS_SWAP |
545 | .swap_activate = nfs_swap_activate, | 577 | .swap_activate = nfs_swap_activate, |
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 44efaa8c5f78..66984a9aafaa 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
@@ -95,7 +95,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh, | |||
95 | goto out; | 95 | goto out; |
96 | } | 96 | } |
97 | 97 | ||
98 | inode = nfs_fhget(sb, mntfh, fsinfo.fattr); | 98 | inode = nfs_fhget(sb, mntfh, fsinfo.fattr, NULL); |
99 | if (IS_ERR(inode)) { | 99 | if (IS_ERR(inode)) { |
100 | dprintk("nfs_get_root: get root inode failed\n"); | 100 | dprintk("nfs_get_root: get root inode failed\n"); |
101 | ret = ERR_CAST(inode); | 101 | ret = ERR_CAST(inode); |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index c516da5873fd..c2c4163d5683 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -262,29 +262,42 @@ static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen, | |||
262 | return desclen; | 262 | return desclen; |
263 | } | 263 | } |
264 | 264 | ||
265 | static ssize_t nfs_idmap_request_key(struct key_type *key_type, | 265 | static struct key *nfs_idmap_request_key(const char *name, size_t namelen, |
266 | const char *name, size_t namelen, | 266 | const char *type, struct idmap *idmap) |
267 | const char *type, void *data, | ||
268 | size_t data_size, struct idmap *idmap) | ||
269 | { | 267 | { |
270 | const struct cred *saved_cred; | ||
271 | struct key *rkey; | ||
272 | char *desc; | 268 | char *desc; |
273 | struct user_key_payload *payload; | 269 | struct key *rkey; |
274 | ssize_t ret; | 270 | ssize_t ret; |
275 | 271 | ||
276 | ret = nfs_idmap_get_desc(name, namelen, type, strlen(type), &desc); | 272 | ret = nfs_idmap_get_desc(name, namelen, type, strlen(type), &desc); |
277 | if (ret <= 0) | 273 | if (ret <= 0) |
278 | goto out; | 274 | return ERR_PTR(ret); |
275 | |||
276 | rkey = request_key(&key_type_id_resolver, desc, ""); | ||
277 | if (IS_ERR(rkey)) { | ||
278 | mutex_lock(&idmap->idmap_mutex); | ||
279 | rkey = request_key_with_auxdata(&key_type_id_resolver_legacy, | ||
280 | desc, "", 0, idmap); | ||
281 | mutex_unlock(&idmap->idmap_mutex); | ||
282 | } | ||
283 | |||
284 | kfree(desc); | ||
285 | return rkey; | ||
286 | } | ||
287 | |||
288 | static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, | ||
289 | const char *type, void *data, | ||
290 | size_t data_size, struct idmap *idmap) | ||
291 | { | ||
292 | const struct cred *saved_cred; | ||
293 | struct key *rkey; | ||
294 | struct user_key_payload *payload; | ||
295 | ssize_t ret; | ||
279 | 296 | ||
280 | saved_cred = override_creds(id_resolver_cache); | 297 | saved_cred = override_creds(id_resolver_cache); |
281 | if (idmap) | 298 | rkey = nfs_idmap_request_key(name, namelen, type, idmap); |
282 | rkey = request_key_with_auxdata(key_type, desc, "", 0, idmap); | ||
283 | else | ||
284 | rkey = request_key(&key_type_id_resolver, desc, ""); | ||
285 | revert_creds(saved_cred); | 299 | revert_creds(saved_cred); |
286 | 300 | ||
287 | kfree(desc); | ||
288 | if (IS_ERR(rkey)) { | 301 | if (IS_ERR(rkey)) { |
289 | ret = PTR_ERR(rkey); | 302 | ret = PTR_ERR(rkey); |
290 | goto out; | 303 | goto out; |
@@ -316,23 +329,6 @@ out: | |||
316 | return ret; | 329 | return ret; |
317 | } | 330 | } |
318 | 331 | ||
319 | static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, | ||
320 | const char *type, void *data, | ||
321 | size_t data_size, struct idmap *idmap) | ||
322 | { | ||
323 | ssize_t ret = nfs_idmap_request_key(&key_type_id_resolver, | ||
324 | name, namelen, type, data, | ||
325 | data_size, NULL); | ||
326 | if (ret < 0) { | ||
327 | mutex_lock(&idmap->idmap_mutex); | ||
328 | ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, | ||
329 | name, namelen, type, data, | ||
330 | data_size, idmap); | ||
331 | mutex_unlock(&idmap->idmap_mutex); | ||
332 | } | ||
333 | return ret; | ||
334 | } | ||
335 | |||
336 | /* ID -> Name */ | 332 | /* ID -> Name */ |
337 | static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, | 333 | static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, |
338 | size_t buflen, struct idmap *idmap) | 334 | size_t buflen, struct idmap *idmap) |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index c1c7a9d78722..941246f2b43d 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -48,7 +48,6 @@ | |||
48 | #include "iostat.h" | 48 | #include "iostat.h" |
49 | #include "internal.h" | 49 | #include "internal.h" |
50 | #include "fscache.h" | 50 | #include "fscache.h" |
51 | #include "dns_resolve.h" | ||
52 | #include "pnfs.h" | 51 | #include "pnfs.h" |
53 | #include "nfs.h" | 52 | #include "nfs.h" |
54 | #include "netns.h" | 53 | #include "netns.h" |
@@ -79,7 +78,7 @@ int nfs_wait_bit_killable(void *word) | |||
79 | { | 78 | { |
80 | if (fatal_signal_pending(current)) | 79 | if (fatal_signal_pending(current)) |
81 | return -ERESTARTSYS; | 80 | return -ERESTARTSYS; |
82 | freezable_schedule(); | 81 | freezable_schedule_unsafe(); |
83 | return 0; | 82 | return 0; |
84 | } | 83 | } |
85 | EXPORT_SYMBOL_GPL(nfs_wait_bit_killable); | 84 | EXPORT_SYMBOL_GPL(nfs_wait_bit_killable); |
@@ -162,11 +161,19 @@ static void nfs_zap_caches_locked(struct inode *inode) | |||
162 | 161 | ||
163 | memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf)); | 162 | memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf)); |
164 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { | 163 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { |
165 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; | ||
166 | nfs_fscache_invalidate(inode); | 164 | nfs_fscache_invalidate(inode); |
167 | } else { | 165 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR |
168 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; | 166 | | NFS_INO_INVALID_LABEL |
169 | } | 167 | | NFS_INO_INVALID_DATA |
168 | | NFS_INO_INVALID_ACCESS | ||
169 | | NFS_INO_INVALID_ACL | ||
170 | | NFS_INO_REVAL_PAGECACHE; | ||
171 | } else | ||
172 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
173 | | NFS_INO_INVALID_LABEL | ||
174 | | NFS_INO_INVALID_ACCESS | ||
175 | | NFS_INO_INVALID_ACL | ||
176 | | NFS_INO_REVAL_PAGECACHE; | ||
170 | } | 177 | } |
171 | 178 | ||
172 | void nfs_zap_caches(struct inode *inode) | 179 | void nfs_zap_caches(struct inode *inode) |
@@ -257,12 +264,72 @@ nfs_init_locked(struct inode *inode, void *opaque) | |||
257 | return 0; | 264 | return 0; |
258 | } | 265 | } |
259 | 266 | ||
267 | #ifdef CONFIG_NFS_V4_SECURITY_LABEL | ||
268 | void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, | ||
269 | struct nfs4_label *label) | ||
270 | { | ||
271 | int error; | ||
272 | |||
273 | if (label == NULL) | ||
274 | return; | ||
275 | |||
276 | if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL) == 0) | ||
277 | return; | ||
278 | |||
279 | if (NFS_SERVER(inode)->nfs_client->cl_minorversion < 2) | ||
280 | return; | ||
281 | |||
282 | if ((fattr->valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL) && inode->i_security) { | ||
283 | error = security_inode_notifysecctx(inode, label->label, | ||
284 | label->len); | ||
285 | if (error) | ||
286 | printk(KERN_ERR "%s() %s %d " | ||
287 | "security_inode_notifysecctx() %d\n", | ||
288 | __func__, | ||
289 | (char *)label->label, | ||
290 | label->len, error); | ||
291 | } | ||
292 | } | ||
293 | |||
294 | struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) | ||
295 | { | ||
296 | struct nfs4_label *label = NULL; | ||
297 | int minor_version = server->nfs_client->cl_minorversion; | ||
298 | |||
299 | if (minor_version < 2) | ||
300 | return label; | ||
301 | |||
302 | if (!(server->caps & NFS_CAP_SECURITY_LABEL)) | ||
303 | return label; | ||
304 | |||
305 | label = kzalloc(sizeof(struct nfs4_label), flags); | ||
306 | if (label == NULL) | ||
307 | return ERR_PTR(-ENOMEM); | ||
308 | |||
309 | label->label = kzalloc(NFS4_MAXLABELLEN, flags); | ||
310 | if (label->label == NULL) { | ||
311 | kfree(label); | ||
312 | return ERR_PTR(-ENOMEM); | ||
313 | } | ||
314 | label->len = NFS4_MAXLABELLEN; | ||
315 | |||
316 | return label; | ||
317 | } | ||
318 | EXPORT_SYMBOL_GPL(nfs4_label_alloc); | ||
319 | #else | ||
320 | void inline nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, | ||
321 | struct nfs4_label *label) | ||
322 | { | ||
323 | } | ||
324 | #endif | ||
325 | EXPORT_SYMBOL_GPL(nfs_setsecurity); | ||
326 | |||
260 | /* | 327 | /* |
261 | * This is our front-end to iget that looks up inodes by file handle | 328 | * This is our front-end to iget that looks up inodes by file handle |
262 | * instead of inode number. | 329 | * instead of inode number. |
263 | */ | 330 | */ |
264 | struct inode * | 331 | struct inode * |
265 | nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | 332 | nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, struct nfs4_label *label) |
266 | { | 333 | { |
267 | struct nfs_find_desc desc = { | 334 | struct nfs_find_desc desc = { |
268 | .fh = fh, | 335 | .fh = fh, |
@@ -384,6 +451,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
384 | */ | 451 | */ |
385 | inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); | 452 | inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); |
386 | } | 453 | } |
454 | |||
455 | nfs_setsecurity(inode, fattr, label); | ||
456 | |||
387 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); | 457 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); |
388 | nfsi->attrtimeo_timestamp = now; | 458 | nfsi->attrtimeo_timestamp = now; |
389 | nfsi->access_cache = RB_ROOT; | 459 | nfsi->access_cache = RB_ROOT; |
@@ -449,7 +519,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
449 | NFS_PROTO(inode)->return_delegation(inode); | 519 | NFS_PROTO(inode)->return_delegation(inode); |
450 | error = NFS_PROTO(inode)->setattr(dentry, fattr, attr); | 520 | error = NFS_PROTO(inode)->setattr(dentry, fattr, attr); |
451 | if (error == 0) | 521 | if (error == 0) |
452 | nfs_refresh_inode(inode, fattr); | 522 | error = nfs_refresh_inode(inode, fattr); |
453 | nfs_free_fattr(fattr); | 523 | nfs_free_fattr(fattr); |
454 | out: | 524 | out: |
455 | return error; | 525 | return error; |
@@ -713,16 +783,23 @@ EXPORT_SYMBOL_GPL(put_nfs_open_context); | |||
713 | * Ensure that mmap has a recent RPC credential for use when writing out | 783 | * Ensure that mmap has a recent RPC credential for use when writing out |
714 | * shared pages | 784 | * shared pages |
715 | */ | 785 | */ |
716 | void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) | 786 | void nfs_inode_attach_open_context(struct nfs_open_context *ctx) |
717 | { | 787 | { |
718 | struct inode *inode = file_inode(filp); | 788 | struct inode *inode = ctx->dentry->d_inode; |
719 | struct nfs_inode *nfsi = NFS_I(inode); | 789 | struct nfs_inode *nfsi = NFS_I(inode); |
720 | 790 | ||
721 | filp->private_data = get_nfs_open_context(ctx); | ||
722 | spin_lock(&inode->i_lock); | 791 | spin_lock(&inode->i_lock); |
723 | list_add(&ctx->list, &nfsi->open_files); | 792 | list_add(&ctx->list, &nfsi->open_files); |
724 | spin_unlock(&inode->i_lock); | 793 | spin_unlock(&inode->i_lock); |
725 | } | 794 | } |
795 | EXPORT_SYMBOL_GPL(nfs_inode_attach_open_context); | ||
796 | |||
797 | void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) | ||
798 | { | ||
799 | filp->private_data = get_nfs_open_context(ctx); | ||
800 | if (list_empty(&ctx->list)) | ||
801 | nfs_inode_attach_open_context(ctx); | ||
802 | } | ||
726 | EXPORT_SYMBOL_GPL(nfs_file_set_open_context); | 803 | EXPORT_SYMBOL_GPL(nfs_file_set_open_context); |
727 | 804 | ||
728 | /* | 805 | /* |
@@ -748,10 +825,11 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c | |||
748 | 825 | ||
749 | static void nfs_file_clear_open_context(struct file *filp) | 826 | static void nfs_file_clear_open_context(struct file *filp) |
750 | { | 827 | { |
751 | struct inode *inode = file_inode(filp); | ||
752 | struct nfs_open_context *ctx = nfs_file_open_context(filp); | 828 | struct nfs_open_context *ctx = nfs_file_open_context(filp); |
753 | 829 | ||
754 | if (ctx) { | 830 | if (ctx) { |
831 | struct inode *inode = ctx->dentry->d_inode; | ||
832 | |||
755 | filp->private_data = NULL; | 833 | filp->private_data = NULL; |
756 | spin_lock(&inode->i_lock); | 834 | spin_lock(&inode->i_lock); |
757 | list_move_tail(&ctx->list, &NFS_I(inode)->open_files); | 835 | list_move_tail(&ctx->list, &NFS_I(inode)->open_files); |
@@ -790,6 +868,7 @@ int | |||
790 | __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | 868 | __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) |
791 | { | 869 | { |
792 | int status = -ESTALE; | 870 | int status = -ESTALE; |
871 | struct nfs4_label *label = NULL; | ||
793 | struct nfs_fattr *fattr = NULL; | 872 | struct nfs_fattr *fattr = NULL; |
794 | struct nfs_inode *nfsi = NFS_I(inode); | 873 | struct nfs_inode *nfsi = NFS_I(inode); |
795 | 874 | ||
@@ -807,7 +886,14 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
807 | goto out; | 886 | goto out; |
808 | 887 | ||
809 | nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); | 888 | nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); |
810 | status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr); | 889 | |
890 | label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL); | ||
891 | if (IS_ERR(label)) { | ||
892 | status = PTR_ERR(label); | ||
893 | goto out; | ||
894 | } | ||
895 | |||
896 | status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, label); | ||
811 | if (status != 0) { | 897 | if (status != 0) { |
812 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", | 898 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", |
813 | inode->i_sb->s_id, | 899 | inode->i_sb->s_id, |
@@ -817,7 +903,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
817 | if (!S_ISDIR(inode->i_mode)) | 903 | if (!S_ISDIR(inode->i_mode)) |
818 | set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); | 904 | set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); |
819 | } | 905 | } |
820 | goto out; | 906 | goto err_out; |
821 | } | 907 | } |
822 | 908 | ||
823 | status = nfs_refresh_inode(inode, fattr); | 909 | status = nfs_refresh_inode(inode, fattr); |
@@ -825,7 +911,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
825 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", | 911 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", |
826 | inode->i_sb->s_id, | 912 | inode->i_sb->s_id, |
827 | (long long)NFS_FILEID(inode), status); | 913 | (long long)NFS_FILEID(inode), status); |
828 | goto out; | 914 | goto err_out; |
829 | } | 915 | } |
830 | 916 | ||
831 | if (nfsi->cache_validity & NFS_INO_INVALID_ACL) | 917 | if (nfsi->cache_validity & NFS_INO_INVALID_ACL) |
@@ -835,7 +921,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
835 | inode->i_sb->s_id, | 921 | inode->i_sb->s_id, |
836 | (long long)NFS_FILEID(inode)); | 922 | (long long)NFS_FILEID(inode)); |
837 | 923 | ||
838 | out: | 924 | err_out: |
925 | nfs4_label_free(label); | ||
926 | out: | ||
839 | nfs_free_fattr(fattr); | 927 | nfs_free_fattr(fattr); |
840 | return status; | 928 | return status; |
841 | } | 929 | } |
@@ -847,7 +935,7 @@ int nfs_attribute_timeout(struct inode *inode) | |||
847 | return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); | 935 | return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); |
848 | } | 936 | } |
849 | 937 | ||
850 | static int nfs_attribute_cache_expired(struct inode *inode) | 938 | int nfs_attribute_cache_expired(struct inode *inode) |
851 | { | 939 | { |
852 | if (nfs_have_delegated_attributes(inode)) | 940 | if (nfs_have_delegated_attributes(inode)) |
853 | return 0; | 941 | return 0; |
@@ -863,7 +951,8 @@ static int nfs_attribute_cache_expired(struct inode *inode) | |||
863 | */ | 951 | */ |
864 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | 952 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) |
865 | { | 953 | { |
866 | if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR) | 954 | if (!(NFS_I(inode)->cache_validity & |
955 | (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) | ||
867 | && !nfs_attribute_cache_expired(inode)) | 956 | && !nfs_attribute_cache_expired(inode)) |
868 | return NFS_STALE(inode) ? -ESTALE : 0; | 957 | return NFS_STALE(inode) ? -ESTALE : 0; |
869 | return __nfs_revalidate_inode(server, inode); | 958 | return __nfs_revalidate_inode(server, inode); |
@@ -873,9 +962,15 @@ EXPORT_SYMBOL_GPL(nfs_revalidate_inode); | |||
873 | static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) | 962 | static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) |
874 | { | 963 | { |
875 | struct nfs_inode *nfsi = NFS_I(inode); | 964 | struct nfs_inode *nfsi = NFS_I(inode); |
876 | 965 | int ret; | |
966 | |||
877 | if (mapping->nrpages != 0) { | 967 | if (mapping->nrpages != 0) { |
878 | int ret = invalidate_inode_pages2(mapping); | 968 | if (S_ISREG(inode->i_mode)) { |
969 | ret = nfs_sync_mapping(mapping); | ||
970 | if (ret < 0) | ||
971 | return ret; | ||
972 | } | ||
973 | ret = invalidate_inode_pages2(mapping); | ||
879 | if (ret < 0) | 974 | if (ret < 0) |
880 | return ret; | 975 | return ret; |
881 | } | 976 | } |
@@ -1243,6 +1338,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1243 | spin_lock(&inode->i_lock); | 1338 | spin_lock(&inode->i_lock); |
1244 | status = nfs_post_op_update_inode_locked(inode, fattr); | 1339 | status = nfs_post_op_update_inode_locked(inode, fattr); |
1245 | spin_unlock(&inode->i_lock); | 1340 | spin_unlock(&inode->i_lock); |
1341 | |||
1246 | return status; | 1342 | return status; |
1247 | } | 1343 | } |
1248 | EXPORT_SYMBOL_GPL(nfs_post_op_update_inode); | 1344 | EXPORT_SYMBOL_GPL(nfs_post_op_update_inode); |
@@ -1483,7 +1579,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1483 | inode->i_blocks = fattr->du.nfs2.blocks; | 1579 | inode->i_blocks = fattr->du.nfs2.blocks; |
1484 | 1580 | ||
1485 | /* Update attrtimeo value if we're out of the unstable period */ | 1581 | /* Update attrtimeo value if we're out of the unstable period */ |
1486 | if (invalid & NFS_INO_INVALID_ATTR) { | 1582 | if (invalid & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) { |
1487 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); | 1583 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); |
1488 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); | 1584 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); |
1489 | nfsi->attrtimeo_timestamp = now; | 1585 | nfsi->attrtimeo_timestamp = now; |
@@ -1496,6 +1592,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1496 | } | 1592 | } |
1497 | } | 1593 | } |
1498 | invalid &= ~NFS_INO_INVALID_ATTR; | 1594 | invalid &= ~NFS_INO_INVALID_ATTR; |
1595 | invalid &= ~NFS_INO_INVALID_LABEL; | ||
1499 | /* Don't invalidate the data if we were to blame */ | 1596 | /* Don't invalidate the data if we were to blame */ |
1500 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) | 1597 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) |
1501 | || S_ISLNK(inode->i_mode))) | 1598 | || S_ISLNK(inode->i_mode))) |
@@ -1638,12 +1735,11 @@ EXPORT_SYMBOL_GPL(nfs_net_id); | |||
1638 | static int nfs_net_init(struct net *net) | 1735 | static int nfs_net_init(struct net *net) |
1639 | { | 1736 | { |
1640 | nfs_clients_init(net); | 1737 | nfs_clients_init(net); |
1641 | return nfs_dns_resolver_cache_init(net); | 1738 | return 0; |
1642 | } | 1739 | } |
1643 | 1740 | ||
1644 | static void nfs_net_exit(struct net *net) | 1741 | static void nfs_net_exit(struct net *net) |
1645 | { | 1742 | { |
1646 | nfs_dns_resolver_cache_destroy(net); | ||
1647 | nfs_cleanup_cb_ident_idr(net); | 1743 | nfs_cleanup_cb_ident_idr(net); |
1648 | } | 1744 | } |
1649 | 1745 | ||
@@ -1661,10 +1757,6 @@ static int __init init_nfs_fs(void) | |||
1661 | { | 1757 | { |
1662 | int err; | 1758 | int err; |
1663 | 1759 | ||
1664 | err = nfs_dns_resolver_init(); | ||
1665 | if (err < 0) | ||
1666 | goto out10;; | ||
1667 | |||
1668 | err = register_pernet_subsys(&nfs_net_ops); | 1760 | err = register_pernet_subsys(&nfs_net_ops); |
1669 | if (err < 0) | 1761 | if (err < 0) |
1670 | goto out9; | 1762 | goto out9; |
@@ -1730,8 +1822,6 @@ out7: | |||
1730 | out8: | 1822 | out8: |
1731 | unregister_pernet_subsys(&nfs_net_ops); | 1823 | unregister_pernet_subsys(&nfs_net_ops); |
1732 | out9: | 1824 | out9: |
1733 | nfs_dns_resolver_destroy(); | ||
1734 | out10: | ||
1735 | return err; | 1825 | return err; |
1736 | } | 1826 | } |
1737 | 1827 | ||
@@ -1744,7 +1834,6 @@ static void __exit exit_nfs_fs(void) | |||
1744 | nfs_destroy_nfspagecache(); | 1834 | nfs_destroy_nfspagecache(); |
1745 | nfs_fscache_unregister(); | 1835 | nfs_fscache_unregister(); |
1746 | unregister_pernet_subsys(&nfs_net_ops); | 1836 | unregister_pernet_subsys(&nfs_net_ops); |
1747 | nfs_dns_resolver_destroy(); | ||
1748 | #ifdef CONFIG_PROC_FS | 1837 | #ifdef CONFIG_PROC_FS |
1749 | rpc_proc_unregister(&init_net, "nfs"); | 1838 | rpc_proc_unregister(&init_net, "nfs"); |
1750 | #endif | 1839 | #endif |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 91e59a39fc08..3c8373f90ab3 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -165,7 +165,7 @@ extern void nfs_free_client(struct nfs_client *); | |||
165 | extern struct nfs_client *nfs4_find_client_ident(struct net *, int); | 165 | extern struct nfs_client *nfs4_find_client_ident(struct net *, int); |
166 | extern struct nfs_client * | 166 | extern struct nfs_client * |
167 | nfs4_find_client_sessionid(struct net *, const struct sockaddr *, | 167 | nfs4_find_client_sessionid(struct net *, const struct sockaddr *, |
168 | struct nfs4_sessionid *); | 168 | struct nfs4_sessionid *, u32); |
169 | extern struct nfs_server *nfs_create_server(struct nfs_mount_info *, | 169 | extern struct nfs_server *nfs_create_server(struct nfs_mount_info *, |
170 | struct nfs_subversion *); | 170 | struct nfs_subversion *); |
171 | extern struct nfs_server *nfs4_create_server( | 171 | extern struct nfs_server *nfs4_create_server( |
@@ -255,6 +255,7 @@ extern int nfs4_decode_dirent(struct xdr_stream *, | |||
255 | #ifdef CONFIG_NFS_V4_1 | 255 | #ifdef CONFIG_NFS_V4_1 |
256 | extern const u32 nfs41_maxread_overhead; | 256 | extern const u32 nfs41_maxread_overhead; |
257 | extern const u32 nfs41_maxwrite_overhead; | 257 | extern const u32 nfs41_maxwrite_overhead; |
258 | extern const u32 nfs41_maxgetdevinfo_overhead; | ||
258 | #endif | 259 | #endif |
259 | 260 | ||
260 | /* nfs4proc.c */ | 261 | /* nfs4proc.c */ |
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 91a6faf811ac..99a45283b9ee 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -139,7 +139,10 @@ struct mnt_fhstatus { | |||
139 | * nfs_mount - Obtain an NFS file handle for the given host and path | 139 | * nfs_mount - Obtain an NFS file handle for the given host and path |
140 | * @info: pointer to mount request arguments | 140 | * @info: pointer to mount request arguments |
141 | * | 141 | * |
142 | * Uses default timeout parameters specified by underlying transport. | 142 | * Uses default timeout parameters specified by underlying transport. On |
143 | * successful return, the auth_flavs list and auth_flav_len will be populated | ||
144 | * with the list from the server or a faked-up list if the server didn't | ||
145 | * provide one. | ||
143 | */ | 146 | */ |
144 | int nfs_mount(struct nfs_mount_request *info) | 147 | int nfs_mount(struct nfs_mount_request *info) |
145 | { | 148 | { |
@@ -195,6 +198,15 @@ int nfs_mount(struct nfs_mount_request *info) | |||
195 | dprintk("NFS: MNT request succeeded\n"); | 198 | dprintk("NFS: MNT request succeeded\n"); |
196 | status = 0; | 199 | status = 0; |
197 | 200 | ||
201 | /* | ||
202 | * If the server didn't provide a flavor list, allow the | ||
203 | * client to try any flavor. | ||
204 | */ | ||
205 | if (info->version != NFS_MNT3_VERSION || *info->auth_flav_len == 0) { | ||
206 | dprintk("NFS: Faking up auth_flavs list\n"); | ||
207 | info->auth_flavs[0] = RPC_AUTH_NULL; | ||
208 | *info->auth_flav_len = 1; | ||
209 | } | ||
198 | out: | 210 | out: |
199 | return status; | 211 | return status; |
200 | 212 | ||
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index fc8dc20fdeb9..348b535cd786 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -280,7 +280,7 @@ struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry, | |||
280 | struct dentry *parent = dget_parent(dentry); | 280 | struct dentry *parent = dget_parent(dentry); |
281 | 281 | ||
282 | /* Look it up again to get its attributes */ | 282 | /* Look it up again to get its attributes */ |
283 | err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr); | 283 | err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr, NULL); |
284 | dput(parent); | 284 | dput(parent); |
285 | if (err != 0) | 285 | if (err != 0) |
286 | return ERR_PTR(err); | 286 | return ERR_PTR(err); |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 43ea96ced28c..f5c84c3efbca 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -33,7 +33,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) | |||
33 | res = rpc_call_sync(clnt, msg, flags); | 33 | res = rpc_call_sync(clnt, msg, flags); |
34 | if (res != -EJUKEBOX) | 34 | if (res != -EJUKEBOX) |
35 | break; | 35 | break; |
36 | freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); | 36 | freezable_schedule_timeout_killable_unsafe(NFS_JUKEBOX_RETRY_TIME); |
37 | res = -ERESTARTSYS; | 37 | res = -ERESTARTSYS; |
38 | } while (!fatal_signal_pending(current)); | 38 | } while (!fatal_signal_pending(current)); |
39 | return res; | 39 | return res; |
@@ -98,7 +98,7 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
98 | */ | 98 | */ |
99 | static int | 99 | static int |
100 | nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | 100 | nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, |
101 | struct nfs_fattr *fattr) | 101 | struct nfs_fattr *fattr, struct nfs4_label *label) |
102 | { | 102 | { |
103 | struct rpc_message msg = { | 103 | struct rpc_message msg = { |
104 | .rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR], | 104 | .rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR], |
@@ -143,7 +143,8 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
143 | 143 | ||
144 | static int | 144 | static int |
145 | nfs3_proc_lookup(struct inode *dir, struct qstr *name, | 145 | nfs3_proc_lookup(struct inode *dir, struct qstr *name, |
146 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 146 | struct nfs_fh *fhandle, struct nfs_fattr *fattr, |
147 | struct nfs4_label *label) | ||
147 | { | 148 | { |
148 | struct nfs3_diropargs arg = { | 149 | struct nfs3_diropargs arg = { |
149 | .fh = NFS_FH(dir), | 150 | .fh = NFS_FH(dir), |
@@ -300,7 +301,7 @@ static int nfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_ | |||
300 | status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); | 301 | status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); |
301 | nfs_post_op_update_inode(dir, data->res.dir_attr); | 302 | nfs_post_op_update_inode(dir, data->res.dir_attr); |
302 | if (status == 0) | 303 | if (status == 0) |
303 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); | 304 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); |
304 | return status; | 305 | return status; |
305 | } | 306 | } |
306 | 307 | ||
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index a1dd768d0a35..ee81e354bce7 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -194,7 +194,7 @@ struct nfs4_state_recovery_ops { | |||
194 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); | 194 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); |
195 | int (*establish_clid)(struct nfs_client *, struct rpc_cred *); | 195 | int (*establish_clid)(struct nfs_client *, struct rpc_cred *); |
196 | struct rpc_cred * (*get_clid_cred)(struct nfs_client *); | 196 | struct rpc_cred * (*get_clid_cred)(struct nfs_client *); |
197 | int (*reclaim_complete)(struct nfs_client *); | 197 | int (*reclaim_complete)(struct nfs_client *, struct rpc_cred *); |
198 | int (*detect_trunking)(struct nfs_client *, struct nfs_client **, | 198 | int (*detect_trunking)(struct nfs_client *, struct nfs_client **, |
199 | struct rpc_cred *); | 199 | struct rpc_cred *); |
200 | }; | 200 | }; |
@@ -303,10 +303,10 @@ is_ds_client(struct nfs_client *clp) | |||
303 | extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[]; | 303 | extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[]; |
304 | 304 | ||
305 | extern const u32 nfs4_fattr_bitmap[3]; | 305 | extern const u32 nfs4_fattr_bitmap[3]; |
306 | extern const u32 nfs4_statfs_bitmap[2]; | 306 | extern const u32 nfs4_statfs_bitmap[3]; |
307 | extern const u32 nfs4_pathconf_bitmap[2]; | 307 | extern const u32 nfs4_pathconf_bitmap[3]; |
308 | extern const u32 nfs4_fsinfo_bitmap[3]; | 308 | extern const u32 nfs4_fsinfo_bitmap[3]; |
309 | extern const u32 nfs4_fs_locations_bitmap[2]; | 309 | extern const u32 nfs4_fs_locations_bitmap[3]; |
310 | 310 | ||
311 | void nfs4_free_client(struct nfs_client *); | 311 | void nfs4_free_client(struct nfs_client *); |
312 | 312 | ||
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 4cbad5d6b276..90dce91dd5b5 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
@@ -66,6 +66,11 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init) | |||
66 | if (err) | 66 | if (err) |
67 | goto error; | 67 | goto error; |
68 | 68 | ||
69 | if (cl_init->minorversion > NFS4_MAX_MINOR_VERSION) { | ||
70 | err = -EINVAL; | ||
71 | goto error; | ||
72 | } | ||
73 | |||
69 | spin_lock_init(&clp->cl_lock); | 74 | spin_lock_init(&clp->cl_lock); |
70 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); | 75 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); |
71 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | 76 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); |
@@ -562,14 +567,14 @@ static bool nfs4_cb_match_client(const struct sockaddr *addr, | |||
562 | */ | 567 | */ |
563 | struct nfs_client * | 568 | struct nfs_client * |
564 | nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, | 569 | nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, |
565 | struct nfs4_sessionid *sid) | 570 | struct nfs4_sessionid *sid, u32 minorversion) |
566 | { | 571 | { |
567 | struct nfs_client *clp; | 572 | struct nfs_client *clp; |
568 | struct nfs_net *nn = net_generic(net, nfs_net_id); | 573 | struct nfs_net *nn = net_generic(net, nfs_net_id); |
569 | 574 | ||
570 | spin_lock(&nn->nfs_client_lock); | 575 | spin_lock(&nn->nfs_client_lock); |
571 | list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { | 576 | list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { |
572 | if (nfs4_cb_match_client(addr, clp, 1) == false) | 577 | if (nfs4_cb_match_client(addr, clp, minorversion) == false) |
573 | continue; | 578 | continue; |
574 | 579 | ||
575 | if (!nfs4_has_session(clp)) | 580 | if (!nfs4_has_session(clp)) |
@@ -592,7 +597,7 @@ nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, | |||
592 | 597 | ||
593 | struct nfs_client * | 598 | struct nfs_client * |
594 | nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, | 599 | nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, |
595 | struct nfs4_sessionid *sid) | 600 | struct nfs4_sessionid *sid, u32 minorversion) |
596 | { | 601 | { |
597 | return NULL; | 602 | return NULL; |
598 | } | 603 | } |
@@ -626,6 +631,8 @@ static int nfs4_set_client(struct nfs_server *server, | |||
626 | 631 | ||
627 | if (server->flags & NFS_MOUNT_NORESVPORT) | 632 | if (server->flags & NFS_MOUNT_NORESVPORT) |
628 | set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); | 633 | set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); |
634 | if (server->options & NFS_OPTION_MIGRATION) | ||
635 | set_bit(NFS_CS_MIGRATION, &cl_init.init_flags); | ||
629 | 636 | ||
630 | /* Allocate or find a client reference we can use */ | 637 | /* Allocate or find a client reference we can use */ |
631 | clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour); | 638 | clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour); |
@@ -730,7 +737,7 @@ static int nfs4_server_common_setup(struct nfs_server *server, | |||
730 | return -ENOMEM; | 737 | return -ENOMEM; |
731 | 738 | ||
732 | /* We must ensure the session is initialised first */ | 739 | /* We must ensure the session is initialised first */ |
733 | error = nfs4_init_session(server); | 740 | error = nfs4_init_session(server->nfs_client); |
734 | if (error < 0) | 741 | if (error < 0) |
735 | goto out; | 742 | goto out; |
736 | 743 | ||
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 13e6bb3e3fe5..e5b804dd944c 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c | |||
@@ -69,7 +69,6 @@ nfs4_file_open(struct inode *inode, struct file *filp) | |||
69 | goto out_drop; | 69 | goto out_drop; |
70 | } | 70 | } |
71 | } | 71 | } |
72 | iput(inode); | ||
73 | if (inode != dentry->d_inode) | 72 | if (inode != dentry->d_inode) |
74 | goto out_drop; | 73 | goto out_drop; |
75 | 74 | ||
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 22d10623f5ee..17ed87ef9de8 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -643,7 +643,8 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo, | |||
643 | d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode)->pnfs_curr_ld, | 643 | d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode)->pnfs_curr_ld, |
644 | NFS_SERVER(lo->plh_inode)->nfs_client, id); | 644 | NFS_SERVER(lo->plh_inode)->nfs_client, id); |
645 | if (d == NULL) { | 645 | if (d == NULL) { |
646 | dsaddr = filelayout_get_device_info(lo->plh_inode, id, gfp_flags); | 646 | dsaddr = filelayout_get_device_info(lo->plh_inode, id, |
647 | lo->plh_lc_cred, gfp_flags); | ||
647 | if (dsaddr == NULL) | 648 | if (dsaddr == NULL) |
648 | goto out; | 649 | goto out; |
649 | } else | 650 | } else |
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h index 235ff952d3c8..cebd20e7e923 100644 --- a/fs/nfs/nfs4filelayout.h +++ b/fs/nfs/nfs4filelayout.h | |||
@@ -150,6 +150,7 @@ struct nfs4_pnfs_ds *nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, | |||
150 | extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr); | 150 | extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr); |
151 | extern void nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr); | 151 | extern void nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr); |
152 | struct nfs4_file_layout_dsaddr * | 152 | struct nfs4_file_layout_dsaddr * |
153 | filelayout_get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags); | 153 | filelayout_get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, |
154 | struct rpc_cred *cred, gfp_t gfp_flags); | ||
154 | 155 | ||
155 | #endif /* FS_NFS_NFS4FILELAYOUT_H */ | 156 | #endif /* FS_NFS_NFS4FILELAYOUT_H */ |
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index 661a0f611215..95604f64cab8 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c | |||
@@ -668,7 +668,10 @@ decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_fl | |||
668 | * of available devices, and return it. | 668 | * of available devices, and return it. |
669 | */ | 669 | */ |
670 | struct nfs4_file_layout_dsaddr * | 670 | struct nfs4_file_layout_dsaddr * |
671 | filelayout_get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags) | 671 | filelayout_get_device_info(struct inode *inode, |
672 | struct nfs4_deviceid *dev_id, | ||
673 | struct rpc_cred *cred, | ||
674 | gfp_t gfp_flags) | ||
672 | { | 675 | { |
673 | struct pnfs_device *pdev = NULL; | 676 | struct pnfs_device *pdev = NULL; |
674 | u32 max_resp_sz; | 677 | u32 max_resp_sz; |
@@ -708,8 +711,9 @@ filelayout_get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gf | |||
708 | pdev->pgbase = 0; | 711 | pdev->pgbase = 0; |
709 | pdev->pglen = max_resp_sz; | 712 | pdev->pglen = max_resp_sz; |
710 | pdev->mincount = 0; | 713 | pdev->mincount = 0; |
714 | pdev->maxcount = max_resp_sz - nfs41_maxgetdevinfo_overhead; | ||
711 | 715 | ||
712 | rc = nfs4_proc_getdeviceinfo(server, pdev); | 716 | rc = nfs4_proc_getdeviceinfo(server, pdev, cred); |
713 | dprintk("%s getdevice info returns %d\n", __func__, rc); | 717 | dprintk("%s getdevice info returns %d\n", __func__, rc); |
714 | if (rc) | 718 | if (rc) |
715 | goto out_free; | 719 | goto out_free; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d7ba5616989c..108a774095f7 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -77,15 +77,68 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data); | |||
77 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 77 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
78 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); | 78 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); |
79 | static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr); | 79 | static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr); |
80 | static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *); | 80 | static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label); |
81 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 81 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label); |
82 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | 82 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, |
83 | struct nfs_fattr *fattr, struct iattr *sattr, | 83 | struct nfs_fattr *fattr, struct iattr *sattr, |
84 | struct nfs4_state *state); | 84 | struct nfs4_state *state, struct nfs4_label *ilabel, |
85 | struct nfs4_label *olabel); | ||
85 | #ifdef CONFIG_NFS_V4_1 | 86 | #ifdef CONFIG_NFS_V4_1 |
86 | static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *); | 87 | static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *, |
87 | static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *); | 88 | struct rpc_cred *); |
89 | static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *, | ||
90 | struct rpc_cred *); | ||
88 | #endif | 91 | #endif |
92 | |||
93 | #ifdef CONFIG_NFS_V4_SECURITY_LABEL | ||
94 | static inline struct nfs4_label * | ||
95 | nfs4_label_init_security(struct inode *dir, struct dentry *dentry, | ||
96 | struct iattr *sattr, struct nfs4_label *label) | ||
97 | { | ||
98 | int err; | ||
99 | |||
100 | if (label == NULL) | ||
101 | return NULL; | ||
102 | |||
103 | if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL) == 0) | ||
104 | return NULL; | ||
105 | |||
106 | if (NFS_SERVER(dir)->nfs_client->cl_minorversion < 2) | ||
107 | return NULL; | ||
108 | |||
109 | err = security_dentry_init_security(dentry, sattr->ia_mode, | ||
110 | &dentry->d_name, (void **)&label->label, &label->len); | ||
111 | if (err == 0) | ||
112 | return label; | ||
113 | |||
114 | return NULL; | ||
115 | } | ||
116 | static inline void | ||
117 | nfs4_label_release_security(struct nfs4_label *label) | ||
118 | { | ||
119 | if (label) | ||
120 | security_release_secctx(label->label, label->len); | ||
121 | } | ||
122 | static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label) | ||
123 | { | ||
124 | if (label) | ||
125 | return server->attr_bitmask; | ||
126 | |||
127 | return server->attr_bitmask_nl; | ||
128 | } | ||
129 | #else | ||
130 | static inline struct nfs4_label * | ||
131 | nfs4_label_init_security(struct inode *dir, struct dentry *dentry, | ||
132 | struct iattr *sattr, struct nfs4_label *l) | ||
133 | { return NULL; } | ||
134 | static inline void | ||
135 | nfs4_label_release_security(struct nfs4_label *label) | ||
136 | { return; } | ||
137 | static inline u32 * | ||
138 | nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label) | ||
139 | { return server->attr_bitmask; } | ||
140 | #endif | ||
141 | |||
89 | /* Prevent leaks of NFSv4 errors into userland */ | 142 | /* Prevent leaks of NFSv4 errors into userland */ |
90 | static int nfs4_map_errors(int err) | 143 | static int nfs4_map_errors(int err) |
91 | { | 144 | { |
@@ -134,7 +187,10 @@ const u32 nfs4_fattr_bitmap[3] = { | |||
134 | | FATTR4_WORD1_SPACE_USED | 187 | | FATTR4_WORD1_SPACE_USED |
135 | | FATTR4_WORD1_TIME_ACCESS | 188 | | FATTR4_WORD1_TIME_ACCESS |
136 | | FATTR4_WORD1_TIME_METADATA | 189 | | FATTR4_WORD1_TIME_METADATA |
137 | | FATTR4_WORD1_TIME_MODIFY | 190 | | FATTR4_WORD1_TIME_MODIFY, |
191 | #ifdef CONFIG_NFS_V4_SECURITY_LABEL | ||
192 | FATTR4_WORD2_SECURITY_LABEL | ||
193 | #endif | ||
138 | }; | 194 | }; |
139 | 195 | ||
140 | static const u32 nfs4_pnfs_open_bitmap[3] = { | 196 | static const u32 nfs4_pnfs_open_bitmap[3] = { |
@@ -161,7 +217,7 @@ static const u32 nfs4_open_noattr_bitmap[3] = { | |||
161 | | FATTR4_WORD0_FILEID, | 217 | | FATTR4_WORD0_FILEID, |
162 | }; | 218 | }; |
163 | 219 | ||
164 | const u32 nfs4_statfs_bitmap[2] = { | 220 | const u32 nfs4_statfs_bitmap[3] = { |
165 | FATTR4_WORD0_FILES_AVAIL | 221 | FATTR4_WORD0_FILES_AVAIL |
166 | | FATTR4_WORD0_FILES_FREE | 222 | | FATTR4_WORD0_FILES_FREE |
167 | | FATTR4_WORD0_FILES_TOTAL, | 223 | | FATTR4_WORD0_FILES_TOTAL, |
@@ -170,7 +226,7 @@ const u32 nfs4_statfs_bitmap[2] = { | |||
170 | | FATTR4_WORD1_SPACE_TOTAL | 226 | | FATTR4_WORD1_SPACE_TOTAL |
171 | }; | 227 | }; |
172 | 228 | ||
173 | const u32 nfs4_pathconf_bitmap[2] = { | 229 | const u32 nfs4_pathconf_bitmap[3] = { |
174 | FATTR4_WORD0_MAXLINK | 230 | FATTR4_WORD0_MAXLINK |
175 | | FATTR4_WORD0_MAXNAME, | 231 | | FATTR4_WORD0_MAXNAME, |
176 | 0 | 232 | 0 |
@@ -185,7 +241,7 @@ const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE | |||
185 | FATTR4_WORD2_LAYOUT_BLKSIZE | 241 | FATTR4_WORD2_LAYOUT_BLKSIZE |
186 | }; | 242 | }; |
187 | 243 | ||
188 | const u32 nfs4_fs_locations_bitmap[2] = { | 244 | const u32 nfs4_fs_locations_bitmap[3] = { |
189 | FATTR4_WORD0_TYPE | 245 | FATTR4_WORD0_TYPE |
190 | | FATTR4_WORD0_CHANGE | 246 | | FATTR4_WORD0_CHANGE |
191 | | FATTR4_WORD0_SIZE | 247 | | FATTR4_WORD0_SIZE |
@@ -201,7 +257,7 @@ const u32 nfs4_fs_locations_bitmap[2] = { | |||
201 | | FATTR4_WORD1_TIME_ACCESS | 257 | | FATTR4_WORD1_TIME_ACCESS |
202 | | FATTR4_WORD1_TIME_METADATA | 258 | | FATTR4_WORD1_TIME_METADATA |
203 | | FATTR4_WORD1_TIME_MODIFY | 259 | | FATTR4_WORD1_TIME_MODIFY |
204 | | FATTR4_WORD1_MOUNTED_ON_FILEID | 260 | | FATTR4_WORD1_MOUNTED_ON_FILEID, |
205 | }; | 261 | }; |
206 | 262 | ||
207 | static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry, | 263 | static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry, |
@@ -268,7 +324,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | |||
268 | *timeout = NFS4_POLL_RETRY_MIN; | 324 | *timeout = NFS4_POLL_RETRY_MIN; |
269 | if (*timeout > NFS4_POLL_RETRY_MAX) | 325 | if (*timeout > NFS4_POLL_RETRY_MAX) |
270 | *timeout = NFS4_POLL_RETRY_MAX; | 326 | *timeout = NFS4_POLL_RETRY_MAX; |
271 | freezable_schedule_timeout_killable(*timeout); | 327 | freezable_schedule_timeout_killable_unsafe(*timeout); |
272 | if (fatal_signal_pending(current)) | 328 | if (fatal_signal_pending(current)) |
273 | res = -ERESTARTSYS; | 329 | res = -ERESTARTSYS; |
274 | *timeout <<= 1; | 330 | *timeout <<= 1; |
@@ -762,6 +818,7 @@ struct nfs4_opendata { | |||
762 | struct nfs4_string owner_name; | 818 | struct nfs4_string owner_name; |
763 | struct nfs4_string group_name; | 819 | struct nfs4_string group_name; |
764 | struct nfs_fattr f_attr; | 820 | struct nfs_fattr f_attr; |
821 | struct nfs4_label *f_label; | ||
765 | struct dentry *dir; | 822 | struct dentry *dir; |
766 | struct dentry *dentry; | 823 | struct dentry *dentry; |
767 | struct nfs4_state_owner *owner; | 824 | struct nfs4_state_owner *owner; |
@@ -807,6 +864,7 @@ nfs4_map_atomic_open_claim(struct nfs_server *server, | |||
807 | static void nfs4_init_opendata_res(struct nfs4_opendata *p) | 864 | static void nfs4_init_opendata_res(struct nfs4_opendata *p) |
808 | { | 865 | { |
809 | p->o_res.f_attr = &p->f_attr; | 866 | p->o_res.f_attr = &p->f_attr; |
867 | p->o_res.f_label = p->f_label; | ||
810 | p->o_res.seqid = p->o_arg.seqid; | 868 | p->o_res.seqid = p->o_arg.seqid; |
811 | p->c_res.seqid = p->c_arg.seqid; | 869 | p->c_res.seqid = p->c_arg.seqid; |
812 | p->o_res.server = p->o_arg.server; | 870 | p->o_res.server = p->o_arg.server; |
@@ -818,6 +876,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
818 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | 876 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, |
819 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, | 877 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, |
820 | const struct iattr *attrs, | 878 | const struct iattr *attrs, |
879 | struct nfs4_label *label, | ||
821 | enum open_claim_type4 claim, | 880 | enum open_claim_type4 claim, |
822 | gfp_t gfp_mask) | 881 | gfp_t gfp_mask) |
823 | { | 882 | { |
@@ -829,9 +888,14 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
829 | p = kzalloc(sizeof(*p), gfp_mask); | 888 | p = kzalloc(sizeof(*p), gfp_mask); |
830 | if (p == NULL) | 889 | if (p == NULL) |
831 | goto err; | 890 | goto err; |
891 | |||
892 | p->f_label = nfs4_label_alloc(server, gfp_mask); | ||
893 | if (IS_ERR(p->f_label)) | ||
894 | goto err_free_p; | ||
895 | |||
832 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask); | 896 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask); |
833 | if (p->o_arg.seqid == NULL) | 897 | if (p->o_arg.seqid == NULL) |
834 | goto err_free; | 898 | goto err_free_label; |
835 | nfs_sb_active(dentry->d_sb); | 899 | nfs_sb_active(dentry->d_sb); |
836 | p->dentry = dget(dentry); | 900 | p->dentry = dget(dentry); |
837 | p->dir = parent; | 901 | p->dir = parent; |
@@ -852,8 +916,9 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
852 | p->o_arg.id.uniquifier = sp->so_seqid.owner_id; | 916 | p->o_arg.id.uniquifier = sp->so_seqid.owner_id; |
853 | p->o_arg.name = &dentry->d_name; | 917 | p->o_arg.name = &dentry->d_name; |
854 | p->o_arg.server = server; | 918 | p->o_arg.server = server; |
855 | p->o_arg.bitmask = server->attr_bitmask; | 919 | p->o_arg.bitmask = nfs4_bitmask(server, label); |
856 | p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0]; | 920 | p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0]; |
921 | p->o_arg.label = label; | ||
857 | p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim); | 922 | p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim); |
858 | switch (p->o_arg.claim) { | 923 | switch (p->o_arg.claim) { |
859 | case NFS4_OPEN_CLAIM_NULL: | 924 | case NFS4_OPEN_CLAIM_NULL: |
@@ -884,7 +949,10 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
884 | nfs4_init_opendata_res(p); | 949 | nfs4_init_opendata_res(p); |
885 | kref_init(&p->kref); | 950 | kref_init(&p->kref); |
886 | return p; | 951 | return p; |
887 | err_free: | 952 | |
953 | err_free_label: | ||
954 | nfs4_label_free(p->f_label); | ||
955 | err_free_p: | ||
888 | kfree(p); | 956 | kfree(p); |
889 | err: | 957 | err: |
890 | dput(parent); | 958 | dput(parent); |
@@ -901,6 +969,9 @@ static void nfs4_opendata_free(struct kref *kref) | |||
901 | if (p->state != NULL) | 969 | if (p->state != NULL) |
902 | nfs4_put_open_state(p->state); | 970 | nfs4_put_open_state(p->state); |
903 | nfs4_put_state_owner(p->owner); | 971 | nfs4_put_state_owner(p->owner); |
972 | |||
973 | nfs4_label_free(p->f_label); | ||
974 | |||
904 | dput(p->dir); | 975 | dput(p->dir); |
905 | dput(p->dentry); | 976 | dput(p->dentry); |
906 | nfs_sb_deactive(sb); | 977 | nfs_sb_deactive(sb); |
@@ -1179,6 +1250,8 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data) | |||
1179 | if (ret) | 1250 | if (ret) |
1180 | goto err; | 1251 | goto err; |
1181 | 1252 | ||
1253 | nfs_setsecurity(inode, &data->f_attr, data->f_label); | ||
1254 | |||
1182 | if (data->o_res.delegation_type != 0) | 1255 | if (data->o_res.delegation_type != 0) |
1183 | nfs4_opendata_check_deleg(data, state); | 1256 | nfs4_opendata_check_deleg(data, state); |
1184 | update_open_stateid(state, &data->o_res.stateid, NULL, | 1257 | update_open_stateid(state, &data->o_res.stateid, NULL, |
@@ -1205,7 +1278,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) | |||
1205 | ret = -EAGAIN; | 1278 | ret = -EAGAIN; |
1206 | if (!(data->f_attr.valid & NFS_ATTR_FATTR)) | 1279 | if (!(data->f_attr.valid & NFS_ATTR_FATTR)) |
1207 | goto err; | 1280 | goto err; |
1208 | inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr); | 1281 | inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr, data->f_label); |
1209 | ret = PTR_ERR(inode); | 1282 | ret = PTR_ERR(inode); |
1210 | if (IS_ERR(inode)) | 1283 | if (IS_ERR(inode)) |
1211 | goto err; | 1284 | goto err; |
@@ -1258,7 +1331,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context | |||
1258 | struct nfs4_opendata *opendata; | 1331 | struct nfs4_opendata *opendata; |
1259 | 1332 | ||
1260 | opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, | 1333 | opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, |
1261 | NULL, claim, GFP_NOFS); | 1334 | NULL, NULL, claim, GFP_NOFS); |
1262 | if (opendata == NULL) | 1335 | if (opendata == NULL) |
1263 | return ERR_PTR(-ENOMEM); | 1336 | return ERR_PTR(-ENOMEM); |
1264 | opendata->state = state; | 1337 | opendata->state = state; |
@@ -1784,7 +1857,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
1784 | return status; | 1857 | return status; |
1785 | } | 1858 | } |
1786 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) | 1859 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) |
1787 | _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr); | 1860 | _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr, o_res->f_label); |
1788 | return 0; | 1861 | return 0; |
1789 | } | 1862 | } |
1790 | 1863 | ||
@@ -1855,18 +1928,30 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state) | |||
1855 | { | 1928 | { |
1856 | struct nfs_server *server = NFS_SERVER(state->inode); | 1929 | struct nfs_server *server = NFS_SERVER(state->inode); |
1857 | nfs4_stateid *stateid = &state->stateid; | 1930 | nfs4_stateid *stateid = &state->stateid; |
1858 | int status; | 1931 | struct nfs_delegation *delegation; |
1932 | struct rpc_cred *cred = NULL; | ||
1933 | int status = -NFS4ERR_BAD_STATEID; | ||
1859 | 1934 | ||
1860 | /* If a state reset has been done, test_stateid is unneeded */ | 1935 | /* If a state reset has been done, test_stateid is unneeded */ |
1861 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | 1936 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
1862 | return; | 1937 | return; |
1863 | 1938 | ||
1864 | status = nfs41_test_stateid(server, stateid); | 1939 | /* Get the delegation credential for use by test/free_stateid */ |
1940 | rcu_read_lock(); | ||
1941 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); | ||
1942 | if (delegation != NULL && | ||
1943 | nfs4_stateid_match(&delegation->stateid, stateid)) { | ||
1944 | cred = get_rpccred(delegation->cred); | ||
1945 | rcu_read_unlock(); | ||
1946 | status = nfs41_test_stateid(server, stateid, cred); | ||
1947 | } else | ||
1948 | rcu_read_unlock(); | ||
1949 | |||
1865 | if (status != NFS_OK) { | 1950 | if (status != NFS_OK) { |
1866 | /* Free the stateid unless the server explicitly | 1951 | /* Free the stateid unless the server explicitly |
1867 | * informs us the stateid is unrecognized. */ | 1952 | * informs us the stateid is unrecognized. */ |
1868 | if (status != -NFS4ERR_BAD_STATEID) | 1953 | if (status != -NFS4ERR_BAD_STATEID) |
1869 | nfs41_free_stateid(server, stateid); | 1954 | nfs41_free_stateid(server, stateid, cred); |
1870 | nfs_remove_bad_delegation(state->inode); | 1955 | nfs_remove_bad_delegation(state->inode); |
1871 | 1956 | ||
1872 | write_seqlock(&state->seqlock); | 1957 | write_seqlock(&state->seqlock); |
@@ -1874,6 +1959,9 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state) | |||
1874 | write_sequnlock(&state->seqlock); | 1959 | write_sequnlock(&state->seqlock); |
1875 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 1960 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
1876 | } | 1961 | } |
1962 | |||
1963 | if (cred != NULL) | ||
1964 | put_rpccred(cred); | ||
1877 | } | 1965 | } |
1878 | 1966 | ||
1879 | /** | 1967 | /** |
@@ -1888,6 +1976,7 @@ static int nfs41_check_open_stateid(struct nfs4_state *state) | |||
1888 | { | 1976 | { |
1889 | struct nfs_server *server = NFS_SERVER(state->inode); | 1977 | struct nfs_server *server = NFS_SERVER(state->inode); |
1890 | nfs4_stateid *stateid = &state->open_stateid; | 1978 | nfs4_stateid *stateid = &state->open_stateid; |
1979 | struct rpc_cred *cred = state->owner->so_cred; | ||
1891 | int status; | 1980 | int status; |
1892 | 1981 | ||
1893 | /* If a state reset has been done, test_stateid is unneeded */ | 1982 | /* If a state reset has been done, test_stateid is unneeded */ |
@@ -1896,12 +1985,12 @@ static int nfs41_check_open_stateid(struct nfs4_state *state) | |||
1896 | (test_bit(NFS_O_RDWR_STATE, &state->flags) == 0)) | 1985 | (test_bit(NFS_O_RDWR_STATE, &state->flags) == 0)) |
1897 | return -NFS4ERR_BAD_STATEID; | 1986 | return -NFS4ERR_BAD_STATEID; |
1898 | 1987 | ||
1899 | status = nfs41_test_stateid(server, stateid); | 1988 | status = nfs41_test_stateid(server, stateid, cred); |
1900 | if (status != NFS_OK) { | 1989 | if (status != NFS_OK) { |
1901 | /* Free the stateid unless the server explicitly | 1990 | /* Free the stateid unless the server explicitly |
1902 | * informs us the stateid is unrecognized. */ | 1991 | * informs us the stateid is unrecognized. */ |
1903 | if (status != -NFS4ERR_BAD_STATEID) | 1992 | if (status != -NFS4ERR_BAD_STATEID) |
1904 | nfs41_free_stateid(server, stateid); | 1993 | nfs41_free_stateid(server, stateid, cred); |
1905 | 1994 | ||
1906 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | 1995 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); |
1907 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | 1996 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); |
@@ -1942,10 +2031,11 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct | |||
1942 | static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, | 2031 | static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, |
1943 | fmode_t fmode, | 2032 | fmode_t fmode, |
1944 | int flags, | 2033 | int flags, |
1945 | struct nfs4_state **res) | 2034 | struct nfs_open_context *ctx) |
1946 | { | 2035 | { |
1947 | struct nfs4_state_owner *sp = opendata->owner; | 2036 | struct nfs4_state_owner *sp = opendata->owner; |
1948 | struct nfs_server *server = sp->so_server; | 2037 | struct nfs_server *server = sp->so_server; |
2038 | struct dentry *dentry; | ||
1949 | struct nfs4_state *state; | 2039 | struct nfs4_state *state; |
1950 | unsigned int seq; | 2040 | unsigned int seq; |
1951 | int ret; | 2041 | int ret; |
@@ -1963,13 +2053,31 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, | |||
1963 | if (server->caps & NFS_CAP_POSIX_LOCK) | 2053 | if (server->caps & NFS_CAP_POSIX_LOCK) |
1964 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); | 2054 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); |
1965 | 2055 | ||
2056 | dentry = opendata->dentry; | ||
2057 | if (dentry->d_inode == NULL) { | ||
2058 | /* FIXME: Is this d_drop() ever needed? */ | ||
2059 | d_drop(dentry); | ||
2060 | dentry = d_add_unique(dentry, igrab(state->inode)); | ||
2061 | if (dentry == NULL) { | ||
2062 | dentry = opendata->dentry; | ||
2063 | } else if (dentry != ctx->dentry) { | ||
2064 | dput(ctx->dentry); | ||
2065 | ctx->dentry = dget(dentry); | ||
2066 | } | ||
2067 | nfs_set_verifier(dentry, | ||
2068 | nfs_save_change_attribute(opendata->dir->d_inode)); | ||
2069 | } | ||
2070 | |||
1966 | ret = nfs4_opendata_access(sp->so_cred, opendata, state, fmode, flags); | 2071 | ret = nfs4_opendata_access(sp->so_cred, opendata, state, fmode, flags); |
1967 | if (ret != 0) | 2072 | if (ret != 0) |
1968 | goto out; | 2073 | goto out; |
1969 | 2074 | ||
1970 | if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) | 2075 | ctx->state = state; |
1971 | nfs4_schedule_stateid_recovery(server, state); | 2076 | if (dentry->d_inode == state->inode) { |
1972 | *res = state; | 2077 | nfs_inode_attach_open_context(ctx); |
2078 | if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) | ||
2079 | nfs4_schedule_stateid_recovery(server, state); | ||
2080 | } | ||
1973 | out: | 2081 | out: |
1974 | return ret; | 2082 | return ret; |
1975 | } | 2083 | } |
@@ -1978,19 +2086,21 @@ out: | |||
1978 | * Returns a referenced nfs4_state | 2086 | * Returns a referenced nfs4_state |
1979 | */ | 2087 | */ |
1980 | static int _nfs4_do_open(struct inode *dir, | 2088 | static int _nfs4_do_open(struct inode *dir, |
1981 | struct dentry *dentry, | 2089 | struct nfs_open_context *ctx, |
1982 | fmode_t fmode, | ||
1983 | int flags, | 2090 | int flags, |
1984 | struct iattr *sattr, | 2091 | struct iattr *sattr, |
1985 | struct rpc_cred *cred, | 2092 | struct nfs4_label *label) |
1986 | struct nfs4_state **res, | ||
1987 | struct nfs4_threshold **ctx_th) | ||
1988 | { | 2093 | { |
1989 | struct nfs4_state_owner *sp; | 2094 | struct nfs4_state_owner *sp; |
1990 | struct nfs4_state *state = NULL; | 2095 | struct nfs4_state *state = NULL; |
1991 | struct nfs_server *server = NFS_SERVER(dir); | 2096 | struct nfs_server *server = NFS_SERVER(dir); |
1992 | struct nfs4_opendata *opendata; | 2097 | struct nfs4_opendata *opendata; |
2098 | struct dentry *dentry = ctx->dentry; | ||
2099 | struct rpc_cred *cred = ctx->cred; | ||
2100 | struct nfs4_threshold **ctx_th = &ctx->mdsthreshold; | ||
2101 | fmode_t fmode = ctx->mode & (FMODE_READ|FMODE_WRITE|FMODE_EXEC); | ||
1993 | enum open_claim_type4 claim = NFS4_OPEN_CLAIM_NULL; | 2102 | enum open_claim_type4 claim = NFS4_OPEN_CLAIM_NULL; |
2103 | struct nfs4_label *olabel = NULL; | ||
1994 | int status; | 2104 | int status; |
1995 | 2105 | ||
1996 | /* Protect against reboot recovery conflicts */ | 2106 | /* Protect against reboot recovery conflicts */ |
@@ -2009,22 +2119,31 @@ static int _nfs4_do_open(struct inode *dir, | |||
2009 | if (dentry->d_inode) | 2119 | if (dentry->d_inode) |
2010 | claim = NFS4_OPEN_CLAIM_FH; | 2120 | claim = NFS4_OPEN_CLAIM_FH; |
2011 | opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, | 2121 | opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, |
2012 | claim, GFP_KERNEL); | 2122 | label, claim, GFP_KERNEL); |
2013 | if (opendata == NULL) | 2123 | if (opendata == NULL) |
2014 | goto err_put_state_owner; | 2124 | goto err_put_state_owner; |
2015 | 2125 | ||
2126 | if (label) { | ||
2127 | olabel = nfs4_label_alloc(server, GFP_KERNEL); | ||
2128 | if (IS_ERR(olabel)) { | ||
2129 | status = PTR_ERR(olabel); | ||
2130 | goto err_opendata_put; | ||
2131 | } | ||
2132 | } | ||
2133 | |||
2016 | if (ctx_th && server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) { | 2134 | if (ctx_th && server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) { |
2017 | opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc(); | 2135 | opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc(); |
2018 | if (!opendata->f_attr.mdsthreshold) | 2136 | if (!opendata->f_attr.mdsthreshold) |
2019 | goto err_opendata_put; | 2137 | goto err_free_label; |
2020 | opendata->o_arg.open_bitmap = &nfs4_pnfs_open_bitmap[0]; | 2138 | opendata->o_arg.open_bitmap = &nfs4_pnfs_open_bitmap[0]; |
2021 | } | 2139 | } |
2022 | if (dentry->d_inode != NULL) | 2140 | if (dentry->d_inode != NULL) |
2023 | opendata->state = nfs4_get_open_state(dentry->d_inode, sp); | 2141 | opendata->state = nfs4_get_open_state(dentry->d_inode, sp); |
2024 | 2142 | ||
2025 | status = _nfs4_open_and_get_state(opendata, fmode, flags, &state); | 2143 | status = _nfs4_open_and_get_state(opendata, fmode, flags, ctx); |
2026 | if (status != 0) | 2144 | if (status != 0) |
2027 | goto err_opendata_put; | 2145 | goto err_free_label; |
2146 | state = ctx->state; | ||
2028 | 2147 | ||
2029 | if ((opendata->o_arg.open_flags & O_EXCL) && | 2148 | if ((opendata->o_arg.open_flags & O_EXCL) && |
2030 | (opendata->o_arg.createmode != NFS4_CREATE_GUARDED)) { | 2149 | (opendata->o_arg.createmode != NFS4_CREATE_GUARDED)) { |
@@ -2033,10 +2152,12 @@ static int _nfs4_do_open(struct inode *dir, | |||
2033 | nfs_fattr_init(opendata->o_res.f_attr); | 2152 | nfs_fattr_init(opendata->o_res.f_attr); |
2034 | status = nfs4_do_setattr(state->inode, cred, | 2153 | status = nfs4_do_setattr(state->inode, cred, |
2035 | opendata->o_res.f_attr, sattr, | 2154 | opendata->o_res.f_attr, sattr, |
2036 | state); | 2155 | state, label, olabel); |
2037 | if (status == 0) | 2156 | if (status == 0) { |
2038 | nfs_setattr_update_inode(state->inode, sattr); | 2157 | nfs_setattr_update_inode(state->inode, sattr); |
2039 | nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr); | 2158 | nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr); |
2159 | nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel); | ||
2160 | } | ||
2040 | } | 2161 | } |
2041 | 2162 | ||
2042 | if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server)) | 2163 | if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server)) |
@@ -2045,38 +2166,37 @@ static int _nfs4_do_open(struct inode *dir, | |||
2045 | kfree(opendata->f_attr.mdsthreshold); | 2166 | kfree(opendata->f_attr.mdsthreshold); |
2046 | opendata->f_attr.mdsthreshold = NULL; | 2167 | opendata->f_attr.mdsthreshold = NULL; |
2047 | 2168 | ||
2169 | nfs4_label_free(olabel); | ||
2170 | |||
2048 | nfs4_opendata_put(opendata); | 2171 | nfs4_opendata_put(opendata); |
2049 | nfs4_put_state_owner(sp); | 2172 | nfs4_put_state_owner(sp); |
2050 | *res = state; | ||
2051 | return 0; | 2173 | return 0; |
2174 | err_free_label: | ||
2175 | nfs4_label_free(olabel); | ||
2052 | err_opendata_put: | 2176 | err_opendata_put: |
2053 | kfree(opendata->f_attr.mdsthreshold); | 2177 | kfree(opendata->f_attr.mdsthreshold); |
2054 | nfs4_opendata_put(opendata); | 2178 | nfs4_opendata_put(opendata); |
2055 | err_put_state_owner: | 2179 | err_put_state_owner: |
2056 | nfs4_put_state_owner(sp); | 2180 | nfs4_put_state_owner(sp); |
2057 | out_err: | 2181 | out_err: |
2058 | *res = NULL; | ||
2059 | return status; | 2182 | return status; |
2060 | } | 2183 | } |
2061 | 2184 | ||
2062 | 2185 | ||
2063 | static struct nfs4_state *nfs4_do_open(struct inode *dir, | 2186 | static struct nfs4_state *nfs4_do_open(struct inode *dir, |
2064 | struct dentry *dentry, | 2187 | struct nfs_open_context *ctx, |
2065 | fmode_t fmode, | ||
2066 | int flags, | 2188 | int flags, |
2067 | struct iattr *sattr, | 2189 | struct iattr *sattr, |
2068 | struct rpc_cred *cred, | 2190 | struct nfs4_label *label) |
2069 | struct nfs4_threshold **ctx_th) | ||
2070 | { | 2191 | { |
2071 | struct nfs_server *server = NFS_SERVER(dir); | 2192 | struct nfs_server *server = NFS_SERVER(dir); |
2072 | struct nfs4_exception exception = { }; | 2193 | struct nfs4_exception exception = { }; |
2073 | struct nfs4_state *res; | 2194 | struct nfs4_state *res; |
2074 | int status; | 2195 | int status; |
2075 | 2196 | ||
2076 | fmode &= FMODE_READ|FMODE_WRITE|FMODE_EXEC; | ||
2077 | do { | 2197 | do { |
2078 | status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred, | 2198 | status = _nfs4_do_open(dir, ctx, flags, sattr, label); |
2079 | &res, ctx_th); | 2199 | res = ctx->state; |
2080 | if (status == 0) | 2200 | if (status == 0) |
2081 | break; | 2201 | break; |
2082 | /* NOTE: BAD_SEQID means the server and client disagree about the | 2202 | /* NOTE: BAD_SEQID means the server and client disagree about the |
@@ -2122,7 +2242,8 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, | |||
2122 | 2242 | ||
2123 | static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | 2243 | static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, |
2124 | struct nfs_fattr *fattr, struct iattr *sattr, | 2244 | struct nfs_fattr *fattr, struct iattr *sattr, |
2125 | struct nfs4_state *state) | 2245 | struct nfs4_state *state, struct nfs4_label *ilabel, |
2246 | struct nfs4_label *olabel) | ||
2126 | { | 2247 | { |
2127 | struct nfs_server *server = NFS_SERVER(inode); | 2248 | struct nfs_server *server = NFS_SERVER(inode); |
2128 | struct nfs_setattrargs arg = { | 2249 | struct nfs_setattrargs arg = { |
@@ -2130,9 +2251,11 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
2130 | .iap = sattr, | 2251 | .iap = sattr, |
2131 | .server = server, | 2252 | .server = server, |
2132 | .bitmask = server->attr_bitmask, | 2253 | .bitmask = server->attr_bitmask, |
2254 | .label = ilabel, | ||
2133 | }; | 2255 | }; |
2134 | struct nfs_setattrres res = { | 2256 | struct nfs_setattrres res = { |
2135 | .fattr = fattr, | 2257 | .fattr = fattr, |
2258 | .label = olabel, | ||
2136 | .server = server, | 2259 | .server = server, |
2137 | }; | 2260 | }; |
2138 | struct rpc_message msg = { | 2261 | struct rpc_message msg = { |
@@ -2146,6 +2269,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
2146 | bool truncate; | 2269 | bool truncate; |
2147 | int status; | 2270 | int status; |
2148 | 2271 | ||
2272 | arg.bitmask = nfs4_bitmask(server, ilabel); | ||
2273 | if (ilabel) | ||
2274 | arg.bitmask = nfs4_bitmask(server, olabel); | ||
2275 | |||
2149 | nfs_fattr_init(fattr); | 2276 | nfs_fattr_init(fattr); |
2150 | 2277 | ||
2151 | /* Servers should only apply open mode checks for file size changes */ | 2278 | /* Servers should only apply open mode checks for file size changes */ |
@@ -2172,7 +2299,8 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
2172 | 2299 | ||
2173 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | 2300 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, |
2174 | struct nfs_fattr *fattr, struct iattr *sattr, | 2301 | struct nfs_fattr *fattr, struct iattr *sattr, |
2175 | struct nfs4_state *state) | 2302 | struct nfs4_state *state, struct nfs4_label *ilabel, |
2303 | struct nfs4_label *olabel) | ||
2176 | { | 2304 | { |
2177 | struct nfs_server *server = NFS_SERVER(inode); | 2305 | struct nfs_server *server = NFS_SERVER(inode); |
2178 | struct nfs4_exception exception = { | 2306 | struct nfs4_exception exception = { |
@@ -2181,7 +2309,7 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
2181 | }; | 2309 | }; |
2182 | int err; | 2310 | int err; |
2183 | do { | 2311 | do { |
2184 | err = _nfs4_do_setattr(inode, cred, fattr, sattr, state); | 2312 | err = _nfs4_do_setattr(inode, cred, fattr, sattr, state, ilabel, olabel); |
2185 | switch (err) { | 2313 | switch (err) { |
2186 | case -NFS4ERR_OPENMODE: | 2314 | case -NFS4ERR_OPENMODE: |
2187 | if (!(sattr->ia_valid & ATTR_SIZE)) { | 2315 | if (!(sattr->ia_valid & ATTR_SIZE)) { |
@@ -2426,14 +2554,18 @@ static struct inode * | |||
2426 | nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr) | 2554 | nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr) |
2427 | { | 2555 | { |
2428 | struct nfs4_state *state; | 2556 | struct nfs4_state *state; |
2557 | struct nfs4_label l = {0, 0, 0, NULL}, *label = NULL; | ||
2558 | |||
2559 | label = nfs4_label_init_security(dir, ctx->dentry, attr, &l); | ||
2429 | 2560 | ||
2430 | /* Protect against concurrent sillydeletes */ | 2561 | /* Protect against concurrent sillydeletes */ |
2431 | state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr, | 2562 | state = nfs4_do_open(dir, ctx, open_flags, attr, label); |
2432 | ctx->cred, &ctx->mdsthreshold); | 2563 | |
2564 | nfs4_label_release_security(label); | ||
2565 | |||
2433 | if (IS_ERR(state)) | 2566 | if (IS_ERR(state)) |
2434 | return ERR_CAST(state); | 2567 | return ERR_CAST(state); |
2435 | ctx->state = state; | 2568 | return state->inode; |
2436 | return igrab(state->inode); | ||
2437 | } | 2569 | } |
2438 | 2570 | ||
2439 | static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | 2571 | static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) |
@@ -2489,7 +2621,17 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
2489 | server->caps |= NFS_CAP_CTIME; | 2621 | server->caps |= NFS_CAP_CTIME; |
2490 | if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY) | 2622 | if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY) |
2491 | server->caps |= NFS_CAP_MTIME; | 2623 | server->caps |= NFS_CAP_MTIME; |
2624 | #ifdef CONFIG_NFS_V4_SECURITY_LABEL | ||
2625 | if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL) | ||
2626 | server->caps |= NFS_CAP_SECURITY_LABEL; | ||
2627 | #endif | ||
2628 | memcpy(server->attr_bitmask_nl, res.attr_bitmask, | ||
2629 | sizeof(server->attr_bitmask)); | ||
2492 | 2630 | ||
2631 | if (server->caps & NFS_CAP_SECURITY_LABEL) { | ||
2632 | server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
2633 | res.attr_bitmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
2634 | } | ||
2493 | memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask)); | 2635 | memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask)); |
2494 | server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; | 2636 | server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; |
2495 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | 2637 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; |
@@ -2515,8 +2657,9 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) | |||
2515 | static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | 2657 | static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, |
2516 | struct nfs_fsinfo *info) | 2658 | struct nfs_fsinfo *info) |
2517 | { | 2659 | { |
2660 | u32 bitmask[3]; | ||
2518 | struct nfs4_lookup_root_arg args = { | 2661 | struct nfs4_lookup_root_arg args = { |
2519 | .bitmask = nfs4_fattr_bitmap, | 2662 | .bitmask = bitmask, |
2520 | }; | 2663 | }; |
2521 | struct nfs4_lookup_res res = { | 2664 | struct nfs4_lookup_res res = { |
2522 | .server = server, | 2665 | .server = server, |
@@ -2529,6 +2672,13 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2529 | .rpc_resp = &res, | 2672 | .rpc_resp = &res, |
2530 | }; | 2673 | }; |
2531 | 2674 | ||
2675 | bitmask[0] = nfs4_fattr_bitmap[0]; | ||
2676 | bitmask[1] = nfs4_fattr_bitmap[1]; | ||
2677 | /* | ||
2678 | * Process the label in the upcoming getfattr | ||
2679 | */ | ||
2680 | bitmask[2] = nfs4_fattr_bitmap[2] & ~FATTR4_WORD2_SECURITY_LABEL; | ||
2681 | |||
2532 | nfs_fattr_init(info->fattr); | 2682 | nfs_fattr_init(info->fattr); |
2533 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); | 2683 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
2534 | } | 2684 | } |
@@ -2648,6 +2798,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh, | |||
2648 | { | 2798 | { |
2649 | int error; | 2799 | int error; |
2650 | struct nfs_fattr *fattr = info->fattr; | 2800 | struct nfs_fattr *fattr = info->fattr; |
2801 | struct nfs4_label *label = NULL; | ||
2651 | 2802 | ||
2652 | error = nfs4_server_capabilities(server, mntfh); | 2803 | error = nfs4_server_capabilities(server, mntfh); |
2653 | if (error < 0) { | 2804 | if (error < 0) { |
@@ -2655,16 +2806,23 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh, | |||
2655 | return error; | 2806 | return error; |
2656 | } | 2807 | } |
2657 | 2808 | ||
2658 | error = nfs4_proc_getattr(server, mntfh, fattr); | 2809 | label = nfs4_label_alloc(server, GFP_KERNEL); |
2810 | if (IS_ERR(label)) | ||
2811 | return PTR_ERR(label); | ||
2812 | |||
2813 | error = nfs4_proc_getattr(server, mntfh, fattr, label); | ||
2659 | if (error < 0) { | 2814 | if (error < 0) { |
2660 | dprintk("nfs4_get_root: getattr error = %d\n", -error); | 2815 | dprintk("nfs4_get_root: getattr error = %d\n", -error); |
2661 | return error; | 2816 | goto err_free_label; |
2662 | } | 2817 | } |
2663 | 2818 | ||
2664 | if (fattr->valid & NFS_ATTR_FATTR_FSID && | 2819 | if (fattr->valid & NFS_ATTR_FATTR_FSID && |
2665 | !nfs_fsid_equal(&server->fsid, &fattr->fsid)) | 2820 | !nfs_fsid_equal(&server->fsid, &fattr->fsid)) |
2666 | memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid)); | 2821 | memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid)); |
2667 | 2822 | ||
2823 | err_free_label: | ||
2824 | nfs4_label_free(label); | ||
2825 | |||
2668 | return error; | 2826 | return error; |
2669 | } | 2827 | } |
2670 | 2828 | ||
@@ -2711,7 +2869,8 @@ out: | |||
2711 | return status; | 2869 | return status; |
2712 | } | 2870 | } |
2713 | 2871 | ||
2714 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2872 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, |
2873 | struct nfs_fattr *fattr, struct nfs4_label *label) | ||
2715 | { | 2874 | { |
2716 | struct nfs4_getattr_arg args = { | 2875 | struct nfs4_getattr_arg args = { |
2717 | .fh = fhandle, | 2876 | .fh = fhandle, |
@@ -2719,6 +2878,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2719 | }; | 2878 | }; |
2720 | struct nfs4_getattr_res res = { | 2879 | struct nfs4_getattr_res res = { |
2721 | .fattr = fattr, | 2880 | .fattr = fattr, |
2881 | .label = label, | ||
2722 | .server = server, | 2882 | .server = server, |
2723 | }; | 2883 | }; |
2724 | struct rpc_message msg = { | 2884 | struct rpc_message msg = { |
@@ -2726,18 +2886,21 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2726 | .rpc_argp = &args, | 2886 | .rpc_argp = &args, |
2727 | .rpc_resp = &res, | 2887 | .rpc_resp = &res, |
2728 | }; | 2888 | }; |
2729 | 2889 | ||
2890 | args.bitmask = nfs4_bitmask(server, label); | ||
2891 | |||
2730 | nfs_fattr_init(fattr); | 2892 | nfs_fattr_init(fattr); |
2731 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); | 2893 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
2732 | } | 2894 | } |
2733 | 2895 | ||
2734 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2896 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, |
2897 | struct nfs_fattr *fattr, struct nfs4_label *label) | ||
2735 | { | 2898 | { |
2736 | struct nfs4_exception exception = { }; | 2899 | struct nfs4_exception exception = { }; |
2737 | int err; | 2900 | int err; |
2738 | do { | 2901 | do { |
2739 | err = nfs4_handle_exception(server, | 2902 | err = nfs4_handle_exception(server, |
2740 | _nfs4_proc_getattr(server, fhandle, fattr), | 2903 | _nfs4_proc_getattr(server, fhandle, fattr, label), |
2741 | &exception); | 2904 | &exception); |
2742 | } while (exception.retry); | 2905 | } while (exception.retry); |
2743 | return err; | 2906 | return err; |
@@ -2767,6 +2930,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
2767 | struct inode *inode = dentry->d_inode; | 2930 | struct inode *inode = dentry->d_inode; |
2768 | struct rpc_cred *cred = NULL; | 2931 | struct rpc_cred *cred = NULL; |
2769 | struct nfs4_state *state = NULL; | 2932 | struct nfs4_state *state = NULL; |
2933 | struct nfs4_label *label = NULL; | ||
2770 | int status; | 2934 | int status; |
2771 | 2935 | ||
2772 | if (pnfs_ld_layoutret_on_setattr(inode)) | 2936 | if (pnfs_ld_layoutret_on_setattr(inode)) |
@@ -2793,15 +2957,22 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
2793 | } | 2957 | } |
2794 | } | 2958 | } |
2795 | 2959 | ||
2796 | status = nfs4_do_setattr(inode, cred, fattr, sattr, state); | 2960 | label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL); |
2797 | if (status == 0) | 2961 | if (IS_ERR(label)) |
2962 | return PTR_ERR(label); | ||
2963 | |||
2964 | status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, label); | ||
2965 | if (status == 0) { | ||
2798 | nfs_setattr_update_inode(inode, sattr); | 2966 | nfs_setattr_update_inode(inode, sattr); |
2967 | nfs_setsecurity(inode, fattr, label); | ||
2968 | } | ||
2969 | nfs4_label_free(label); | ||
2799 | return status; | 2970 | return status; |
2800 | } | 2971 | } |
2801 | 2972 | ||
2802 | static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, | 2973 | static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, |
2803 | const struct qstr *name, struct nfs_fh *fhandle, | 2974 | const struct qstr *name, struct nfs_fh *fhandle, |
2804 | struct nfs_fattr *fattr) | 2975 | struct nfs_fattr *fattr, struct nfs4_label *label) |
2805 | { | 2976 | { |
2806 | struct nfs_server *server = NFS_SERVER(dir); | 2977 | struct nfs_server *server = NFS_SERVER(dir); |
2807 | int status; | 2978 | int status; |
@@ -2813,6 +2984,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, | |||
2813 | struct nfs4_lookup_res res = { | 2984 | struct nfs4_lookup_res res = { |
2814 | .server = server, | 2985 | .server = server, |
2815 | .fattr = fattr, | 2986 | .fattr = fattr, |
2987 | .label = label, | ||
2816 | .fh = fhandle, | 2988 | .fh = fhandle, |
2817 | }; | 2989 | }; |
2818 | struct rpc_message msg = { | 2990 | struct rpc_message msg = { |
@@ -2821,6 +2993,8 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, | |||
2821 | .rpc_resp = &res, | 2993 | .rpc_resp = &res, |
2822 | }; | 2994 | }; |
2823 | 2995 | ||
2996 | args.bitmask = nfs4_bitmask(server, label); | ||
2997 | |||
2824 | nfs_fattr_init(fattr); | 2998 | nfs_fattr_init(fattr); |
2825 | 2999 | ||
2826 | dprintk("NFS call lookup %s\n", name->name); | 3000 | dprintk("NFS call lookup %s\n", name->name); |
@@ -2839,13 +3013,13 @@ static void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr) | |||
2839 | 3013 | ||
2840 | static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir, | 3014 | static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir, |
2841 | struct qstr *name, struct nfs_fh *fhandle, | 3015 | struct qstr *name, struct nfs_fh *fhandle, |
2842 | struct nfs_fattr *fattr) | 3016 | struct nfs_fattr *fattr, struct nfs4_label *label) |
2843 | { | 3017 | { |
2844 | struct nfs4_exception exception = { }; | 3018 | struct nfs4_exception exception = { }; |
2845 | struct rpc_clnt *client = *clnt; | 3019 | struct rpc_clnt *client = *clnt; |
2846 | int err; | 3020 | int err; |
2847 | do { | 3021 | do { |
2848 | err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr); | 3022 | err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr, label); |
2849 | switch (err) { | 3023 | switch (err) { |
2850 | case -NFS4ERR_BADNAME: | 3024 | case -NFS4ERR_BADNAME: |
2851 | err = -ENOENT; | 3025 | err = -ENOENT; |
@@ -2879,12 +3053,13 @@ out: | |||
2879 | } | 3053 | } |
2880 | 3054 | ||
2881 | static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, | 3055 | static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, |
2882 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 3056 | struct nfs_fh *fhandle, struct nfs_fattr *fattr, |
3057 | struct nfs4_label *label) | ||
2883 | { | 3058 | { |
2884 | int status; | 3059 | int status; |
2885 | struct rpc_clnt *client = NFS_CLIENT(dir); | 3060 | struct rpc_clnt *client = NFS_CLIENT(dir); |
2886 | 3061 | ||
2887 | status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr); | 3062 | status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, label); |
2888 | if (client != NFS_CLIENT(dir)) { | 3063 | if (client != NFS_CLIENT(dir)) { |
2889 | rpc_shutdown_client(client); | 3064 | rpc_shutdown_client(client); |
2890 | nfs_fixup_secinfo_attributes(fattr); | 3065 | nfs_fixup_secinfo_attributes(fattr); |
@@ -2896,15 +3071,13 @@ struct rpc_clnt * | |||
2896 | nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name, | 3071 | nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name, |
2897 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 3072 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
2898 | { | 3073 | { |
3074 | struct rpc_clnt *client = NFS_CLIENT(dir); | ||
2899 | int status; | 3075 | int status; |
2900 | struct rpc_clnt *client = rpc_clone_client(NFS_CLIENT(dir)); | ||
2901 | 3076 | ||
2902 | status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr); | 3077 | status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, NULL); |
2903 | if (status < 0) { | 3078 | if (status < 0) |
2904 | rpc_shutdown_client(client); | ||
2905 | return ERR_PTR(status); | 3079 | return ERR_PTR(status); |
2906 | } | 3080 | return (client == NFS_CLIENT(dir)) ? rpc_clone_client(client) : client; |
2907 | return client; | ||
2908 | } | 3081 | } |
2909 | 3082 | ||
2910 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) | 3083 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) |
@@ -2924,7 +3097,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
2924 | .rpc_cred = entry->cred, | 3097 | .rpc_cred = entry->cred, |
2925 | }; | 3098 | }; |
2926 | int mode = entry->mask; | 3099 | int mode = entry->mask; |
2927 | int status; | 3100 | int status = 0; |
2928 | 3101 | ||
2929 | /* | 3102 | /* |
2930 | * Determine which access bits we want to ask for... | 3103 | * Determine which access bits we want to ask for... |
@@ -3029,6 +3202,7 @@ static int | |||
3029 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 3202 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
3030 | int flags) | 3203 | int flags) |
3031 | { | 3204 | { |
3205 | struct nfs4_label l, *ilabel = NULL; | ||
3032 | struct nfs_open_context *ctx; | 3206 | struct nfs_open_context *ctx; |
3033 | struct nfs4_state *state; | 3207 | struct nfs4_state *state; |
3034 | int status = 0; | 3208 | int status = 0; |
@@ -3037,19 +3211,16 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
3037 | if (IS_ERR(ctx)) | 3211 | if (IS_ERR(ctx)) |
3038 | return PTR_ERR(ctx); | 3212 | return PTR_ERR(ctx); |
3039 | 3213 | ||
3214 | ilabel = nfs4_label_init_security(dir, dentry, sattr, &l); | ||
3215 | |||
3040 | sattr->ia_mode &= ~current_umask(); | 3216 | sattr->ia_mode &= ~current_umask(); |
3041 | state = nfs4_do_open(dir, dentry, ctx->mode, | 3217 | state = nfs4_do_open(dir, ctx, flags, sattr, ilabel); |
3042 | flags, sattr, ctx->cred, | ||
3043 | &ctx->mdsthreshold); | ||
3044 | d_drop(dentry); | ||
3045 | if (IS_ERR(state)) { | 3218 | if (IS_ERR(state)) { |
3046 | status = PTR_ERR(state); | 3219 | status = PTR_ERR(state); |
3047 | goto out; | 3220 | goto out; |
3048 | } | 3221 | } |
3049 | d_add(dentry, igrab(state->inode)); | ||
3050 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
3051 | ctx->state = state; | ||
3052 | out: | 3222 | out: |
3223 | nfs4_label_release_security(ilabel); | ||
3053 | put_nfs_open_context(ctx); | 3224 | put_nfs_open_context(ctx); |
3054 | return status; | 3225 | return status; |
3055 | } | 3226 | } |
@@ -3098,6 +3269,8 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) | |||
3098 | res->server = server; | 3269 | res->server = server; |
3099 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; | 3270 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; |
3100 | nfs41_init_sequence(&args->seq_args, &res->seq_res, 1); | 3271 | nfs41_init_sequence(&args->seq_args, &res->seq_res, 1); |
3272 | |||
3273 | nfs_fattr_init(res->dir_attr); | ||
3101 | } | 3274 | } |
3102 | 3275 | ||
3103 | static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data) | 3276 | static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data) |
@@ -3173,7 +3346,7 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
3173 | .rpc_resp = &res, | 3346 | .rpc_resp = &res, |
3174 | }; | 3347 | }; |
3175 | int status = -ENOMEM; | 3348 | int status = -ENOMEM; |
3176 | 3349 | ||
3177 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); | 3350 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
3178 | if (!status) { | 3351 | if (!status) { |
3179 | update_changeattr(old_dir, &res.old_cinfo); | 3352 | update_changeattr(old_dir, &res.old_cinfo); |
@@ -3207,6 +3380,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
3207 | }; | 3380 | }; |
3208 | struct nfs4_link_res res = { | 3381 | struct nfs4_link_res res = { |
3209 | .server = server, | 3382 | .server = server, |
3383 | .label = NULL, | ||
3210 | }; | 3384 | }; |
3211 | struct rpc_message msg = { | 3385 | struct rpc_message msg = { |
3212 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], | 3386 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], |
@@ -3219,11 +3393,24 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
3219 | if (res.fattr == NULL) | 3393 | if (res.fattr == NULL) |
3220 | goto out; | 3394 | goto out; |
3221 | 3395 | ||
3396 | res.label = nfs4_label_alloc(server, GFP_KERNEL); | ||
3397 | if (IS_ERR(res.label)) { | ||
3398 | status = PTR_ERR(res.label); | ||
3399 | goto out; | ||
3400 | } | ||
3401 | arg.bitmask = nfs4_bitmask(server, res.label); | ||
3402 | |||
3222 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); | 3403 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
3223 | if (!status) { | 3404 | if (!status) { |
3224 | update_changeattr(dir, &res.cinfo); | 3405 | update_changeattr(dir, &res.cinfo); |
3225 | nfs_post_op_update_inode(inode, res.fattr); | 3406 | status = nfs_post_op_update_inode(inode, res.fattr); |
3407 | if (!status) | ||
3408 | nfs_setsecurity(inode, res.fattr, res.label); | ||
3226 | } | 3409 | } |
3410 | |||
3411 | |||
3412 | nfs4_label_free(res.label); | ||
3413 | |||
3227 | out: | 3414 | out: |
3228 | nfs_free_fattr(res.fattr); | 3415 | nfs_free_fattr(res.fattr); |
3229 | return status; | 3416 | return status; |
@@ -3247,6 +3434,7 @@ struct nfs4_createdata { | |||
3247 | struct nfs4_create_res res; | 3434 | struct nfs4_create_res res; |
3248 | struct nfs_fh fh; | 3435 | struct nfs_fh fh; |
3249 | struct nfs_fattr fattr; | 3436 | struct nfs_fattr fattr; |
3437 | struct nfs4_label *label; | ||
3250 | }; | 3438 | }; |
3251 | 3439 | ||
3252 | static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, | 3440 | static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, |
@@ -3258,6 +3446,10 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, | |||
3258 | if (data != NULL) { | 3446 | if (data != NULL) { |
3259 | struct nfs_server *server = NFS_SERVER(dir); | 3447 | struct nfs_server *server = NFS_SERVER(dir); |
3260 | 3448 | ||
3449 | data->label = nfs4_label_alloc(server, GFP_KERNEL); | ||
3450 | if (IS_ERR(data->label)) | ||
3451 | goto out_free; | ||
3452 | |||
3261 | data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE]; | 3453 | data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE]; |
3262 | data->msg.rpc_argp = &data->arg; | 3454 | data->msg.rpc_argp = &data->arg; |
3263 | data->msg.rpc_resp = &data->res; | 3455 | data->msg.rpc_resp = &data->res; |
@@ -3266,13 +3458,17 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, | |||
3266 | data->arg.name = name; | 3458 | data->arg.name = name; |
3267 | data->arg.attrs = sattr; | 3459 | data->arg.attrs = sattr; |
3268 | data->arg.ftype = ftype; | 3460 | data->arg.ftype = ftype; |
3269 | data->arg.bitmask = server->attr_bitmask; | 3461 | data->arg.bitmask = nfs4_bitmask(server, data->label); |
3270 | data->res.server = server; | 3462 | data->res.server = server; |
3271 | data->res.fh = &data->fh; | 3463 | data->res.fh = &data->fh; |
3272 | data->res.fattr = &data->fattr; | 3464 | data->res.fattr = &data->fattr; |
3465 | data->res.label = data->label; | ||
3273 | nfs_fattr_init(data->res.fattr); | 3466 | nfs_fattr_init(data->res.fattr); |
3274 | } | 3467 | } |
3275 | return data; | 3468 | return data; |
3469 | out_free: | ||
3470 | kfree(data); | ||
3471 | return NULL; | ||
3276 | } | 3472 | } |
3277 | 3473 | ||
3278 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) | 3474 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) |
@@ -3281,18 +3477,20 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_ | |||
3281 | &data->arg.seq_args, &data->res.seq_res, 1); | 3477 | &data->arg.seq_args, &data->res.seq_res, 1); |
3282 | if (status == 0) { | 3478 | if (status == 0) { |
3283 | update_changeattr(dir, &data->res.dir_cinfo); | 3479 | update_changeattr(dir, &data->res.dir_cinfo); |
3284 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); | 3480 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label); |
3285 | } | 3481 | } |
3286 | return status; | 3482 | return status; |
3287 | } | 3483 | } |
3288 | 3484 | ||
3289 | static void nfs4_free_createdata(struct nfs4_createdata *data) | 3485 | static void nfs4_free_createdata(struct nfs4_createdata *data) |
3290 | { | 3486 | { |
3487 | nfs4_label_free(data->label); | ||
3291 | kfree(data); | 3488 | kfree(data); |
3292 | } | 3489 | } |
3293 | 3490 | ||
3294 | static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, | 3491 | static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, |
3295 | struct page *page, unsigned int len, struct iattr *sattr) | 3492 | struct page *page, unsigned int len, struct iattr *sattr, |
3493 | struct nfs4_label *label) | ||
3296 | { | 3494 | { |
3297 | struct nfs4_createdata *data; | 3495 | struct nfs4_createdata *data; |
3298 | int status = -ENAMETOOLONG; | 3496 | int status = -ENAMETOOLONG; |
@@ -3308,6 +3506,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, | |||
3308 | data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK]; | 3506 | data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK]; |
3309 | data->arg.u.symlink.pages = &page; | 3507 | data->arg.u.symlink.pages = &page; |
3310 | data->arg.u.symlink.len = len; | 3508 | data->arg.u.symlink.len = len; |
3509 | data->arg.label = label; | ||
3311 | 3510 | ||
3312 | status = nfs4_do_create(dir, dentry, data); | 3511 | status = nfs4_do_create(dir, dentry, data); |
3313 | 3512 | ||
@@ -3320,18 +3519,24 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, | |||
3320 | struct page *page, unsigned int len, struct iattr *sattr) | 3519 | struct page *page, unsigned int len, struct iattr *sattr) |
3321 | { | 3520 | { |
3322 | struct nfs4_exception exception = { }; | 3521 | struct nfs4_exception exception = { }; |
3522 | struct nfs4_label l, *label = NULL; | ||
3323 | int err; | 3523 | int err; |
3524 | |||
3525 | label = nfs4_label_init_security(dir, dentry, sattr, &l); | ||
3526 | |||
3324 | do { | 3527 | do { |
3325 | err = nfs4_handle_exception(NFS_SERVER(dir), | 3528 | err = nfs4_handle_exception(NFS_SERVER(dir), |
3326 | _nfs4_proc_symlink(dir, dentry, page, | 3529 | _nfs4_proc_symlink(dir, dentry, page, |
3327 | len, sattr), | 3530 | len, sattr, label), |
3328 | &exception); | 3531 | &exception); |
3329 | } while (exception.retry); | 3532 | } while (exception.retry); |
3533 | |||
3534 | nfs4_label_release_security(label); | ||
3330 | return err; | 3535 | return err; |
3331 | } | 3536 | } |
3332 | 3537 | ||
3333 | static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, | 3538 | static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, |
3334 | struct iattr *sattr) | 3539 | struct iattr *sattr, struct nfs4_label *label) |
3335 | { | 3540 | { |
3336 | struct nfs4_createdata *data; | 3541 | struct nfs4_createdata *data; |
3337 | int status = -ENOMEM; | 3542 | int status = -ENOMEM; |
@@ -3340,6 +3545,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, | |||
3340 | if (data == NULL) | 3545 | if (data == NULL) |
3341 | goto out; | 3546 | goto out; |
3342 | 3547 | ||
3548 | data->arg.label = label; | ||
3343 | status = nfs4_do_create(dir, dentry, data); | 3549 | status = nfs4_do_create(dir, dentry, data); |
3344 | 3550 | ||
3345 | nfs4_free_createdata(data); | 3551 | nfs4_free_createdata(data); |
@@ -3351,14 +3557,19 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, | |||
3351 | struct iattr *sattr) | 3557 | struct iattr *sattr) |
3352 | { | 3558 | { |
3353 | struct nfs4_exception exception = { }; | 3559 | struct nfs4_exception exception = { }; |
3560 | struct nfs4_label l, *label = NULL; | ||
3354 | int err; | 3561 | int err; |
3355 | 3562 | ||
3563 | label = nfs4_label_init_security(dir, dentry, sattr, &l); | ||
3564 | |||
3356 | sattr->ia_mode &= ~current_umask(); | 3565 | sattr->ia_mode &= ~current_umask(); |
3357 | do { | 3566 | do { |
3358 | err = nfs4_handle_exception(NFS_SERVER(dir), | 3567 | err = nfs4_handle_exception(NFS_SERVER(dir), |
3359 | _nfs4_proc_mkdir(dir, dentry, sattr), | 3568 | _nfs4_proc_mkdir(dir, dentry, sattr, label), |
3360 | &exception); | 3569 | &exception); |
3361 | } while (exception.retry); | 3570 | } while (exception.retry); |
3571 | nfs4_label_release_security(label); | ||
3572 | |||
3362 | return err; | 3573 | return err; |
3363 | } | 3574 | } |
3364 | 3575 | ||
@@ -3416,7 +3627,7 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
3416 | } | 3627 | } |
3417 | 3628 | ||
3418 | static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, | 3629 | static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, |
3419 | struct iattr *sattr, dev_t rdev) | 3630 | struct iattr *sattr, struct nfs4_label *label, dev_t rdev) |
3420 | { | 3631 | { |
3421 | struct nfs4_createdata *data; | 3632 | struct nfs4_createdata *data; |
3422 | int mode = sattr->ia_mode; | 3633 | int mode = sattr->ia_mode; |
@@ -3441,7 +3652,8 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, | |||
3441 | status = -EINVAL; | 3652 | status = -EINVAL; |
3442 | goto out_free; | 3653 | goto out_free; |
3443 | } | 3654 | } |
3444 | 3655 | ||
3656 | data->arg.label = label; | ||
3445 | status = nfs4_do_create(dir, dentry, data); | 3657 | status = nfs4_do_create(dir, dentry, data); |
3446 | out_free: | 3658 | out_free: |
3447 | nfs4_free_createdata(data); | 3659 | nfs4_free_createdata(data); |
@@ -3453,14 +3665,20 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, | |||
3453 | struct iattr *sattr, dev_t rdev) | 3665 | struct iattr *sattr, dev_t rdev) |
3454 | { | 3666 | { |
3455 | struct nfs4_exception exception = { }; | 3667 | struct nfs4_exception exception = { }; |
3668 | struct nfs4_label l, *label = NULL; | ||
3456 | int err; | 3669 | int err; |
3457 | 3670 | ||
3671 | label = nfs4_label_init_security(dir, dentry, sattr, &l); | ||
3672 | |||
3458 | sattr->ia_mode &= ~current_umask(); | 3673 | sattr->ia_mode &= ~current_umask(); |
3459 | do { | 3674 | do { |
3460 | err = nfs4_handle_exception(NFS_SERVER(dir), | 3675 | err = nfs4_handle_exception(NFS_SERVER(dir), |
3461 | _nfs4_proc_mknod(dir, dentry, sattr, rdev), | 3676 | _nfs4_proc_mknod(dir, dentry, sattr, label, rdev), |
3462 | &exception); | 3677 | &exception); |
3463 | } while (exception.retry); | 3678 | } while (exception.retry); |
3679 | |||
3680 | nfs4_label_release_security(label); | ||
3681 | |||
3464 | return err; | 3682 | return err; |
3465 | } | 3683 | } |
3466 | 3684 | ||
@@ -4187,6 +4405,155 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
4187 | return err; | 4405 | return err; |
4188 | } | 4406 | } |
4189 | 4407 | ||
4408 | #ifdef CONFIG_NFS_V4_SECURITY_LABEL | ||
4409 | static int _nfs4_get_security_label(struct inode *inode, void *buf, | ||
4410 | size_t buflen) | ||
4411 | { | ||
4412 | struct nfs_server *server = NFS_SERVER(inode); | ||
4413 | struct nfs_fattr fattr; | ||
4414 | struct nfs4_label label = {0, 0, buflen, buf}; | ||
4415 | |||
4416 | u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL }; | ||
4417 | struct nfs4_getattr_arg args = { | ||
4418 | .fh = NFS_FH(inode), | ||
4419 | .bitmask = bitmask, | ||
4420 | }; | ||
4421 | struct nfs4_getattr_res res = { | ||
4422 | .fattr = &fattr, | ||
4423 | .label = &label, | ||
4424 | .server = server, | ||
4425 | }; | ||
4426 | struct rpc_message msg = { | ||
4427 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR], | ||
4428 | .rpc_argp = &args, | ||
4429 | .rpc_resp = &res, | ||
4430 | }; | ||
4431 | int ret; | ||
4432 | |||
4433 | nfs_fattr_init(&fattr); | ||
4434 | |||
4435 | ret = rpc_call_sync(server->client, &msg, 0); | ||
4436 | if (ret) | ||
4437 | return ret; | ||
4438 | if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL)) | ||
4439 | return -ENOENT; | ||
4440 | if (buflen < label.len) | ||
4441 | return -ERANGE; | ||
4442 | return 0; | ||
4443 | } | ||
4444 | |||
4445 | static int nfs4_get_security_label(struct inode *inode, void *buf, | ||
4446 | size_t buflen) | ||
4447 | { | ||
4448 | struct nfs4_exception exception = { }; | ||
4449 | int err; | ||
4450 | |||
4451 | if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) | ||
4452 | return -EOPNOTSUPP; | ||
4453 | |||
4454 | do { | ||
4455 | err = nfs4_handle_exception(NFS_SERVER(inode), | ||
4456 | _nfs4_get_security_label(inode, buf, buflen), | ||
4457 | &exception); | ||
4458 | } while (exception.retry); | ||
4459 | return err; | ||
4460 | } | ||
4461 | |||
4462 | static int _nfs4_do_set_security_label(struct inode *inode, | ||
4463 | struct nfs4_label *ilabel, | ||
4464 | struct nfs_fattr *fattr, | ||
4465 | struct nfs4_label *olabel) | ||
4466 | { | ||
4467 | |||
4468 | struct iattr sattr = {0}; | ||
4469 | struct nfs_server *server = NFS_SERVER(inode); | ||
4470 | const u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL }; | ||
4471 | struct nfs_setattrargs args = { | ||
4472 | .fh = NFS_FH(inode), | ||
4473 | .iap = &sattr, | ||
4474 | .server = server, | ||
4475 | .bitmask = bitmask, | ||
4476 | .label = ilabel, | ||
4477 | }; | ||
4478 | struct nfs_setattrres res = { | ||
4479 | .fattr = fattr, | ||
4480 | .label = olabel, | ||
4481 | .server = server, | ||
4482 | }; | ||
4483 | struct rpc_message msg = { | ||
4484 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR], | ||
4485 | .rpc_argp = &args, | ||
4486 | .rpc_resp = &res, | ||
4487 | }; | ||
4488 | int status; | ||
4489 | |||
4490 | nfs4_stateid_copy(&args.stateid, &zero_stateid); | ||
4491 | |||
4492 | status = rpc_call_sync(server->client, &msg, 0); | ||
4493 | if (status) | ||
4494 | dprintk("%s failed: %d\n", __func__, status); | ||
4495 | |||
4496 | return status; | ||
4497 | } | ||
4498 | |||
4499 | static int nfs4_do_set_security_label(struct inode *inode, | ||
4500 | struct nfs4_label *ilabel, | ||
4501 | struct nfs_fattr *fattr, | ||
4502 | struct nfs4_label *olabel) | ||
4503 | { | ||
4504 | struct nfs4_exception exception = { }; | ||
4505 | int err; | ||
4506 | |||
4507 | do { | ||
4508 | err = nfs4_handle_exception(NFS_SERVER(inode), | ||
4509 | _nfs4_do_set_security_label(inode, ilabel, | ||
4510 | fattr, olabel), | ||
4511 | &exception); | ||
4512 | } while (exception.retry); | ||
4513 | return err; | ||
4514 | } | ||
4515 | |||
4516 | static int | ||
4517 | nfs4_set_security_label(struct dentry *dentry, const void *buf, size_t buflen) | ||
4518 | { | ||
4519 | struct nfs4_label ilabel, *olabel = NULL; | ||
4520 | struct nfs_fattr fattr; | ||
4521 | struct rpc_cred *cred; | ||
4522 | struct inode *inode = dentry->d_inode; | ||
4523 | int status; | ||
4524 | |||
4525 | if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) | ||
4526 | return -EOPNOTSUPP; | ||
4527 | |||
4528 | nfs_fattr_init(&fattr); | ||
4529 | |||
4530 | ilabel.pi = 0; | ||
4531 | ilabel.lfs = 0; | ||
4532 | ilabel.label = (char *)buf; | ||
4533 | ilabel.len = buflen; | ||
4534 | |||
4535 | cred = rpc_lookup_cred(); | ||
4536 | if (IS_ERR(cred)) | ||
4537 | return PTR_ERR(cred); | ||
4538 | |||
4539 | olabel = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL); | ||
4540 | if (IS_ERR(olabel)) { | ||
4541 | status = -PTR_ERR(olabel); | ||
4542 | goto out; | ||
4543 | } | ||
4544 | |||
4545 | status = nfs4_do_set_security_label(inode, &ilabel, &fattr, olabel); | ||
4546 | if (status == 0) | ||
4547 | nfs_setsecurity(inode, &fattr, olabel); | ||
4548 | |||
4549 | nfs4_label_free(olabel); | ||
4550 | out: | ||
4551 | put_rpccred(cred); | ||
4552 | return status; | ||
4553 | } | ||
4554 | #endif /* CONFIG_NFS_V4_SECURITY_LABEL */ | ||
4555 | |||
4556 | |||
4190 | static int | 4557 | static int |
4191 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | 4558 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) |
4192 | { | 4559 | { |
@@ -4345,7 +4712,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | |||
4345 | /* cb_client4 */ | 4712 | /* cb_client4 */ |
4346 | rcu_read_lock(); | 4713 | rcu_read_lock(); |
4347 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, | 4714 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, |
4348 | sizeof(setclientid.sc_netid), | 4715 | sizeof(setclientid.sc_netid), "%s", |
4349 | rpc_peeraddr2str(clp->cl_rpcclient, | 4716 | rpc_peeraddr2str(clp->cl_rpcclient, |
4350 | RPC_DISPLAY_NETID)); | 4717 | RPC_DISPLAY_NETID)); |
4351 | rcu_read_unlock(); | 4718 | rcu_read_unlock(); |
@@ -4528,7 +4895,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4 | |||
4528 | static unsigned long | 4895 | static unsigned long |
4529 | nfs4_set_lock_task_retry(unsigned long timeout) | 4896 | nfs4_set_lock_task_retry(unsigned long timeout) |
4530 | { | 4897 | { |
4531 | freezable_schedule_timeout_killable(timeout); | 4898 | freezable_schedule_timeout_killable_unsafe(timeout); |
4532 | timeout <<= 1; | 4899 | timeout <<= 1; |
4533 | if (timeout > NFS4_LOCK_MAXTIMEOUT) | 4900 | if (timeout > NFS4_LOCK_MAXTIMEOUT) |
4534 | return NFS4_LOCK_MAXTIMEOUT; | 4901 | return NFS4_LOCK_MAXTIMEOUT; |
@@ -5056,13 +5423,18 @@ static int nfs41_check_expired_locks(struct nfs4_state *state) | |||
5056 | 5423 | ||
5057 | list_for_each_entry(lsp, &state->lock_states, ls_locks) { | 5424 | list_for_each_entry(lsp, &state->lock_states, ls_locks) { |
5058 | if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { | 5425 | if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { |
5059 | status = nfs41_test_stateid(server, &lsp->ls_stateid); | 5426 | struct rpc_cred *cred = lsp->ls_state->owner->so_cred; |
5427 | |||
5428 | status = nfs41_test_stateid(server, | ||
5429 | &lsp->ls_stateid, | ||
5430 | cred); | ||
5060 | if (status != NFS_OK) { | 5431 | if (status != NFS_OK) { |
5061 | /* Free the stateid unless the server | 5432 | /* Free the stateid unless the server |
5062 | * informs us the stateid is unrecognized. */ | 5433 | * informs us the stateid is unrecognized. */ |
5063 | if (status != -NFS4ERR_BAD_STATEID) | 5434 | if (status != -NFS4ERR_BAD_STATEID) |
5064 | nfs41_free_stateid(server, | 5435 | nfs41_free_stateid(server, |
5065 | &lsp->ls_stateid); | 5436 | &lsp->ls_stateid, |
5437 | cred); | ||
5066 | clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags); | 5438 | clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags); |
5067 | ret = status; | 5439 | ret = status; |
5068 | } | 5440 | } |
@@ -5295,6 +5667,53 @@ static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list, | |||
5295 | return len; | 5667 | return len; |
5296 | } | 5668 | } |
5297 | 5669 | ||
5670 | #ifdef CONFIG_NFS_V4_SECURITY_LABEL | ||
5671 | static inline int nfs4_server_supports_labels(struct nfs_server *server) | ||
5672 | { | ||
5673 | return server->caps & NFS_CAP_SECURITY_LABEL; | ||
5674 | } | ||
5675 | |||
5676 | static int nfs4_xattr_set_nfs4_label(struct dentry *dentry, const char *key, | ||
5677 | const void *buf, size_t buflen, | ||
5678 | int flags, int type) | ||
5679 | { | ||
5680 | if (security_ismaclabel(key)) | ||
5681 | return nfs4_set_security_label(dentry, buf, buflen); | ||
5682 | |||
5683 | return -EOPNOTSUPP; | ||
5684 | } | ||
5685 | |||
5686 | static int nfs4_xattr_get_nfs4_label(struct dentry *dentry, const char *key, | ||
5687 | void *buf, size_t buflen, int type) | ||
5688 | { | ||
5689 | if (security_ismaclabel(key)) | ||
5690 | return nfs4_get_security_label(dentry->d_inode, buf, buflen); | ||
5691 | return -EOPNOTSUPP; | ||
5692 | } | ||
5693 | |||
5694 | static size_t nfs4_xattr_list_nfs4_label(struct dentry *dentry, char *list, | ||
5695 | size_t list_len, const char *name, | ||
5696 | size_t name_len, int type) | ||
5697 | { | ||
5698 | size_t len = 0; | ||
5699 | |||
5700 | if (nfs_server_capable(dentry->d_inode, NFS_CAP_SECURITY_LABEL)) { | ||
5701 | len = security_inode_listsecurity(dentry->d_inode, NULL, 0); | ||
5702 | if (list && len <= list_len) | ||
5703 | security_inode_listsecurity(dentry->d_inode, list, len); | ||
5704 | } | ||
5705 | return len; | ||
5706 | } | ||
5707 | |||
5708 | static const struct xattr_handler nfs4_xattr_nfs4_label_handler = { | ||
5709 | .prefix = XATTR_SECURITY_PREFIX, | ||
5710 | .list = nfs4_xattr_list_nfs4_label, | ||
5711 | .get = nfs4_xattr_get_nfs4_label, | ||
5712 | .set = nfs4_xattr_set_nfs4_label, | ||
5713 | }; | ||
5714 | #endif | ||
5715 | |||
5716 | |||
5298 | /* | 5717 | /* |
5299 | * nfs_fhget will use either the mounted_on_fileid or the fileid | 5718 | * nfs_fhget will use either the mounted_on_fileid or the fileid |
5300 | */ | 5719 | */ |
@@ -5318,7 +5737,7 @@ static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir, | |||
5318 | struct page *page) | 5737 | struct page *page) |
5319 | { | 5738 | { |
5320 | struct nfs_server *server = NFS_SERVER(dir); | 5739 | struct nfs_server *server = NFS_SERVER(dir); |
5321 | u32 bitmask[2] = { | 5740 | u32 bitmask[3] = { |
5322 | [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS, | 5741 | [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS, |
5323 | }; | 5742 | }; |
5324 | struct nfs4_fs_locations_arg args = { | 5743 | struct nfs4_fs_locations_arg args = { |
@@ -5505,7 +5924,8 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
5505 | struct nfs41_exchange_id_args args = { | 5924 | struct nfs41_exchange_id_args args = { |
5506 | .verifier = &verifier, | 5925 | .verifier = &verifier, |
5507 | .client = clp, | 5926 | .client = clp, |
5508 | .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER, | 5927 | .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER | |
5928 | EXCHGID4_FLAG_BIND_PRINC_STATEID, | ||
5509 | }; | 5929 | }; |
5510 | struct nfs41_exchange_id_res res = { | 5930 | struct nfs41_exchange_id_res res = { |
5511 | 0 | 5931 | 0 |
@@ -5762,17 +6182,14 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | |||
5762 | */ | 6182 | */ |
5763 | static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | 6183 | static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) |
5764 | { | 6184 | { |
5765 | struct nfs4_session *session = args->client->cl_session; | 6185 | unsigned int max_rqst_sz, max_resp_sz; |
5766 | unsigned int mxrqst_sz = session->fc_target_max_rqst_sz, | 6186 | |
5767 | mxresp_sz = session->fc_target_max_resp_sz; | 6187 | max_rqst_sz = NFS_MAX_FILE_IO_SIZE + nfs41_maxwrite_overhead; |
6188 | max_resp_sz = NFS_MAX_FILE_IO_SIZE + nfs41_maxread_overhead; | ||
5768 | 6189 | ||
5769 | if (mxrqst_sz == 0) | ||
5770 | mxrqst_sz = NFS_MAX_FILE_IO_SIZE; | ||
5771 | if (mxresp_sz == 0) | ||
5772 | mxresp_sz = NFS_MAX_FILE_IO_SIZE; | ||
5773 | /* Fore channel attributes */ | 6190 | /* Fore channel attributes */ |
5774 | args->fc_attrs.max_rqst_sz = mxrqst_sz; | 6191 | args->fc_attrs.max_rqst_sz = max_rqst_sz; |
5775 | args->fc_attrs.max_resp_sz = mxresp_sz; | 6192 | args->fc_attrs.max_resp_sz = max_resp_sz; |
5776 | args->fc_attrs.max_ops = NFS4_MAX_OPS; | 6193 | args->fc_attrs.max_ops = NFS4_MAX_OPS; |
5777 | args->fc_attrs.max_reqs = max_session_slots; | 6194 | args->fc_attrs.max_reqs = max_session_slots; |
5778 | 6195 | ||
@@ -6159,12 +6576,14 @@ static const struct rpc_call_ops nfs4_reclaim_complete_call_ops = { | |||
6159 | /* | 6576 | /* |
6160 | * Issue a global reclaim complete. | 6577 | * Issue a global reclaim complete. |
6161 | */ | 6578 | */ |
6162 | static int nfs41_proc_reclaim_complete(struct nfs_client *clp) | 6579 | static int nfs41_proc_reclaim_complete(struct nfs_client *clp, |
6580 | struct rpc_cred *cred) | ||
6163 | { | 6581 | { |
6164 | struct nfs4_reclaim_complete_data *calldata; | 6582 | struct nfs4_reclaim_complete_data *calldata; |
6165 | struct rpc_task *task; | 6583 | struct rpc_task *task; |
6166 | struct rpc_message msg = { | 6584 | struct rpc_message msg = { |
6167 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RECLAIM_COMPLETE], | 6585 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RECLAIM_COMPLETE], |
6586 | .rpc_cred = cred, | ||
6168 | }; | 6587 | }; |
6169 | struct rpc_task_setup task_setup_data = { | 6588 | struct rpc_task_setup task_setup_data = { |
6170 | .rpc_client = clp->cl_rpcclient, | 6589 | .rpc_client = clp->cl_rpcclient, |
@@ -6348,6 +6767,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) | |||
6348 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET], | 6767 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET], |
6349 | .rpc_argp = &lgp->args, | 6768 | .rpc_argp = &lgp->args, |
6350 | .rpc_resp = &lgp->res, | 6769 | .rpc_resp = &lgp->res, |
6770 | .rpc_cred = lgp->cred, | ||
6351 | }; | 6771 | }; |
6352 | struct rpc_task_setup task_setup_data = { | 6772 | struct rpc_task_setup task_setup_data = { |
6353 | .rpc_client = server->client, | 6773 | .rpc_client = server->client, |
@@ -6451,6 +6871,7 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp) | |||
6451 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTRETURN], | 6871 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTRETURN], |
6452 | .rpc_argp = &lrp->args, | 6872 | .rpc_argp = &lrp->args, |
6453 | .rpc_resp = &lrp->res, | 6873 | .rpc_resp = &lrp->res, |
6874 | .rpc_cred = lrp->cred, | ||
6454 | }; | 6875 | }; |
6455 | struct rpc_task_setup task_setup_data = { | 6876 | struct rpc_task_setup task_setup_data = { |
6456 | .rpc_client = lrp->clp->cl_rpcclient, | 6877 | .rpc_client = lrp->clp->cl_rpcclient, |
@@ -6520,7 +6941,9 @@ int nfs4_proc_getdevicelist(struct nfs_server *server, | |||
6520 | EXPORT_SYMBOL_GPL(nfs4_proc_getdevicelist); | 6941 | EXPORT_SYMBOL_GPL(nfs4_proc_getdevicelist); |
6521 | 6942 | ||
6522 | static int | 6943 | static int |
6523 | _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) | 6944 | _nfs4_proc_getdeviceinfo(struct nfs_server *server, |
6945 | struct pnfs_device *pdev, | ||
6946 | struct rpc_cred *cred) | ||
6524 | { | 6947 | { |
6525 | struct nfs4_getdeviceinfo_args args = { | 6948 | struct nfs4_getdeviceinfo_args args = { |
6526 | .pdev = pdev, | 6949 | .pdev = pdev, |
@@ -6532,6 +6955,7 @@ _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) | |||
6532 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICEINFO], | 6955 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICEINFO], |
6533 | .rpc_argp = &args, | 6956 | .rpc_argp = &args, |
6534 | .rpc_resp = &res, | 6957 | .rpc_resp = &res, |
6958 | .rpc_cred = cred, | ||
6535 | }; | 6959 | }; |
6536 | int status; | 6960 | int status; |
6537 | 6961 | ||
@@ -6542,14 +6966,16 @@ _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) | |||
6542 | return status; | 6966 | return status; |
6543 | } | 6967 | } |
6544 | 6968 | ||
6545 | int nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) | 6969 | int nfs4_proc_getdeviceinfo(struct nfs_server *server, |
6970 | struct pnfs_device *pdev, | ||
6971 | struct rpc_cred *cred) | ||
6546 | { | 6972 | { |
6547 | struct nfs4_exception exception = { }; | 6973 | struct nfs4_exception exception = { }; |
6548 | int err; | 6974 | int err; |
6549 | 6975 | ||
6550 | do { | 6976 | do { |
6551 | err = nfs4_handle_exception(server, | 6977 | err = nfs4_handle_exception(server, |
6552 | _nfs4_proc_getdeviceinfo(server, pdev), | 6978 | _nfs4_proc_getdeviceinfo(server, pdev, cred), |
6553 | &exception); | 6979 | &exception); |
6554 | } while (exception.retry); | 6980 | } while (exception.retry); |
6555 | return err; | 6981 | return err; |
@@ -6733,7 +7159,9 @@ out: | |||
6733 | return err; | 7159 | return err; |
6734 | } | 7160 | } |
6735 | 7161 | ||
6736 | static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) | 7162 | static int _nfs41_test_stateid(struct nfs_server *server, |
7163 | nfs4_stateid *stateid, | ||
7164 | struct rpc_cred *cred) | ||
6737 | { | 7165 | { |
6738 | int status; | 7166 | int status; |
6739 | struct nfs41_test_stateid_args args = { | 7167 | struct nfs41_test_stateid_args args = { |
@@ -6744,6 +7172,7 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) | |||
6744 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID], | 7172 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID], |
6745 | .rpc_argp = &args, | 7173 | .rpc_argp = &args, |
6746 | .rpc_resp = &res, | 7174 | .rpc_resp = &res, |
7175 | .rpc_cred = cred, | ||
6747 | }; | 7176 | }; |
6748 | 7177 | ||
6749 | dprintk("NFS call test_stateid %p\n", stateid); | 7178 | dprintk("NFS call test_stateid %p\n", stateid); |
@@ -6764,17 +7193,20 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) | |||
6764 | * | 7193 | * |
6765 | * @server: server / transport on which to perform the operation | 7194 | * @server: server / transport on which to perform the operation |
6766 | * @stateid: state ID to test | 7195 | * @stateid: state ID to test |
7196 | * @cred: credential | ||
6767 | * | 7197 | * |
6768 | * Returns NFS_OK if the server recognizes that "stateid" is valid. | 7198 | * Returns NFS_OK if the server recognizes that "stateid" is valid. |
6769 | * Otherwise a negative NFS4ERR value is returned if the operation | 7199 | * Otherwise a negative NFS4ERR value is returned if the operation |
6770 | * failed or the state ID is not currently valid. | 7200 | * failed or the state ID is not currently valid. |
6771 | */ | 7201 | */ |
6772 | static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) | 7202 | static int nfs41_test_stateid(struct nfs_server *server, |
7203 | nfs4_stateid *stateid, | ||
7204 | struct rpc_cred *cred) | ||
6773 | { | 7205 | { |
6774 | struct nfs4_exception exception = { }; | 7206 | struct nfs4_exception exception = { }; |
6775 | int err; | 7207 | int err; |
6776 | do { | 7208 | do { |
6777 | err = _nfs41_test_stateid(server, stateid); | 7209 | err = _nfs41_test_stateid(server, stateid, cred); |
6778 | if (err != -NFS4ERR_DELAY) | 7210 | if (err != -NFS4ERR_DELAY) |
6779 | break; | 7211 | break; |
6780 | nfs4_handle_exception(server, err, &exception); | 7212 | nfs4_handle_exception(server, err, &exception); |
@@ -6823,10 +7255,12 @@ const struct rpc_call_ops nfs41_free_stateid_ops = { | |||
6823 | 7255 | ||
6824 | static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, | 7256 | static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, |
6825 | nfs4_stateid *stateid, | 7257 | nfs4_stateid *stateid, |
7258 | struct rpc_cred *cred, | ||
6826 | bool privileged) | 7259 | bool privileged) |
6827 | { | 7260 | { |
6828 | struct rpc_message msg = { | 7261 | struct rpc_message msg = { |
6829 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID], | 7262 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID], |
7263 | .rpc_cred = cred, | ||
6830 | }; | 7264 | }; |
6831 | struct rpc_task_setup task_setup = { | 7265 | struct rpc_task_setup task_setup = { |
6832 | .rpc_client = server->client, | 7266 | .rpc_client = server->client, |
@@ -6859,16 +7293,19 @@ static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, | |||
6859 | * | 7293 | * |
6860 | * @server: server / transport on which to perform the operation | 7294 | * @server: server / transport on which to perform the operation |
6861 | * @stateid: state ID to release | 7295 | * @stateid: state ID to release |
7296 | * @cred: credential | ||
6862 | * | 7297 | * |
6863 | * Returns NFS_OK if the server freed "stateid". Otherwise a | 7298 | * Returns NFS_OK if the server freed "stateid". Otherwise a |
6864 | * negative NFS4ERR value is returned. | 7299 | * negative NFS4ERR value is returned. |
6865 | */ | 7300 | */ |
6866 | static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) | 7301 | static int nfs41_free_stateid(struct nfs_server *server, |
7302 | nfs4_stateid *stateid, | ||
7303 | struct rpc_cred *cred) | ||
6867 | { | 7304 | { |
6868 | struct rpc_task *task; | 7305 | struct rpc_task *task; |
6869 | int ret; | 7306 | int ret; |
6870 | 7307 | ||
6871 | task = _nfs41_free_stateid(server, stateid, true); | 7308 | task = _nfs41_free_stateid(server, stateid, cred, true); |
6872 | if (IS_ERR(task)) | 7309 | if (IS_ERR(task)) |
6873 | return PTR_ERR(task); | 7310 | return PTR_ERR(task); |
6874 | ret = rpc_wait_for_completion_task(task); | 7311 | ret = rpc_wait_for_completion_task(task); |
@@ -6881,8 +7318,9 @@ static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) | |||
6881 | static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp) | 7318 | static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp) |
6882 | { | 7319 | { |
6883 | struct rpc_task *task; | 7320 | struct rpc_task *task; |
7321 | struct rpc_cred *cred = lsp->ls_state->owner->so_cred; | ||
6884 | 7322 | ||
6885 | task = _nfs41_free_stateid(server, &lsp->ls_stateid, false); | 7323 | task = _nfs41_free_stateid(server, &lsp->ls_stateid, cred, false); |
6886 | nfs4_free_lock_state(server, lsp); | 7324 | nfs4_free_lock_state(server, lsp); |
6887 | if (IS_ERR(task)) | 7325 | if (IS_ERR(task)) |
6888 | return PTR_ERR(task); | 7326 | return PTR_ERR(task); |
@@ -7004,11 +7442,33 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { | |||
7004 | }; | 7442 | }; |
7005 | #endif | 7443 | #endif |
7006 | 7444 | ||
7445 | #if defined(CONFIG_NFS_V4_2) | ||
7446 | static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { | ||
7447 | .minor_version = 2, | ||
7448 | .init_caps = NFS_CAP_READDIRPLUS | ||
7449 | | NFS_CAP_ATOMIC_OPEN | ||
7450 | | NFS_CAP_CHANGE_ATTR | ||
7451 | | NFS_CAP_POSIX_LOCK | ||
7452 | | NFS_CAP_STATEID_NFSV41 | ||
7453 | | NFS_CAP_ATOMIC_OPEN_V1, | ||
7454 | .call_sync = nfs4_call_sync_sequence, | ||
7455 | .match_stateid = nfs41_match_stateid, | ||
7456 | .find_root_sec = nfs41_find_root_sec, | ||
7457 | .free_lock_state = nfs41_free_lock_state, | ||
7458 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, | ||
7459 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, | ||
7460 | .state_renewal_ops = &nfs41_state_renewal_ops, | ||
7461 | }; | ||
7462 | #endif | ||
7463 | |||
7007 | const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = { | 7464 | const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = { |
7008 | [0] = &nfs_v4_0_minor_ops, | 7465 | [0] = &nfs_v4_0_minor_ops, |
7009 | #if defined(CONFIG_NFS_V4_1) | 7466 | #if defined(CONFIG_NFS_V4_1) |
7010 | [1] = &nfs_v4_1_minor_ops, | 7467 | [1] = &nfs_v4_1_minor_ops, |
7011 | #endif | 7468 | #endif |
7469 | #if defined(CONFIG_NFS_V4_2) | ||
7470 | [2] = &nfs_v4_2_minor_ops, | ||
7471 | #endif | ||
7012 | }; | 7472 | }; |
7013 | 7473 | ||
7014 | const struct inode_operations nfs4_dir_inode_operations = { | 7474 | const struct inode_operations nfs4_dir_inode_operations = { |
@@ -7108,6 +7568,9 @@ static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = { | |||
7108 | 7568 | ||
7109 | const struct xattr_handler *nfs4_xattr_handlers[] = { | 7569 | const struct xattr_handler *nfs4_xattr_handlers[] = { |
7110 | &nfs4_xattr_nfs4_acl_handler, | 7570 | &nfs4_xattr_nfs4_acl_handler, |
7571 | #ifdef CONFIG_NFS_V4_SECURITY_LABEL | ||
7572 | &nfs4_xattr_nfs4_label_handler, | ||
7573 | #endif | ||
7111 | NULL | 7574 | NULL |
7112 | }; | 7575 | }; |
7113 | 7576 | ||
diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c index c4e225e4a9af..36e21cb29d65 100644 --- a/fs/nfs/nfs4session.c +++ b/fs/nfs/nfs4session.c | |||
@@ -478,48 +478,12 @@ static int nfs41_check_session_ready(struct nfs_client *clp) | |||
478 | return 0; | 478 | return 0; |
479 | } | 479 | } |
480 | 480 | ||
481 | int nfs4_init_session(struct nfs_server *server) | 481 | int nfs4_init_session(struct nfs_client *clp) |
482 | { | 482 | { |
483 | struct nfs_client *clp = server->nfs_client; | ||
484 | struct nfs4_session *session; | ||
485 | unsigned int target_max_rqst_sz = NFS_MAX_FILE_IO_SIZE; | ||
486 | unsigned int target_max_resp_sz = NFS_MAX_FILE_IO_SIZE; | ||
487 | |||
488 | if (!nfs4_has_session(clp)) | 483 | if (!nfs4_has_session(clp)) |
489 | return 0; | 484 | return 0; |
490 | 485 | ||
491 | if (server->rsize != 0) | 486 | clear_bit(NFS4_SESSION_INITING, &clp->cl_session->session_state); |
492 | target_max_resp_sz = server->rsize; | ||
493 | target_max_resp_sz += nfs41_maxread_overhead; | ||
494 | |||
495 | if (server->wsize != 0) | ||
496 | target_max_rqst_sz = server->wsize; | ||
497 | target_max_rqst_sz += nfs41_maxwrite_overhead; | ||
498 | |||
499 | session = clp->cl_session; | ||
500 | spin_lock(&clp->cl_lock); | ||
501 | if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) { | ||
502 | /* Initialise targets and channel attributes */ | ||
503 | session->fc_target_max_rqst_sz = target_max_rqst_sz; | ||
504 | session->fc_attrs.max_rqst_sz = target_max_rqst_sz; | ||
505 | session->fc_target_max_resp_sz = target_max_resp_sz; | ||
506 | session->fc_attrs.max_resp_sz = target_max_resp_sz; | ||
507 | } else { | ||
508 | /* Just adjust the targets */ | ||
509 | if (target_max_rqst_sz > session->fc_target_max_rqst_sz) { | ||
510 | session->fc_target_max_rqst_sz = target_max_rqst_sz; | ||
511 | set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); | ||
512 | } | ||
513 | if (target_max_resp_sz > session->fc_target_max_resp_sz) { | ||
514 | session->fc_target_max_resp_sz = target_max_resp_sz; | ||
515 | set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); | ||
516 | } | ||
517 | } | ||
518 | spin_unlock(&clp->cl_lock); | ||
519 | |||
520 | if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) | ||
521 | nfs4_schedule_lease_recovery(clp); | ||
522 | |||
523 | return nfs41_check_session_ready(clp); | 487 | return nfs41_check_session_ready(clp); |
524 | } | 488 | } |
525 | 489 | ||
diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h index ff7d9f0f8a65..3a153d82b90c 100644 --- a/fs/nfs/nfs4session.h +++ b/fs/nfs/nfs4session.h | |||
@@ -66,9 +66,6 @@ struct nfs4_session { | |||
66 | struct nfs4_channel_attrs bc_attrs; | 66 | struct nfs4_channel_attrs bc_attrs; |
67 | struct nfs4_slot_table bc_slot_table; | 67 | struct nfs4_slot_table bc_slot_table; |
68 | struct nfs_client *clp; | 68 | struct nfs_client *clp; |
69 | /* Create session arguments */ | ||
70 | unsigned int fc_target_max_rqst_sz; | ||
71 | unsigned int fc_target_max_resp_sz; | ||
72 | }; | 69 | }; |
73 | 70 | ||
74 | enum nfs4_session_state { | 71 | enum nfs4_session_state { |
@@ -89,7 +86,7 @@ extern int nfs4_setup_session_slot_tables(struct nfs4_session *ses); | |||
89 | 86 | ||
90 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); | 87 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); |
91 | extern void nfs4_destroy_session(struct nfs4_session *session); | 88 | extern void nfs4_destroy_session(struct nfs4_session *session); |
92 | extern int nfs4_init_session(struct nfs_server *server); | 89 | extern int nfs4_init_session(struct nfs_client *clp); |
93 | extern int nfs4_init_ds_session(struct nfs_client *, unsigned long); | 90 | extern int nfs4_init_ds_session(struct nfs_client *, unsigned long); |
94 | 91 | ||
95 | extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl); | 92 | extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl); |
@@ -122,7 +119,7 @@ static inline int nfs4_has_persistent_session(const struct nfs_client *clp) | |||
122 | 119 | ||
123 | #else /* defined(CONFIG_NFS_V4_1) */ | 120 | #else /* defined(CONFIG_NFS_V4_1) */ |
124 | 121 | ||
125 | static inline int nfs4_init_session(struct nfs_server *server) | 122 | static inline int nfs4_init_session(struct nfs_client *clp) |
126 | { | 123 | { |
127 | return 0; | 124 | return 0; |
128 | } | 125 | } |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 1fab140764c4..e22862f13564 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -228,19 +228,8 @@ static int nfs41_setup_state_renewal(struct nfs_client *clp) | |||
228 | return status; | 228 | return status; |
229 | } | 229 | } |
230 | 230 | ||
231 | /* | 231 | static void nfs4_end_drain_slot_table(struct nfs4_slot_table *tbl) |
232 | * Back channel returns NFS4ERR_DELAY for new requests when | ||
233 | * NFS4_SESSION_DRAINING is set so there is no work to be done when draining | ||
234 | * is ended. | ||
235 | */ | ||
236 | static void nfs4_end_drain_session(struct nfs_client *clp) | ||
237 | { | 232 | { |
238 | struct nfs4_session *ses = clp->cl_session; | ||
239 | struct nfs4_slot_table *tbl; | ||
240 | |||
241 | if (ses == NULL) | ||
242 | return; | ||
243 | tbl = &ses->fc_slot_table; | ||
244 | if (test_and_clear_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) { | 233 | if (test_and_clear_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) { |
245 | spin_lock(&tbl->slot_tbl_lock); | 234 | spin_lock(&tbl->slot_tbl_lock); |
246 | nfs41_wake_slot_table(tbl); | 235 | nfs41_wake_slot_table(tbl); |
@@ -248,6 +237,16 @@ static void nfs4_end_drain_session(struct nfs_client *clp) | |||
248 | } | 237 | } |
249 | } | 238 | } |
250 | 239 | ||
240 | static void nfs4_end_drain_session(struct nfs_client *clp) | ||
241 | { | ||
242 | struct nfs4_session *ses = clp->cl_session; | ||
243 | |||
244 | if (ses != NULL) { | ||
245 | nfs4_end_drain_slot_table(&ses->bc_slot_table); | ||
246 | nfs4_end_drain_slot_table(&ses->fc_slot_table); | ||
247 | } | ||
248 | } | ||
249 | |||
251 | /* | 250 | /* |
252 | * Signal state manager thread if session fore channel is drained | 251 | * Signal state manager thread if session fore channel is drained |
253 | */ | 252 | */ |
@@ -1194,7 +1193,7 @@ void nfs4_schedule_state_manager(struct nfs_client *clp) | |||
1194 | snprintf(buf, sizeof(buf), "%s-manager", | 1193 | snprintf(buf, sizeof(buf), "%s-manager", |
1195 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); | 1194 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); |
1196 | rcu_read_unlock(); | 1195 | rcu_read_unlock(); |
1197 | task = kthread_run(nfs4_run_state_manager, clp, buf); | 1196 | task = kthread_run(nfs4_run_state_manager, clp, "%s", buf); |
1198 | if (IS_ERR(task)) { | 1197 | if (IS_ERR(task)) { |
1199 | printk(KERN_ERR "%s: kthread_run: %ld\n", | 1198 | printk(KERN_ERR "%s: kthread_run: %ld\n", |
1200 | __func__, PTR_ERR(task)); | 1199 | __func__, PTR_ERR(task)); |
@@ -1373,13 +1372,13 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ | |||
1373 | /* Guard against delegation returns and new lock/unlock calls */ | 1372 | /* Guard against delegation returns and new lock/unlock calls */ |
1374 | down_write(&nfsi->rwsem); | 1373 | down_write(&nfsi->rwsem); |
1375 | /* Protect inode->i_flock using the BKL */ | 1374 | /* Protect inode->i_flock using the BKL */ |
1376 | lock_flocks(); | 1375 | spin_lock(&inode->i_lock); |
1377 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 1376 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
1378 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) | 1377 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) |
1379 | continue; | 1378 | continue; |
1380 | if (nfs_file_open_context(fl->fl_file)->state != state) | 1379 | if (nfs_file_open_context(fl->fl_file)->state != state) |
1381 | continue; | 1380 | continue; |
1382 | unlock_flocks(); | 1381 | spin_unlock(&inode->i_lock); |
1383 | status = ops->recover_lock(state, fl); | 1382 | status = ops->recover_lock(state, fl); |
1384 | switch (status) { | 1383 | switch (status) { |
1385 | case 0: | 1384 | case 0: |
@@ -1406,9 +1405,9 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ | |||
1406 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | 1405 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ |
1407 | status = 0; | 1406 | status = 0; |
1408 | } | 1407 | } |
1409 | lock_flocks(); | 1408 | spin_lock(&inode->i_lock); |
1410 | } | 1409 | } |
1411 | unlock_flocks(); | 1410 | spin_unlock(&inode->i_lock); |
1412 | out: | 1411 | out: |
1413 | up_write(&nfsi->rwsem); | 1412 | up_write(&nfsi->rwsem); |
1414 | return status; | 1413 | return status; |
@@ -1563,11 +1562,12 @@ static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp) | |||
1563 | } | 1562 | } |
1564 | 1563 | ||
1565 | static void nfs4_reclaim_complete(struct nfs_client *clp, | 1564 | static void nfs4_reclaim_complete(struct nfs_client *clp, |
1566 | const struct nfs4_state_recovery_ops *ops) | 1565 | const struct nfs4_state_recovery_ops *ops, |
1566 | struct rpc_cred *cred) | ||
1567 | { | 1567 | { |
1568 | /* Notify the server we're done reclaiming our state */ | 1568 | /* Notify the server we're done reclaiming our state */ |
1569 | if (ops->reclaim_complete) | 1569 | if (ops->reclaim_complete) |
1570 | (void)ops->reclaim_complete(clp); | 1570 | (void)ops->reclaim_complete(clp, cred); |
1571 | } | 1571 | } |
1572 | 1572 | ||
1573 | static void nfs4_clear_reclaim_server(struct nfs_server *server) | 1573 | static void nfs4_clear_reclaim_server(struct nfs_server *server) |
@@ -1612,9 +1612,15 @@ static int nfs4_state_clear_reclaim_reboot(struct nfs_client *clp) | |||
1612 | 1612 | ||
1613 | static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) | 1613 | static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) |
1614 | { | 1614 | { |
1615 | const struct nfs4_state_recovery_ops *ops; | ||
1616 | struct rpc_cred *cred; | ||
1617 | |||
1615 | if (!nfs4_state_clear_reclaim_reboot(clp)) | 1618 | if (!nfs4_state_clear_reclaim_reboot(clp)) |
1616 | return; | 1619 | return; |
1617 | nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops); | 1620 | ops = clp->cl_mvops->reboot_recovery_ops; |
1621 | cred = ops->get_clid_cred(clp); | ||
1622 | nfs4_reclaim_complete(clp, ops, cred); | ||
1623 | put_rpccred(cred); | ||
1618 | } | 1624 | } |
1619 | 1625 | ||
1620 | static void nfs_delegation_clear_all(struct nfs_client *clp) | 1626 | static void nfs_delegation_clear_all(struct nfs_client *clp) |
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index a5e1a3026d48..5dbe2d269210 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "delegation.h" | 9 | #include "delegation.h" |
10 | #include "internal.h" | 10 | #include "internal.h" |
11 | #include "nfs4_fs.h" | 11 | #include "nfs4_fs.h" |
12 | #include "dns_resolve.h" | ||
12 | #include "pnfs.h" | 13 | #include "pnfs.h" |
13 | #include "nfs.h" | 14 | #include "nfs.h" |
14 | 15 | ||
@@ -331,18 +332,24 @@ static int __init init_nfs_v4(void) | |||
331 | { | 332 | { |
332 | int err; | 333 | int err; |
333 | 334 | ||
334 | err = nfs_idmap_init(); | 335 | err = nfs_dns_resolver_init(); |
335 | if (err) | 336 | if (err) |
336 | goto out; | 337 | goto out; |
337 | 338 | ||
338 | err = nfs4_register_sysctl(); | 339 | err = nfs_idmap_init(); |
339 | if (err) | 340 | if (err) |
340 | goto out1; | 341 | goto out1; |
341 | 342 | ||
343 | err = nfs4_register_sysctl(); | ||
344 | if (err) | ||
345 | goto out2; | ||
346 | |||
342 | register_nfs_version(&nfs_v4); | 347 | register_nfs_version(&nfs_v4); |
343 | return 0; | 348 | return 0; |
344 | out1: | 349 | out2: |
345 | nfs_idmap_quit(); | 350 | nfs_idmap_quit(); |
351 | out1: | ||
352 | nfs_dns_resolver_destroy(); | ||
346 | out: | 353 | out: |
347 | return err; | 354 | return err; |
348 | } | 355 | } |
@@ -352,6 +359,7 @@ static void __exit exit_nfs_v4(void) | |||
352 | unregister_nfs_version(&nfs_v4); | 359 | unregister_nfs_version(&nfs_v4); |
353 | nfs4_unregister_sysctl(); | 360 | nfs4_unregister_sysctl(); |
354 | nfs_idmap_quit(); | 361 | nfs_idmap_quit(); |
362 | nfs_dns_resolver_destroy(); | ||
355 | } | 363 | } |
356 | 364 | ||
357 | MODULE_LICENSE("GPL"); | 365 | MODULE_LICENSE("GPL"); |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 4be8d135ed61..3850b018815f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -102,12 +102,23 @@ static int nfs4_stat_to_errno(int); | |||
102 | #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) | 102 | #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) |
103 | #define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) | 103 | #define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) |
104 | #define nfs4_group_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) | 104 | #define nfs4_group_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) |
105 | #ifdef CONFIG_NFS_V4_SECURITY_LABEL | ||
106 | /* PI(4 bytes) + LFS(4 bytes) + 1(for null terminator?) + MAXLABELLEN */ | ||
107 | #define nfs4_label_maxsz (4 + 4 + 1 + XDR_QUADLEN(NFS4_MAXLABELLEN)) | ||
108 | #define encode_readdir_space 24 | ||
109 | #define encode_readdir_bitmask_sz 3 | ||
110 | #else | ||
111 | #define nfs4_label_maxsz 0 | ||
112 | #define encode_readdir_space 20 | ||
113 | #define encode_readdir_bitmask_sz 2 | ||
114 | #endif | ||
105 | /* We support only one layout type per file system */ | 115 | /* We support only one layout type per file system */ |
106 | #define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8) | 116 | #define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8) |
107 | /* This is based on getfattr, which uses the most attributes: */ | 117 | /* This is based on getfattr, which uses the most attributes: */ |
108 | #define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \ | 118 | #define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \ |
109 | 3 + 3 + 3 + nfs4_owner_maxsz + \ | 119 | 3 + 3 + 3 + nfs4_owner_maxsz + \ |
110 | nfs4_group_maxsz + decode_mdsthreshold_maxsz)) | 120 | nfs4_group_maxsz + nfs4_label_maxsz + \ |
121 | decode_mdsthreshold_maxsz)) | ||
111 | #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \ | 122 | #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \ |
112 | nfs4_fattr_value_maxsz) | 123 | nfs4_fattr_value_maxsz) |
113 | #define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz) | 124 | #define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz) |
@@ -115,6 +126,7 @@ static int nfs4_stat_to_errno(int); | |||
115 | 1 + 2 + 1 + \ | 126 | 1 + 2 + 1 + \ |
116 | nfs4_owner_maxsz + \ | 127 | nfs4_owner_maxsz + \ |
117 | nfs4_group_maxsz + \ | 128 | nfs4_group_maxsz + \ |
129 | nfs4_label_maxsz + \ | ||
118 | 4 + 4) | 130 | 4 + 4) |
119 | #define encode_savefh_maxsz (op_encode_hdr_maxsz) | 131 | #define encode_savefh_maxsz (op_encode_hdr_maxsz) |
120 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) | 132 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) |
@@ -192,9 +204,11 @@ static int nfs4_stat_to_errno(int); | |||
192 | encode_stateid_maxsz + 3) | 204 | encode_stateid_maxsz + 3) |
193 | #define decode_read_maxsz (op_decode_hdr_maxsz + 2) | 205 | #define decode_read_maxsz (op_decode_hdr_maxsz + 2) |
194 | #define encode_readdir_maxsz (op_encode_hdr_maxsz + \ | 206 | #define encode_readdir_maxsz (op_encode_hdr_maxsz + \ |
195 | 2 + encode_verifier_maxsz + 5) | 207 | 2 + encode_verifier_maxsz + 5 + \ |
208 | nfs4_label_maxsz) | ||
196 | #define decode_readdir_maxsz (op_decode_hdr_maxsz + \ | 209 | #define decode_readdir_maxsz (op_decode_hdr_maxsz + \ |
197 | decode_verifier_maxsz) | 210 | decode_verifier_maxsz + \ |
211 | nfs4_label_maxsz + nfs4_fattr_maxsz) | ||
198 | #define encode_readlink_maxsz (op_encode_hdr_maxsz) | 212 | #define encode_readlink_maxsz (op_encode_hdr_maxsz) |
199 | #define decode_readlink_maxsz (op_decode_hdr_maxsz + 1) | 213 | #define decode_readlink_maxsz (op_decode_hdr_maxsz + 1) |
200 | #define encode_write_maxsz (op_encode_hdr_maxsz + \ | 214 | #define encode_write_maxsz (op_encode_hdr_maxsz + \ |
@@ -853,6 +867,12 @@ const u32 nfs41_maxread_overhead = ((RPC_MAX_HEADER_WITH_AUTH + | |||
853 | decode_sequence_maxsz + | 867 | decode_sequence_maxsz + |
854 | decode_putfh_maxsz) * | 868 | decode_putfh_maxsz) * |
855 | XDR_UNIT); | 869 | XDR_UNIT); |
870 | |||
871 | const u32 nfs41_maxgetdevinfo_overhead = ((RPC_MAX_REPHEADER_WITH_AUTH + | ||
872 | compound_decode_hdr_maxsz + | ||
873 | decode_sequence_maxsz) * | ||
874 | XDR_UNIT); | ||
875 | EXPORT_SYMBOL_GPL(nfs41_maxgetdevinfo_overhead); | ||
856 | #endif /* CONFIG_NFS_V4_1 */ | 876 | #endif /* CONFIG_NFS_V4_1 */ |
857 | 877 | ||
858 | static const umode_t nfs_type2fmt[] = { | 878 | static const umode_t nfs_type2fmt[] = { |
@@ -968,7 +988,9 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve | |||
968 | encode_opaque_fixed(xdr, verf->data, NFS4_VERIFIER_SIZE); | 988 | encode_opaque_fixed(xdr, verf->data, NFS4_VERIFIER_SIZE); |
969 | } | 989 | } |
970 | 990 | ||
971 | static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server) | 991 | static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, |
992 | const struct nfs4_label *label, | ||
993 | const struct nfs_server *server) | ||
972 | { | 994 | { |
973 | char owner_name[IDMAP_NAMESZ]; | 995 | char owner_name[IDMAP_NAMESZ]; |
974 | char owner_group[IDMAP_NAMESZ]; | 996 | char owner_group[IDMAP_NAMESZ]; |
@@ -977,17 +999,19 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
977 | __be32 *p; | 999 | __be32 *p; |
978 | __be32 *q; | 1000 | __be32 *q; |
979 | int len; | 1001 | int len; |
1002 | uint32_t bmval_len = 2; | ||
980 | uint32_t bmval0 = 0; | 1003 | uint32_t bmval0 = 0; |
981 | uint32_t bmval1 = 0; | 1004 | uint32_t bmval1 = 0; |
1005 | uint32_t bmval2 = 0; | ||
982 | 1006 | ||
983 | /* | 1007 | /* |
984 | * We reserve enough space to write the entire attribute buffer at once. | 1008 | * We reserve enough space to write the entire attribute buffer at once. |
985 | * In the worst-case, this would be | 1009 | * In the worst-case, this would be |
986 | * 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime) | 1010 | * 16(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime) |
987 | * = 36 bytes, plus any contribution from variable-length fields | 1011 | * = 40 bytes, plus any contribution from variable-length fields |
988 | * such as owner/group. | 1012 | * such as owner/group. |
989 | */ | 1013 | */ |
990 | len = 16; | 1014 | len = 8; |
991 | 1015 | ||
992 | /* Sigh */ | 1016 | /* Sigh */ |
993 | if (iap->ia_valid & ATTR_SIZE) | 1017 | if (iap->ia_valid & ATTR_SIZE) |
@@ -1025,15 +1049,22 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
1025 | len += 16; | 1049 | len += 16; |
1026 | else if (iap->ia_valid & ATTR_MTIME) | 1050 | else if (iap->ia_valid & ATTR_MTIME) |
1027 | len += 4; | 1051 | len += 4; |
1052 | if (label) { | ||
1053 | len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2); | ||
1054 | bmval_len = 3; | ||
1055 | } | ||
1056 | |||
1057 | len += bmval_len << 2; | ||
1028 | p = reserve_space(xdr, len); | 1058 | p = reserve_space(xdr, len); |
1029 | 1059 | ||
1030 | /* | 1060 | /* |
1031 | * We write the bitmap length now, but leave the bitmap and the attribute | 1061 | * We write the bitmap length now, but leave the bitmap and the attribute |
1032 | * buffer length to be backfilled at the end of this routine. | 1062 | * buffer length to be backfilled at the end of this routine. |
1033 | */ | 1063 | */ |
1034 | *p++ = cpu_to_be32(2); | 1064 | *p++ = cpu_to_be32(bmval_len); |
1035 | q = p; | 1065 | q = p; |
1036 | p += 3; | 1066 | /* Skip bitmap entries + attrlen */ |
1067 | p += bmval_len + 1; | ||
1037 | 1068 | ||
1038 | if (iap->ia_valid & ATTR_SIZE) { | 1069 | if (iap->ia_valid & ATTR_SIZE) { |
1039 | bmval0 |= FATTR4_WORD0_SIZE; | 1070 | bmval0 |= FATTR4_WORD0_SIZE; |
@@ -1071,6 +1102,13 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
1071 | bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; | 1102 | bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; |
1072 | *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME); | 1103 | *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME); |
1073 | } | 1104 | } |
1105 | if (label) { | ||
1106 | bmval2 |= FATTR4_WORD2_SECURITY_LABEL; | ||
1107 | *p++ = cpu_to_be32(label->lfs); | ||
1108 | *p++ = cpu_to_be32(label->pi); | ||
1109 | *p++ = cpu_to_be32(label->len); | ||
1110 | p = xdr_encode_opaque_fixed(p, label->label, label->len); | ||
1111 | } | ||
1074 | 1112 | ||
1075 | /* | 1113 | /* |
1076 | * Now we backfill the bitmap and the attribute buffer length. | 1114 | * Now we backfill the bitmap and the attribute buffer length. |
@@ -1080,9 +1118,11 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
1080 | len, ((char *)p - (char *)q) + 4); | 1118 | len, ((char *)p - (char *)q) + 4); |
1081 | BUG(); | 1119 | BUG(); |
1082 | } | 1120 | } |
1083 | len = (char *)p - (char *)q - 12; | ||
1084 | *q++ = htonl(bmval0); | 1121 | *q++ = htonl(bmval0); |
1085 | *q++ = htonl(bmval1); | 1122 | *q++ = htonl(bmval1); |
1123 | if (bmval_len == 3) | ||
1124 | *q++ = htonl(bmval2); | ||
1125 | len = (char *)p - (char *)(q + 1); | ||
1086 | *q = htonl(len); | 1126 | *q = htonl(len); |
1087 | 1127 | ||
1088 | /* out: */ | 1128 | /* out: */ |
@@ -1136,7 +1176,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * | |||
1136 | } | 1176 | } |
1137 | 1177 | ||
1138 | encode_string(xdr, create->name->len, create->name->name); | 1178 | encode_string(xdr, create->name->len, create->name->name); |
1139 | encode_attrs(xdr, create->attrs, create->server); | 1179 | encode_attrs(xdr, create->attrs, create->label, create->server); |
1140 | } | 1180 | } |
1141 | 1181 | ||
1142 | static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr) | 1182 | static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr) |
@@ -1188,8 +1228,10 @@ encode_getattr_three(struct xdr_stream *xdr, | |||
1188 | 1228 | ||
1189 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) | 1229 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) |
1190 | { | 1230 | { |
1191 | encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0], | 1231 | encode_getattr_three(xdr, bitmask[0] & nfs4_fattr_bitmap[0], |
1192 | bitmask[1] & nfs4_fattr_bitmap[1], hdr); | 1232 | bitmask[1] & nfs4_fattr_bitmap[1], |
1233 | bitmask[2] & nfs4_fattr_bitmap[2], | ||
1234 | hdr); | ||
1193 | } | 1235 | } |
1194 | 1236 | ||
1195 | static void encode_getfattr_open(struct xdr_stream *xdr, const u32 *bitmask, | 1237 | static void encode_getfattr_open(struct xdr_stream *xdr, const u32 *bitmask, |
@@ -1367,11 +1409,11 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op | |||
1367 | switch(arg->createmode) { | 1409 | switch(arg->createmode) { |
1368 | case NFS4_CREATE_UNCHECKED: | 1410 | case NFS4_CREATE_UNCHECKED: |
1369 | *p = cpu_to_be32(NFS4_CREATE_UNCHECKED); | 1411 | *p = cpu_to_be32(NFS4_CREATE_UNCHECKED); |
1370 | encode_attrs(xdr, arg->u.attrs, arg->server); | 1412 | encode_attrs(xdr, arg->u.attrs, arg->label, arg->server); |
1371 | break; | 1413 | break; |
1372 | case NFS4_CREATE_GUARDED: | 1414 | case NFS4_CREATE_GUARDED: |
1373 | *p = cpu_to_be32(NFS4_CREATE_GUARDED); | 1415 | *p = cpu_to_be32(NFS4_CREATE_GUARDED); |
1374 | encode_attrs(xdr, arg->u.attrs, arg->server); | 1416 | encode_attrs(xdr, arg->u.attrs, arg->label, arg->server); |
1375 | break; | 1417 | break; |
1376 | case NFS4_CREATE_EXCLUSIVE: | 1418 | case NFS4_CREATE_EXCLUSIVE: |
1377 | *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); | 1419 | *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); |
@@ -1381,7 +1423,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op | |||
1381 | *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1); | 1423 | *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1); |
1382 | encode_nfs4_verifier(xdr, &arg->u.verifier); | 1424 | encode_nfs4_verifier(xdr, &arg->u.verifier); |
1383 | dummy.ia_valid = 0; | 1425 | dummy.ia_valid = 0; |
1384 | encode_attrs(xdr, &dummy, arg->server); | 1426 | encode_attrs(xdr, &dummy, arg->label, arg->server); |
1385 | } | 1427 | } |
1386 | } | 1428 | } |
1387 | 1429 | ||
@@ -1532,7 +1574,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, | |||
1532 | 1574 | ||
1533 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) | 1575 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) |
1534 | { | 1576 | { |
1535 | uint32_t attrs[2] = { | 1577 | uint32_t attrs[3] = { |
1536 | FATTR4_WORD0_RDATTR_ERROR, | 1578 | FATTR4_WORD0_RDATTR_ERROR, |
1537 | FATTR4_WORD1_MOUNTED_ON_FILEID, | 1579 | FATTR4_WORD1_MOUNTED_ON_FILEID, |
1538 | }; | 1580 | }; |
@@ -1555,20 +1597,26 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1555 | encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr); | 1597 | encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr); |
1556 | encode_uint64(xdr, readdir->cookie); | 1598 | encode_uint64(xdr, readdir->cookie); |
1557 | encode_nfs4_verifier(xdr, &readdir->verifier); | 1599 | encode_nfs4_verifier(xdr, &readdir->verifier); |
1558 | p = reserve_space(xdr, 20); | 1600 | p = reserve_space(xdr, encode_readdir_space); |
1559 | *p++ = cpu_to_be32(dircount); | 1601 | *p++ = cpu_to_be32(dircount); |
1560 | *p++ = cpu_to_be32(readdir->count); | 1602 | *p++ = cpu_to_be32(readdir->count); |
1561 | *p++ = cpu_to_be32(2); | 1603 | *p++ = cpu_to_be32(encode_readdir_bitmask_sz); |
1562 | |||
1563 | *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); | 1604 | *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); |
1564 | *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); | 1605 | *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); |
1606 | if (encode_readdir_bitmask_sz > 2) { | ||
1607 | if (hdr->minorversion > 1) | ||
1608 | attrs[2] |= FATTR4_WORD2_SECURITY_LABEL; | ||
1609 | p++, *p++ = cpu_to_be32(attrs[2] & readdir->bitmask[2]); | ||
1610 | } | ||
1565 | memcpy(verf, readdir->verifier.data, sizeof(verf)); | 1611 | memcpy(verf, readdir->verifier.data, sizeof(verf)); |
1566 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", | 1612 | |
1613 | dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x:%08x\n", | ||
1567 | __func__, | 1614 | __func__, |
1568 | (unsigned long long)readdir->cookie, | 1615 | (unsigned long long)readdir->cookie, |
1569 | verf[0], verf[1], | 1616 | verf[0], verf[1], |
1570 | attrs[0] & readdir->bitmask[0], | 1617 | attrs[0] & readdir->bitmask[0], |
1571 | attrs[1] & readdir->bitmask[1]); | 1618 | attrs[1] & readdir->bitmask[1], |
1619 | attrs[2] & readdir->bitmask[2]); | ||
1572 | } | 1620 | } |
1573 | 1621 | ||
1574 | static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr) | 1622 | static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr) |
@@ -1627,7 +1675,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs | |||
1627 | { | 1675 | { |
1628 | encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr); | 1676 | encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr); |
1629 | encode_nfs4_stateid(xdr, &arg->stateid); | 1677 | encode_nfs4_stateid(xdr, &arg->stateid); |
1630 | encode_attrs(xdr, arg->iap, server); | 1678 | encode_attrs(xdr, arg->iap, arg->label, server); |
1631 | } | 1679 | } |
1632 | 1680 | ||
1633 | static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr) | 1681 | static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr) |
@@ -1889,7 +1937,7 @@ encode_getdeviceinfo(struct xdr_stream *xdr, | |||
1889 | p = xdr_encode_opaque_fixed(p, args->pdev->dev_id.data, | 1937 | p = xdr_encode_opaque_fixed(p, args->pdev->dev_id.data, |
1890 | NFS4_DEVICEID4_SIZE); | 1938 | NFS4_DEVICEID4_SIZE); |
1891 | *p++ = cpu_to_be32(args->pdev->layout_type); | 1939 | *p++ = cpu_to_be32(args->pdev->layout_type); |
1892 | *p++ = cpu_to_be32(args->pdev->pglen); /* gdia_maxcount */ | 1940 | *p++ = cpu_to_be32(args->pdev->maxcount); /* gdia_maxcount */ |
1893 | *p++ = cpu_to_be32(0); /* bitmap length 0 */ | 1941 | *p++ = cpu_to_be32(0); /* bitmap length 0 */ |
1894 | } | 1942 | } |
1895 | 1943 | ||
@@ -4038,6 +4086,56 @@ static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap, | |||
4038 | return status; | 4086 | return status; |
4039 | } | 4087 | } |
4040 | 4088 | ||
4089 | static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap, | ||
4090 | struct nfs4_label *label) | ||
4091 | { | ||
4092 | uint32_t pi = 0; | ||
4093 | uint32_t lfs = 0; | ||
4094 | __u32 len; | ||
4095 | __be32 *p; | ||
4096 | int status = 0; | ||
4097 | |||
4098 | if (unlikely(bitmap[2] & (FATTR4_WORD2_SECURITY_LABEL - 1U))) | ||
4099 | return -EIO; | ||
4100 | if (likely(bitmap[2] & FATTR4_WORD2_SECURITY_LABEL)) { | ||
4101 | p = xdr_inline_decode(xdr, 4); | ||
4102 | if (unlikely(!p)) | ||
4103 | goto out_overflow; | ||
4104 | lfs = be32_to_cpup(p++); | ||
4105 | p = xdr_inline_decode(xdr, 4); | ||
4106 | if (unlikely(!p)) | ||
4107 | goto out_overflow; | ||
4108 | pi = be32_to_cpup(p++); | ||
4109 | p = xdr_inline_decode(xdr, 4); | ||
4110 | if (unlikely(!p)) | ||
4111 | goto out_overflow; | ||
4112 | len = be32_to_cpup(p++); | ||
4113 | p = xdr_inline_decode(xdr, len); | ||
4114 | if (unlikely(!p)) | ||
4115 | goto out_overflow; | ||
4116 | if (len < NFS4_MAXLABELLEN) { | ||
4117 | if (label) { | ||
4118 | memcpy(label->label, p, len); | ||
4119 | label->len = len; | ||
4120 | label->pi = pi; | ||
4121 | label->lfs = lfs; | ||
4122 | status = NFS_ATTR_FATTR_V4_SECURITY_LABEL; | ||
4123 | } | ||
4124 | bitmap[2] &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
4125 | } else | ||
4126 | printk(KERN_WARNING "%s: label too long (%u)!\n", | ||
4127 | __func__, len); | ||
4128 | } | ||
4129 | if (label && label->label) | ||
4130 | dprintk("%s: label=%s, len=%d, PI=%d, LFS=%d\n", __func__, | ||
4131 | (char *)label->label, label->len, label->pi, label->lfs); | ||
4132 | return status; | ||
4133 | |||
4134 | out_overflow: | ||
4135 | print_overflow_msg(__func__, xdr); | ||
4136 | return -EIO; | ||
4137 | } | ||
4138 | |||
4041 | static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) | 4139 | static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) |
4042 | { | 4140 | { |
4043 | int status = 0; | 4141 | int status = 0; |
@@ -4380,7 +4478,7 @@ out_overflow: | |||
4380 | 4478 | ||
4381 | static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | 4479 | static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, |
4382 | struct nfs_fattr *fattr, struct nfs_fh *fh, | 4480 | struct nfs_fattr *fattr, struct nfs_fh *fh, |
4383 | struct nfs4_fs_locations *fs_loc, | 4481 | struct nfs4_fs_locations *fs_loc, struct nfs4_label *label, |
4384 | const struct nfs_server *server) | 4482 | const struct nfs_server *server) |
4385 | { | 4483 | { |
4386 | int status; | 4484 | int status; |
@@ -4488,6 +4586,13 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | |||
4488 | if (status < 0) | 4586 | if (status < 0) |
4489 | goto xdr_error; | 4587 | goto xdr_error; |
4490 | 4588 | ||
4589 | if (label) { | ||
4590 | status = decode_attr_security_label(xdr, bitmap, label); | ||
4591 | if (status < 0) | ||
4592 | goto xdr_error; | ||
4593 | fattr->valid |= status; | ||
4594 | } | ||
4595 | |||
4491 | xdr_error: | 4596 | xdr_error: |
4492 | dprintk("%s: xdr returned %d\n", __func__, -status); | 4597 | dprintk("%s: xdr returned %d\n", __func__, -status); |
4493 | return status; | 4598 | return status; |
@@ -4495,7 +4600,7 @@ xdr_error: | |||
4495 | 4600 | ||
4496 | static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr, | 4601 | static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr, |
4497 | struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc, | 4602 | struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc, |
4498 | const struct nfs_server *server) | 4603 | struct nfs4_label *label, const struct nfs_server *server) |
4499 | { | 4604 | { |
4500 | unsigned int savep; | 4605 | unsigned int savep; |
4501 | uint32_t attrlen, | 4606 | uint32_t attrlen, |
@@ -4514,7 +4619,8 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat | |||
4514 | if (status < 0) | 4619 | if (status < 0) |
4515 | goto xdr_error; | 4620 | goto xdr_error; |
4516 | 4621 | ||
4517 | status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc, server); | 4622 | status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc, |
4623 | label, server); | ||
4518 | if (status < 0) | 4624 | if (status < 0) |
4519 | goto xdr_error; | 4625 | goto xdr_error; |
4520 | 4626 | ||
@@ -4524,10 +4630,16 @@ xdr_error: | |||
4524 | return status; | 4630 | return status; |
4525 | } | 4631 | } |
4526 | 4632 | ||
4633 | static int decode_getfattr_label(struct xdr_stream *xdr, struct nfs_fattr *fattr, | ||
4634 | struct nfs4_label *label, const struct nfs_server *server) | ||
4635 | { | ||
4636 | return decode_getfattr_generic(xdr, fattr, NULL, NULL, label, server); | ||
4637 | } | ||
4638 | |||
4527 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, | 4639 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, |
4528 | const struct nfs_server *server) | 4640 | const struct nfs_server *server) |
4529 | { | 4641 | { |
4530 | return decode_getfattr_generic(xdr, fattr, NULL, NULL, server); | 4642 | return decode_getfattr_generic(xdr, fattr, NULL, NULL, NULL, server); |
4531 | } | 4643 | } |
4532 | 4644 | ||
4533 | /* | 4645 | /* |
@@ -5919,7 +6031,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
5919 | status = decode_getfh(xdr, res->fh); | 6031 | status = decode_getfh(xdr, res->fh); |
5920 | if (status) | 6032 | if (status) |
5921 | goto out; | 6033 | goto out; |
5922 | status = decode_getfattr(xdr, res->fattr, res->server); | 6034 | status = decode_getfattr_label(xdr, res->fattr, res->label, res->server); |
5923 | out: | 6035 | out: |
5924 | return status; | 6036 | return status; |
5925 | } | 6037 | } |
@@ -5945,7 +6057,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, | |||
5945 | goto out; | 6057 | goto out; |
5946 | status = decode_getfh(xdr, res->fh); | 6058 | status = decode_getfh(xdr, res->fh); |
5947 | if (status == 0) | 6059 | if (status == 0) |
5948 | status = decode_getfattr(xdr, res->fattr, res->server); | 6060 | status = decode_getfattr_label(xdr, res->fattr, |
6061 | res->label, res->server); | ||
5949 | out: | 6062 | out: |
5950 | return status; | 6063 | return status; |
5951 | } | 6064 | } |
@@ -6036,7 +6149,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
6036 | status = decode_restorefh(xdr); | 6149 | status = decode_restorefh(xdr); |
6037 | if (status) | 6150 | if (status) |
6038 | goto out; | 6151 | goto out; |
6039 | decode_getfattr(xdr, res->fattr, res->server); | 6152 | decode_getfattr_label(xdr, res->fattr, res->label, res->server); |
6040 | out: | 6153 | out: |
6041 | return status; | 6154 | return status; |
6042 | } | 6155 | } |
@@ -6065,7 +6178,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
6065 | status = decode_getfh(xdr, res->fh); | 6178 | status = decode_getfh(xdr, res->fh); |
6066 | if (status) | 6179 | if (status) |
6067 | goto out; | 6180 | goto out; |
6068 | decode_getfattr(xdr, res->fattr, res->server); | 6181 | decode_getfattr_label(xdr, res->fattr, res->label, res->server); |
6069 | out: | 6182 | out: |
6070 | return status; | 6183 | return status; |
6071 | } | 6184 | } |
@@ -6097,7 +6210,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
6097 | status = decode_putfh(xdr); | 6210 | status = decode_putfh(xdr); |
6098 | if (status) | 6211 | if (status) |
6099 | goto out; | 6212 | goto out; |
6100 | status = decode_getfattr(xdr, res->fattr, res->server); | 6213 | status = decode_getfattr_label(xdr, res->fattr, res->label, res->server); |
6101 | out: | 6214 | out: |
6102 | return status; | 6215 | return status; |
6103 | } | 6216 | } |
@@ -6230,7 +6343,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
6230 | goto out; | 6343 | goto out; |
6231 | if (res->access_request) | 6344 | if (res->access_request) |
6232 | decode_access(xdr, &res->access_supported, &res->access_result); | 6345 | decode_access(xdr, &res->access_supported, &res->access_result); |
6233 | decode_getfattr(xdr, res->f_attr, res->server); | 6346 | decode_getfattr_label(xdr, res->f_attr, res->f_label, res->server); |
6234 | out: | 6347 | out: |
6235 | return status; | 6348 | return status; |
6236 | } | 6349 | } |
@@ -6307,7 +6420,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, | |||
6307 | status = decode_setattr(xdr); | 6420 | status = decode_setattr(xdr); |
6308 | if (status) | 6421 | if (status) |
6309 | goto out; | 6422 | goto out; |
6310 | decode_getfattr(xdr, res->fattr, res->server); | 6423 | decode_getfattr_label(xdr, res->fattr, res->label, res->server); |
6311 | out: | 6424 | out: |
6312 | return status; | 6425 | return status; |
6313 | } | 6426 | } |
@@ -6696,7 +6809,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, | |||
6696 | xdr_enter_page(xdr, PAGE_SIZE); | 6809 | xdr_enter_page(xdr, PAGE_SIZE); |
6697 | status = decode_getfattr_generic(xdr, &res->fs_locations->fattr, | 6810 | status = decode_getfattr_generic(xdr, &res->fs_locations->fattr, |
6698 | NULL, res->fs_locations, | 6811 | NULL, res->fs_locations, |
6699 | res->fs_locations->server); | 6812 | NULL, res->fs_locations->server); |
6700 | out: | 6813 | out: |
6701 | return status; | 6814 | return status; |
6702 | } | 6815 | } |
@@ -7109,7 +7222,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |||
7109 | goto out_overflow; | 7222 | goto out_overflow; |
7110 | 7223 | ||
7111 | if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, | 7224 | if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, |
7112 | NULL, entry->server) < 0) | 7225 | NULL, entry->label, entry->server) < 0) |
7113 | goto out_overflow; | 7226 | goto out_overflow; |
7114 | if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) | 7227 | if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) |
7115 | entry->ino = entry->fattr->mounted_on_fileid; | 7228 | entry->ino = entry->fattr->mounted_on_fileid; |
diff --git a/fs/nfs/objlayout/objlayout.c b/fs/nfs/objlayout/objlayout.c index a9ebd817278b..e4f9cbfec67b 100644 --- a/fs/nfs/objlayout/objlayout.c +++ b/fs/nfs/objlayout/objlayout.c | |||
@@ -613,8 +613,10 @@ int objlayout_get_deviceinfo(struct pnfs_layout_hdr *pnfslay, | |||
613 | pd.pgbase = 0; | 613 | pd.pgbase = 0; |
614 | pd.pglen = PAGE_SIZE; | 614 | pd.pglen = PAGE_SIZE; |
615 | pd.mincount = 0; | 615 | pd.mincount = 0; |
616 | pd.maxcount = PAGE_SIZE; | ||
616 | 617 | ||
617 | err = nfs4_proc_getdeviceinfo(NFS_SERVER(pnfslay->plh_inode), &pd); | 618 | err = nfs4_proc_getdeviceinfo(NFS_SERVER(pnfslay->plh_inode), &pd, |
619 | pnfslay->plh_lc_cred); | ||
618 | dprintk("%s nfs_getdeviceinfo returned %d\n", __func__, err); | 620 | dprintk("%s nfs_getdeviceinfo returned %d\n", __func__, err); |
619 | if (err) | 621 | if (err) |
620 | goto err_out; | 622 | goto err_out; |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index c5bd758e5637..3a3a79d6bf15 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -360,7 +360,7 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg) | |||
360 | } | 360 | } |
361 | EXPORT_SYMBOL_GPL(pnfs_put_lseg); | 361 | EXPORT_SYMBOL_GPL(pnfs_put_lseg); |
362 | 362 | ||
363 | static inline u64 | 363 | static u64 |
364 | end_offset(u64 start, u64 len) | 364 | end_offset(u64 start, u64 len) |
365 | { | 365 | { |
366 | u64 end; | 366 | u64 end; |
@@ -376,9 +376,9 @@ end_offset(u64 start, u64 len) | |||
376 | * start2 end2 | 376 | * start2 end2 |
377 | * [----------------) | 377 | * [----------------) |
378 | */ | 378 | */ |
379 | static inline int | 379 | static bool |
380 | lo_seg_contained(struct pnfs_layout_range *l1, | 380 | pnfs_lseg_range_contained(const struct pnfs_layout_range *l1, |
381 | struct pnfs_layout_range *l2) | 381 | const struct pnfs_layout_range *l2) |
382 | { | 382 | { |
383 | u64 start1 = l1->offset; | 383 | u64 start1 = l1->offset; |
384 | u64 end1 = end_offset(start1, l1->length); | 384 | u64 end1 = end_offset(start1, l1->length); |
@@ -395,9 +395,9 @@ lo_seg_contained(struct pnfs_layout_range *l1, | |||
395 | * start2 end2 | 395 | * start2 end2 |
396 | * [----------------) | 396 | * [----------------) |
397 | */ | 397 | */ |
398 | static inline int | 398 | static bool |
399 | lo_seg_intersecting(struct pnfs_layout_range *l1, | 399 | pnfs_lseg_range_intersecting(const struct pnfs_layout_range *l1, |
400 | struct pnfs_layout_range *l2) | 400 | const struct pnfs_layout_range *l2) |
401 | { | 401 | { |
402 | u64 start1 = l1->offset; | 402 | u64 start1 = l1->offset; |
403 | u64 end1 = end_offset(start1, l1->length); | 403 | u64 end1 = end_offset(start1, l1->length); |
@@ -409,12 +409,12 @@ lo_seg_intersecting(struct pnfs_layout_range *l1, | |||
409 | } | 409 | } |
410 | 410 | ||
411 | static bool | 411 | static bool |
412 | should_free_lseg(struct pnfs_layout_range *lseg_range, | 412 | should_free_lseg(const struct pnfs_layout_range *lseg_range, |
413 | struct pnfs_layout_range *recall_range) | 413 | const struct pnfs_layout_range *recall_range) |
414 | { | 414 | { |
415 | return (recall_range->iomode == IOMODE_ANY || | 415 | return (recall_range->iomode == IOMODE_ANY || |
416 | lseg_range->iomode == recall_range->iomode) && | 416 | lseg_range->iomode == recall_range->iomode) && |
417 | lo_seg_intersecting(lseg_range, recall_range); | 417 | pnfs_lseg_range_intersecting(lseg_range, recall_range); |
418 | } | 418 | } |
419 | 419 | ||
420 | static bool pnfs_lseg_dec_and_remove_zero(struct pnfs_layout_segment *lseg, | 420 | static bool pnfs_lseg_dec_and_remove_zero(struct pnfs_layout_segment *lseg, |
@@ -766,6 +766,7 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
766 | lgp->args.inode = ino; | 766 | lgp->args.inode = ino; |
767 | lgp->args.ctx = get_nfs_open_context(ctx); | 767 | lgp->args.ctx = get_nfs_open_context(ctx); |
768 | lgp->gfp_flags = gfp_flags; | 768 | lgp->gfp_flags = gfp_flags; |
769 | lgp->cred = lo->plh_lc_cred; | ||
769 | 770 | ||
770 | /* Synchronously retrieve layout information from server and | 771 | /* Synchronously retrieve layout information from server and |
771 | * store in lseg. | 772 | * store in lseg. |
@@ -860,6 +861,7 @@ _pnfs_return_layout(struct inode *ino) | |||
860 | lrp->args.inode = ino; | 861 | lrp->args.inode = ino; |
861 | lrp->args.layout = lo; | 862 | lrp->args.layout = lo; |
862 | lrp->clp = NFS_SERVER(ino)->nfs_client; | 863 | lrp->clp = NFS_SERVER(ino)->nfs_client; |
864 | lrp->cred = lo->plh_lc_cred; | ||
863 | 865 | ||
864 | status = nfs4_proc_layoutreturn(lrp); | 866 | status = nfs4_proc_layoutreturn(lrp); |
865 | out: | 867 | out: |
@@ -984,8 +986,8 @@ out: | |||
984 | * are seen first. | 986 | * are seen first. |
985 | */ | 987 | */ |
986 | static s64 | 988 | static s64 |
987 | cmp_layout(struct pnfs_layout_range *l1, | 989 | pnfs_lseg_range_cmp(const struct pnfs_layout_range *l1, |
988 | struct pnfs_layout_range *l2) | 990 | const struct pnfs_layout_range *l2) |
989 | { | 991 | { |
990 | s64 d; | 992 | s64 d; |
991 | 993 | ||
@@ -1012,7 +1014,7 @@ pnfs_layout_insert_lseg(struct pnfs_layout_hdr *lo, | |||
1012 | dprintk("%s:Begin\n", __func__); | 1014 | dprintk("%s:Begin\n", __func__); |
1013 | 1015 | ||
1014 | list_for_each_entry(lp, &lo->plh_segs, pls_list) { | 1016 | list_for_each_entry(lp, &lo->plh_segs, pls_list) { |
1015 | if (cmp_layout(&lseg->pls_range, &lp->pls_range) > 0) | 1017 | if (pnfs_lseg_range_cmp(&lseg->pls_range, &lp->pls_range) > 0) |
1016 | continue; | 1018 | continue; |
1017 | list_add_tail(&lseg->pls_list, &lp->pls_list); | 1019 | list_add_tail(&lseg->pls_list, &lp->pls_list); |
1018 | dprintk("%s: inserted lseg %p " | 1020 | dprintk("%s: inserted lseg %p " |
@@ -1050,7 +1052,7 @@ alloc_init_layout_hdr(struct inode *ino, | |||
1050 | INIT_LIST_HEAD(&lo->plh_segs); | 1052 | INIT_LIST_HEAD(&lo->plh_segs); |
1051 | INIT_LIST_HEAD(&lo->plh_bulk_destroy); | 1053 | INIT_LIST_HEAD(&lo->plh_bulk_destroy); |
1052 | lo->plh_inode = ino; | 1054 | lo->plh_inode = ino; |
1053 | lo->plh_lc_cred = get_rpccred(ctx->state->owner->so_cred); | 1055 | lo->plh_lc_cred = get_rpccred(ctx->cred); |
1054 | return lo; | 1056 | return lo; |
1055 | } | 1057 | } |
1056 | 1058 | ||
@@ -1091,21 +1093,21 @@ out_existing: | |||
1091 | * READ READ true | 1093 | * READ READ true |
1092 | * READ RW true | 1094 | * READ RW true |
1093 | */ | 1095 | */ |
1094 | static int | 1096 | static bool |
1095 | is_matching_lseg(struct pnfs_layout_range *ls_range, | 1097 | pnfs_lseg_range_match(const struct pnfs_layout_range *ls_range, |
1096 | struct pnfs_layout_range *range) | 1098 | const struct pnfs_layout_range *range) |
1097 | { | 1099 | { |
1098 | struct pnfs_layout_range range1; | 1100 | struct pnfs_layout_range range1; |
1099 | 1101 | ||
1100 | if ((range->iomode == IOMODE_RW && | 1102 | if ((range->iomode == IOMODE_RW && |
1101 | ls_range->iomode != IOMODE_RW) || | 1103 | ls_range->iomode != IOMODE_RW) || |
1102 | !lo_seg_intersecting(ls_range, range)) | 1104 | !pnfs_lseg_range_intersecting(ls_range, range)) |
1103 | return 0; | 1105 | return 0; |
1104 | 1106 | ||
1105 | /* range1 covers only the first byte in the range */ | 1107 | /* range1 covers only the first byte in the range */ |
1106 | range1 = *range; | 1108 | range1 = *range; |
1107 | range1.length = 1; | 1109 | range1.length = 1; |
1108 | return lo_seg_contained(ls_range, &range1); | 1110 | return pnfs_lseg_range_contained(ls_range, &range1); |
1109 | } | 1111 | } |
1110 | 1112 | ||
1111 | /* | 1113 | /* |
@@ -1121,7 +1123,7 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, | |||
1121 | 1123 | ||
1122 | list_for_each_entry(lseg, &lo->plh_segs, pls_list) { | 1124 | list_for_each_entry(lseg, &lo->plh_segs, pls_list) { |
1123 | if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) && | 1125 | if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) && |
1124 | is_matching_lseg(&lseg->pls_range, range)) { | 1126 | pnfs_lseg_range_match(&lseg->pls_range, range)) { |
1125 | ret = pnfs_get_lseg(lseg); | 1127 | ret = pnfs_get_lseg(lseg); |
1126 | break; | 1128 | break; |
1127 | } | 1129 | } |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index f5f8a470a647..a4f41810a7f4 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -149,9 +149,10 @@ struct pnfs_device { | |||
149 | struct nfs4_deviceid dev_id; | 149 | struct nfs4_deviceid dev_id; |
150 | unsigned int layout_type; | 150 | unsigned int layout_type; |
151 | unsigned int mincount; | 151 | unsigned int mincount; |
152 | unsigned int maxcount; /* gdia_maxcount */ | ||
152 | struct page **pages; | 153 | struct page **pages; |
153 | unsigned int pgbase; | 154 | unsigned int pgbase; |
154 | unsigned int pglen; | 155 | unsigned int pglen; /* reply buffer length */ |
155 | }; | 156 | }; |
156 | 157 | ||
157 | #define NFS4_PNFS_GETDEVLIST_MAXNUM 16 | 158 | #define NFS4_PNFS_GETDEVLIST_MAXNUM 16 |
@@ -170,7 +171,8 @@ extern int nfs4_proc_getdevicelist(struct nfs_server *server, | |||
170 | const struct nfs_fh *fh, | 171 | const struct nfs_fh *fh, |
171 | struct pnfs_devicelist *devlist); | 172 | struct pnfs_devicelist *devlist); |
172 | extern int nfs4_proc_getdeviceinfo(struct nfs_server *server, | 173 | extern int nfs4_proc_getdeviceinfo(struct nfs_server *server, |
173 | struct pnfs_device *dev); | 174 | struct pnfs_device *dev, |
175 | struct rpc_cred *cred); | ||
174 | extern struct pnfs_layout_segment* nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags); | 176 | extern struct pnfs_layout_segment* nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags); |
175 | extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp); | 177 | extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp); |
176 | 178 | ||
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index fc8de9016acf..c041c41f7a52 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -98,7 +98,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
98 | */ | 98 | */ |
99 | static int | 99 | static int |
100 | nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | 100 | nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, |
101 | struct nfs_fattr *fattr) | 101 | struct nfs_fattr *fattr, struct nfs4_label *label) |
102 | { | 102 | { |
103 | struct rpc_message msg = { | 103 | struct rpc_message msg = { |
104 | .rpc_proc = &nfs_procedures[NFSPROC_GETATTR], | 104 | .rpc_proc = &nfs_procedures[NFSPROC_GETATTR], |
@@ -146,7 +146,8 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
146 | 146 | ||
147 | static int | 147 | static int |
148 | nfs_proc_lookup(struct inode *dir, struct qstr *name, | 148 | nfs_proc_lookup(struct inode *dir, struct qstr *name, |
149 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 149 | struct nfs_fh *fhandle, struct nfs_fattr *fattr, |
150 | struct nfs4_label *label) | ||
150 | { | 151 | { |
151 | struct nfs_diropargs arg = { | 152 | struct nfs_diropargs arg = { |
152 | .fh = NFS_FH(dir), | 153 | .fh = NFS_FH(dir), |
@@ -243,7 +244,7 @@ nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
243 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 244 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
244 | nfs_mark_for_revalidate(dir); | 245 | nfs_mark_for_revalidate(dir); |
245 | if (status == 0) | 246 | if (status == 0) |
246 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); | 247 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); |
247 | nfs_free_createdata(data); | 248 | nfs_free_createdata(data); |
248 | out: | 249 | out: |
249 | dprintk("NFS reply create: %d\n", status); | 250 | dprintk("NFS reply create: %d\n", status); |
@@ -290,7 +291,7 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
290 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 291 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
291 | } | 292 | } |
292 | if (status == 0) | 293 | if (status == 0) |
293 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); | 294 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); |
294 | nfs_free_createdata(data); | 295 | nfs_free_createdata(data); |
295 | out: | 296 | out: |
296 | dprintk("NFS reply mknod: %d\n", status); | 297 | dprintk("NFS reply mknod: %d\n", status); |
@@ -442,7 +443,7 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, | |||
442 | * should fill in the data with a LOOKUP call on the wire. | 443 | * should fill in the data with a LOOKUP call on the wire. |
443 | */ | 444 | */ |
444 | if (status == 0) | 445 | if (status == 0) |
445 | status = nfs_instantiate(dentry, fh, fattr); | 446 | status = nfs_instantiate(dentry, fh, fattr, NULL); |
446 | 447 | ||
447 | out_free: | 448 | out_free: |
448 | nfs_free_fattr(fattr); | 449 | nfs_free_fattr(fattr); |
@@ -471,7 +472,7 @@ nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) | |||
471 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 472 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
472 | nfs_mark_for_revalidate(dir); | 473 | nfs_mark_for_revalidate(dir); |
473 | if (status == 0) | 474 | if (status == 0) |
474 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); | 475 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); |
475 | nfs_free_createdata(data); | 476 | nfs_free_createdata(data); |
476 | out: | 477 | out: |
477 | dprintk("NFS reply mkdir: %d\n", status); | 478 | dprintk("NFS reply mkdir: %d\n", status); |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 2d7525fbcf25..f6db66d8f647 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -269,7 +269,7 @@ static match_table_t nfs_local_lock_tokens = { | |||
269 | 269 | ||
270 | enum { | 270 | enum { |
271 | Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0, | 271 | Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0, |
272 | Opt_vers_4_1, | 272 | Opt_vers_4_1, Opt_vers_4_2, |
273 | 273 | ||
274 | Opt_vers_err | 274 | Opt_vers_err |
275 | }; | 275 | }; |
@@ -280,6 +280,7 @@ static match_table_t nfs_vers_tokens = { | |||
280 | { Opt_vers_4, "4" }, | 280 | { Opt_vers_4, "4" }, |
281 | { Opt_vers_4_0, "4.0" }, | 281 | { Opt_vers_4_0, "4.0" }, |
282 | { Opt_vers_4_1, "4.1" }, | 282 | { Opt_vers_4_1, "4.1" }, |
283 | { Opt_vers_4_2, "4.2" }, | ||
283 | 284 | ||
284 | { Opt_vers_err, NULL } | 285 | { Opt_vers_err, NULL } |
285 | }; | 286 | }; |
@@ -832,6 +833,7 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root) | |||
832 | seq_printf(m, "\n\tnfsv4:\t"); | 833 | seq_printf(m, "\n\tnfsv4:\t"); |
833 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); | 834 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); |
834 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); | 835 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); |
836 | seq_printf(m, ",bm2=0x%x", nfss->attr_bitmask[2]); | ||
835 | seq_printf(m, ",acl=0x%x", nfss->acl_bitmask); | 837 | seq_printf(m, ",acl=0x%x", nfss->acl_bitmask); |
836 | show_sessions(m, nfss); | 838 | show_sessions(m, nfss); |
837 | show_pnfs(m, nfss); | 839 | show_pnfs(m, nfss); |
@@ -1097,6 +1099,10 @@ static int nfs_parse_version_string(char *string, | |||
1097 | mnt->version = 4; | 1099 | mnt->version = 4; |
1098 | mnt->minorversion = 1; | 1100 | mnt->minorversion = 1; |
1099 | break; | 1101 | break; |
1102 | case Opt_vers_4_2: | ||
1103 | mnt->version = 4; | ||
1104 | mnt->minorversion = 2; | ||
1105 | break; | ||
1100 | default: | 1106 | default: |
1101 | return 0; | 1107 | return 0; |
1102 | } | 1108 | } |
@@ -1608,29 +1614,13 @@ out_security_failure: | |||
1608 | } | 1614 | } |
1609 | 1615 | ||
1610 | /* | 1616 | /* |
1611 | * Select a security flavor for this mount. The selected flavor | 1617 | * Ensure that the specified authtype in args->auth_flavors[0] is supported by |
1612 | * is planted in args->auth_flavors[0]. | 1618 | * the server. Returns 0 if it's ok, and -EACCES if not. |
1613 | * | ||
1614 | * Returns 0 on success, -EACCES on failure. | ||
1615 | */ | 1619 | */ |
1616 | static int nfs_select_flavor(struct nfs_parsed_mount_data *args, | 1620 | static int nfs_verify_authflavor(struct nfs_parsed_mount_data *args, |
1617 | struct nfs_mount_request *request) | 1621 | rpc_authflavor_t *server_authlist, unsigned int count) |
1618 | { | 1622 | { |
1619 | unsigned int i, count = *(request->auth_flav_len); | 1623 | unsigned int i; |
1620 | rpc_authflavor_t flavor; | ||
1621 | |||
1622 | /* | ||
1623 | * The NFSv2 MNT operation does not return a flavor list. | ||
1624 | */ | ||
1625 | if (args->mount_server.version != NFS_MNT3_VERSION) | ||
1626 | goto out_default; | ||
1627 | |||
1628 | /* | ||
1629 | * Certain releases of Linux's mountd return an empty | ||
1630 | * flavor list in some cases. | ||
1631 | */ | ||
1632 | if (count == 0) | ||
1633 | goto out_default; | ||
1634 | 1624 | ||
1635 | /* | 1625 | /* |
1636 | * If the sec= mount option is used, the specified flavor or AUTH_NULL | 1626 | * If the sec= mount option is used, the specified flavor or AUTH_NULL |
@@ -1640,60 +1630,19 @@ static int nfs_select_flavor(struct nfs_parsed_mount_data *args, | |||
1640 | * means that the server will ignore the rpc creds, so any flavor | 1630 | * means that the server will ignore the rpc creds, so any flavor |
1641 | * can be used. | 1631 | * can be used. |
1642 | */ | 1632 | */ |
1643 | if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR) { | ||
1644 | for (i = 0; i < count; i++) { | ||
1645 | if (args->auth_flavors[0] == request->auth_flavs[i] || | ||
1646 | request->auth_flavs[i] == RPC_AUTH_NULL) | ||
1647 | goto out; | ||
1648 | } | ||
1649 | dfprintk(MOUNT, "NFS: auth flavor %d not supported by server\n", | ||
1650 | args->auth_flavors[0]); | ||
1651 | goto out_err; | ||
1652 | } | ||
1653 | |||
1654 | /* | ||
1655 | * RFC 2623, section 2.7 suggests we SHOULD prefer the | ||
1656 | * flavor listed first. However, some servers list | ||
1657 | * AUTH_NULL first. Avoid ever choosing AUTH_NULL. | ||
1658 | */ | ||
1659 | for (i = 0; i < count; i++) { | ||
1660 | struct rpcsec_gss_info info; | ||
1661 | |||
1662 | flavor = request->auth_flavs[i]; | ||
1663 | switch (flavor) { | ||
1664 | case RPC_AUTH_UNIX: | ||
1665 | goto out_set; | ||
1666 | case RPC_AUTH_NULL: | ||
1667 | continue; | ||
1668 | default: | ||
1669 | if (rpcauth_get_gssinfo(flavor, &info) == 0) | ||
1670 | goto out_set; | ||
1671 | } | ||
1672 | } | ||
1673 | |||
1674 | /* | ||
1675 | * As a last chance, see if the server list contains AUTH_NULL - | ||
1676 | * if it does, use the default flavor. | ||
1677 | */ | ||
1678 | for (i = 0; i < count; i++) { | 1633 | for (i = 0; i < count; i++) { |
1679 | if (request->auth_flavs[i] == RPC_AUTH_NULL) | 1634 | if (args->auth_flavors[0] == server_authlist[i] || |
1680 | goto out_default; | 1635 | server_authlist[i] == RPC_AUTH_NULL) |
1636 | goto out; | ||
1681 | } | 1637 | } |
1682 | 1638 | ||
1683 | dfprintk(MOUNT, "NFS: no auth flavors in common with server\n"); | 1639 | dfprintk(MOUNT, "NFS: auth flavor %u not supported by server\n", |
1684 | goto out_err; | 1640 | args->auth_flavors[0]); |
1641 | return -EACCES; | ||
1685 | 1642 | ||
1686 | out_default: | ||
1687 | /* use default if flavor not already set */ | ||
1688 | flavor = (args->auth_flavors[0] == RPC_AUTH_MAXFLAVOR) ? | ||
1689 | RPC_AUTH_UNIX : args->auth_flavors[0]; | ||
1690 | out_set: | ||
1691 | args->auth_flavors[0] = flavor; | ||
1692 | out: | 1643 | out: |
1693 | dfprintk(MOUNT, "NFS: using auth flavor %d\n", args->auth_flavors[0]); | 1644 | dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->auth_flavors[0]); |
1694 | return 0; | 1645 | return 0; |
1695 | out_err: | ||
1696 | return -EACCES; | ||
1697 | } | 1646 | } |
1698 | 1647 | ||
1699 | /* | 1648 | /* |
@@ -1701,10 +1650,10 @@ out_err: | |||
1701 | * corresponding to the provided path. | 1650 | * corresponding to the provided path. |
1702 | */ | 1651 | */ |
1703 | static int nfs_request_mount(struct nfs_parsed_mount_data *args, | 1652 | static int nfs_request_mount(struct nfs_parsed_mount_data *args, |
1704 | struct nfs_fh *root_fh) | 1653 | struct nfs_fh *root_fh, |
1654 | rpc_authflavor_t *server_authlist, | ||
1655 | unsigned int *server_authlist_len) | ||
1705 | { | 1656 | { |
1706 | rpc_authflavor_t server_authlist[NFS_MAX_SECFLAVORS]; | ||
1707 | unsigned int server_authlist_len = ARRAY_SIZE(server_authlist); | ||
1708 | struct nfs_mount_request request = { | 1657 | struct nfs_mount_request request = { |
1709 | .sap = (struct sockaddr *) | 1658 | .sap = (struct sockaddr *) |
1710 | &args->mount_server.address, | 1659 | &args->mount_server.address, |
@@ -1712,7 +1661,7 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args, | |||
1712 | .protocol = args->mount_server.protocol, | 1661 | .protocol = args->mount_server.protocol, |
1713 | .fh = root_fh, | 1662 | .fh = root_fh, |
1714 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, | 1663 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, |
1715 | .auth_flav_len = &server_authlist_len, | 1664 | .auth_flav_len = server_authlist_len, |
1716 | .auth_flavs = server_authlist, | 1665 | .auth_flavs = server_authlist, |
1717 | .net = args->net, | 1666 | .net = args->net, |
1718 | }; | 1667 | }; |
@@ -1756,24 +1705,92 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args, | |||
1756 | return status; | 1705 | return status; |
1757 | } | 1706 | } |
1758 | 1707 | ||
1759 | return nfs_select_flavor(args, &request); | 1708 | return 0; |
1760 | } | 1709 | } |
1761 | 1710 | ||
1762 | struct dentry *nfs_try_mount(int flags, const char *dev_name, | 1711 | static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_info, |
1763 | struct nfs_mount_info *mount_info, | 1712 | struct nfs_subversion *nfs_mod) |
1764 | struct nfs_subversion *nfs_mod) | ||
1765 | { | 1713 | { |
1766 | int status; | 1714 | int status; |
1767 | struct nfs_server *server; | 1715 | unsigned int i; |
1716 | bool tried_auth_unix = false; | ||
1717 | bool auth_null_in_list = false; | ||
1718 | struct nfs_server *server = ERR_PTR(-EACCES); | ||
1719 | struct nfs_parsed_mount_data *args = mount_info->parsed; | ||
1720 | rpc_authflavor_t authlist[NFS_MAX_SECFLAVORS]; | ||
1721 | unsigned int authlist_len = ARRAY_SIZE(authlist); | ||
1722 | |||
1723 | status = nfs_request_mount(args, mount_info->mntfh, authlist, | ||
1724 | &authlist_len); | ||
1725 | if (status) | ||
1726 | return ERR_PTR(status); | ||
1768 | 1727 | ||
1769 | if (mount_info->parsed->need_mount) { | 1728 | /* |
1770 | status = nfs_request_mount(mount_info->parsed, mount_info->mntfh); | 1729 | * Was a sec= authflavor specified in the options? First, verify |
1730 | * whether the server supports it, and then just try to use it if so. | ||
1731 | */ | ||
1732 | if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR) { | ||
1733 | status = nfs_verify_authflavor(args, authlist, authlist_len); | ||
1734 | dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->auth_flavors[0]); | ||
1771 | if (status) | 1735 | if (status) |
1772 | return ERR_PTR(status); | 1736 | return ERR_PTR(status); |
1737 | return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | ||
1738 | } | ||
1739 | |||
1740 | /* | ||
1741 | * No sec= option was provided. RFC 2623, section 2.7 suggests we | ||
1742 | * SHOULD prefer the flavor listed first. However, some servers list | ||
1743 | * AUTH_NULL first. Avoid ever choosing AUTH_NULL. | ||
1744 | */ | ||
1745 | for (i = 0; i < authlist_len; ++i) { | ||
1746 | rpc_authflavor_t flavor; | ||
1747 | struct rpcsec_gss_info info; | ||
1748 | |||
1749 | flavor = authlist[i]; | ||
1750 | switch (flavor) { | ||
1751 | case RPC_AUTH_UNIX: | ||
1752 | tried_auth_unix = true; | ||
1753 | break; | ||
1754 | case RPC_AUTH_NULL: | ||
1755 | auth_null_in_list = true; | ||
1756 | continue; | ||
1757 | default: | ||
1758 | if (rpcauth_get_gssinfo(flavor, &info) != 0) | ||
1759 | continue; | ||
1760 | /* Fallthrough */ | ||
1761 | } | ||
1762 | dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor); | ||
1763 | args->auth_flavors[0] = flavor; | ||
1764 | server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | ||
1765 | if (!IS_ERR(server)) | ||
1766 | return server; | ||
1773 | } | 1767 | } |
1774 | 1768 | ||
1775 | /* Get a volume representation */ | 1769 | /* |
1776 | server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | 1770 | * Nothing we tried so far worked. At this point, give up if we've |
1771 | * already tried AUTH_UNIX or if the server's list doesn't contain | ||
1772 | * AUTH_NULL | ||
1773 | */ | ||
1774 | if (tried_auth_unix || !auth_null_in_list) | ||
1775 | return server; | ||
1776 | |||
1777 | /* Last chance! Try AUTH_UNIX */ | ||
1778 | dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX); | ||
1779 | args->auth_flavors[0] = RPC_AUTH_UNIX; | ||
1780 | return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | ||
1781 | } | ||
1782 | |||
1783 | struct dentry *nfs_try_mount(int flags, const char *dev_name, | ||
1784 | struct nfs_mount_info *mount_info, | ||
1785 | struct nfs_subversion *nfs_mod) | ||
1786 | { | ||
1787 | struct nfs_server *server; | ||
1788 | |||
1789 | if (mount_info->parsed->need_mount) | ||
1790 | server = nfs_try_mount_request(mount_info, nfs_mod); | ||
1791 | else | ||
1792 | server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | ||
1793 | |||
1777 | if (IS_ERR(server)) | 1794 | if (IS_ERR(server)) |
1778 | return ERR_CAST(server); | 1795 | return ERR_CAST(server); |
1779 | 1796 | ||
@@ -2412,7 +2429,21 @@ static int nfs_bdi_register(struct nfs_server *server) | |||
2412 | int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, | 2429 | int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, |
2413 | struct nfs_mount_info *mount_info) | 2430 | struct nfs_mount_info *mount_info) |
2414 | { | 2431 | { |
2415 | return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts); | 2432 | int error; |
2433 | unsigned long kflags = 0, kflags_out = 0; | ||
2434 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL) | ||
2435 | kflags |= SECURITY_LSM_NATIVE_LABELS; | ||
2436 | |||
2437 | error = security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts, | ||
2438 | kflags, &kflags_out); | ||
2439 | if (error) | ||
2440 | goto err; | ||
2441 | |||
2442 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL && | ||
2443 | !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) | ||
2444 | NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL; | ||
2445 | err: | ||
2446 | return error; | ||
2416 | } | 2447 | } |
2417 | EXPORT_SYMBOL_GPL(nfs_set_sb_security); | 2448 | EXPORT_SYMBOL_GPL(nfs_set_sb_security); |
2418 | 2449 | ||
@@ -2447,6 +2478,10 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server, | |||
2447 | if (server->flags & NFS_MOUNT_NOAC) | 2478 | if (server->flags & NFS_MOUNT_NOAC) |
2448 | sb_mntdata.mntflags |= MS_SYNCHRONOUS; | 2479 | sb_mntdata.mntflags |= MS_SYNCHRONOUS; |
2449 | 2480 | ||
2481 | if (mount_info->cloned != NULL && mount_info->cloned->sb != NULL) | ||
2482 | if (mount_info->cloned->sb->s_flags & MS_SYNCHRONOUS) | ||
2483 | sb_mntdata.mntflags |= MS_SYNCHRONOUS; | ||
2484 | |||
2450 | /* Get a superblock - note that we may end up sharing one that already exists */ | 2485 | /* Get a superblock - note that we may end up sharing one that already exists */ |
2451 | s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata); | 2486 | s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata); |
2452 | if (IS_ERR(s)) { | 2487 | if (IS_ERR(s)) { |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 1f1f38f0c5d5..60395ad3a2e4 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -479,7 +479,7 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) | |||
479 | 479 | ||
480 | dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", | 480 | dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", |
481 | dentry->d_parent->d_name.name, dentry->d_name.name, | 481 | dentry->d_parent->d_name.name, dentry->d_name.name, |
482 | dentry->d_count); | 482 | d_count(dentry)); |
483 | nfs_inc_stats(dir, NFSIOS_SILLYRENAME); | 483 | nfs_inc_stats(dir, NFSIOS_SILLYRENAME); |
484 | 484 | ||
485 | /* | 485 | /* |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index a2c7c28049d5..f1bdb7254776 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -888,6 +888,28 @@ out: | |||
888 | return PageUptodate(page) != 0; | 888 | return PageUptodate(page) != 0; |
889 | } | 889 | } |
890 | 890 | ||
891 | /* If we know the page is up to date, and we're not using byte range locks (or | ||
892 | * if we have the whole file locked for writing), it may be more efficient to | ||
893 | * extend the write to cover the entire page in order to avoid fragmentation | ||
894 | * inefficiencies. | ||
895 | * | ||
896 | * If the file is opened for synchronous writes or if we have a write delegation | ||
897 | * from the server then we can just skip the rest of the checks. | ||
898 | */ | ||
899 | static int nfs_can_extend_write(struct file *file, struct page *page, struct inode *inode) | ||
900 | { | ||
901 | if (file->f_flags & O_DSYNC) | ||
902 | return 0; | ||
903 | if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE)) | ||
904 | return 1; | ||
905 | if (nfs_write_pageuptodate(page, inode) && (inode->i_flock == NULL || | ||
906 | (inode->i_flock->fl_start == 0 && | ||
907 | inode->i_flock->fl_end == OFFSET_MAX && | ||
908 | inode->i_flock->fl_type != F_RDLCK))) | ||
909 | return 1; | ||
910 | return 0; | ||
911 | } | ||
912 | |||
891 | /* | 913 | /* |
892 | * Update and possibly write a cached page of an NFS file. | 914 | * Update and possibly write a cached page of an NFS file. |
893 | * | 915 | * |
@@ -908,14 +930,7 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
908 | file->f_path.dentry->d_name.name, count, | 930 | file->f_path.dentry->d_name.name, count, |
909 | (long long)(page_file_offset(page) + offset)); | 931 | (long long)(page_file_offset(page) + offset)); |
910 | 932 | ||
911 | /* If we're not using byte range locks, and we know the page | 933 | if (nfs_can_extend_write(file, page, inode)) { |
912 | * is up to date, it may be more efficient to extend the write | ||
913 | * to cover the entire page in order to avoid fragmentation | ||
914 | * inefficiencies. | ||
915 | */ | ||
916 | if (nfs_write_pageuptodate(page, inode) && | ||
917 | inode->i_flock == NULL && | ||
918 | !(file->f_flags & O_DSYNC)) { | ||
919 | count = max(count + offset, nfs_page_length(page)); | 934 | count = max(count + offset, nfs_page_length(page)); |
920 | offset = 0; | 935 | offset = 0; |
921 | } | 936 | } |