diff options
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r-- | fs/nfs/super.c | 138 |
1 files changed, 85 insertions, 53 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 9abcd2b329f7..8b28b95c9e44 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -91,6 +91,7 @@ enum { | |||
91 | /* Mount options that take string arguments */ | 91 | /* Mount options that take string arguments */ |
92 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, | 92 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, |
93 | Opt_addr, Opt_mountaddr, Opt_clientaddr, | 93 | Opt_addr, Opt_mountaddr, Opt_clientaddr, |
94 | Opt_lookupcache, | ||
94 | 95 | ||
95 | /* Special mount options */ | 96 | /* Special mount options */ |
96 | Opt_userspace, Opt_deprecated, Opt_sloppy, | 97 | Opt_userspace, Opt_deprecated, Opt_sloppy, |
@@ -98,7 +99,7 @@ enum { | |||
98 | Opt_err | 99 | Opt_err |
99 | }; | 100 | }; |
100 | 101 | ||
101 | static match_table_t nfs_mount_option_tokens = { | 102 | static const match_table_t nfs_mount_option_tokens = { |
102 | { Opt_userspace, "bg" }, | 103 | { Opt_userspace, "bg" }, |
103 | { Opt_userspace, "fg" }, | 104 | { Opt_userspace, "fg" }, |
104 | { Opt_userspace, "retry=%s" }, | 105 | { Opt_userspace, "retry=%s" }, |
@@ -154,6 +155,8 @@ static match_table_t nfs_mount_option_tokens = { | |||
154 | { Opt_mounthost, "mounthost=%s" }, | 155 | { Opt_mounthost, "mounthost=%s" }, |
155 | { Opt_mountaddr, "mountaddr=%s" }, | 156 | { Opt_mountaddr, "mountaddr=%s" }, |
156 | 157 | ||
158 | { Opt_lookupcache, "lookupcache=%s" }, | ||
159 | |||
157 | { Opt_err, NULL } | 160 | { Opt_err, NULL } |
158 | }; | 161 | }; |
159 | 162 | ||
@@ -163,7 +166,7 @@ enum { | |||
163 | Opt_xprt_err | 166 | Opt_xprt_err |
164 | }; | 167 | }; |
165 | 168 | ||
166 | static match_table_t nfs_xprt_protocol_tokens = { | 169 | static const match_table_t nfs_xprt_protocol_tokens = { |
167 | { Opt_xprt_udp, "udp" }, | 170 | { Opt_xprt_udp, "udp" }, |
168 | { Opt_xprt_tcp, "tcp" }, | 171 | { Opt_xprt_tcp, "tcp" }, |
169 | { Opt_xprt_rdma, "rdma" }, | 172 | { Opt_xprt_rdma, "rdma" }, |
@@ -180,7 +183,7 @@ enum { | |||
180 | Opt_sec_err | 183 | Opt_sec_err |
181 | }; | 184 | }; |
182 | 185 | ||
183 | static match_table_t nfs_secflavor_tokens = { | 186 | static const match_table_t nfs_secflavor_tokens = { |
184 | { Opt_sec_none, "none" }, | 187 | { Opt_sec_none, "none" }, |
185 | { Opt_sec_none, "null" }, | 188 | { Opt_sec_none, "null" }, |
186 | { Opt_sec_sys, "sys" }, | 189 | { Opt_sec_sys, "sys" }, |
@@ -200,6 +203,22 @@ static match_table_t nfs_secflavor_tokens = { | |||
200 | { Opt_sec_err, NULL } | 203 | { Opt_sec_err, NULL } |
201 | }; | 204 | }; |
202 | 205 | ||
206 | enum { | ||
207 | Opt_lookupcache_all, Opt_lookupcache_positive, | ||
208 | Opt_lookupcache_none, | ||
209 | |||
210 | Opt_lookupcache_err | ||
211 | }; | ||
212 | |||
213 | static match_table_t nfs_lookupcache_tokens = { | ||
214 | { Opt_lookupcache_all, "all" }, | ||
215 | { Opt_lookupcache_positive, "pos" }, | ||
216 | { Opt_lookupcache_positive, "positive" }, | ||
217 | { Opt_lookupcache_none, "none" }, | ||
218 | |||
219 | { Opt_lookupcache_err, NULL } | ||
220 | }; | ||
221 | |||
203 | 222 | ||
204 | static void nfs_umount_begin(struct super_block *); | 223 | static void nfs_umount_begin(struct super_block *); |
205 | static int nfs_statfs(struct dentry *, struct kstatfs *); | 224 | static int nfs_statfs(struct dentry *, struct kstatfs *); |
@@ -209,7 +228,6 @@ static int nfs_get_sb(struct file_system_type *, int, const char *, void *, stru | |||
209 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, | 228 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, |
210 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 229 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
211 | static void nfs_kill_super(struct super_block *); | 230 | static void nfs_kill_super(struct super_block *); |
212 | static void nfs_put_super(struct super_block *); | ||
213 | static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); | 231 | static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); |
214 | 232 | ||
215 | static struct file_system_type nfs_fs_type = { | 233 | static struct file_system_type nfs_fs_type = { |
@@ -232,7 +250,6 @@ static const struct super_operations nfs_sops = { | |||
232 | .alloc_inode = nfs_alloc_inode, | 250 | .alloc_inode = nfs_alloc_inode, |
233 | .destroy_inode = nfs_destroy_inode, | 251 | .destroy_inode = nfs_destroy_inode, |
234 | .write_inode = nfs_write_inode, | 252 | .write_inode = nfs_write_inode, |
235 | .put_super = nfs_put_super, | ||
236 | .statfs = nfs_statfs, | 253 | .statfs = nfs_statfs, |
237 | .clear_inode = nfs_clear_inode, | 254 | .clear_inode = nfs_clear_inode, |
238 | .umount_begin = nfs_umount_begin, | 255 | .umount_begin = nfs_umount_begin, |
@@ -337,26 +354,20 @@ void __exit unregister_nfs_fs(void) | |||
337 | unregister_filesystem(&nfs_fs_type); | 354 | unregister_filesystem(&nfs_fs_type); |
338 | } | 355 | } |
339 | 356 | ||
340 | void nfs_sb_active(struct nfs_server *server) | 357 | void nfs_sb_active(struct super_block *sb) |
341 | { | 358 | { |
342 | atomic_inc(&server->active); | 359 | struct nfs_server *server = NFS_SB(sb); |
343 | } | ||
344 | 360 | ||
345 | void nfs_sb_deactive(struct nfs_server *server) | 361 | if (atomic_inc_return(&server->active) == 1) |
346 | { | 362 | atomic_inc(&sb->s_active); |
347 | if (atomic_dec_and_test(&server->active)) | ||
348 | wake_up(&server->active_wq); | ||
349 | } | 363 | } |
350 | 364 | ||
351 | static void nfs_put_super(struct super_block *sb) | 365 | void nfs_sb_deactive(struct super_block *sb) |
352 | { | 366 | { |
353 | struct nfs_server *server = NFS_SB(sb); | 367 | struct nfs_server *server = NFS_SB(sb); |
354 | /* | 368 | |
355 | * Make sure there are no outstanding ops to this server. | 369 | if (atomic_dec_and_test(&server->active)) |
356 | * If so, wait for them to finish before allowing the | 370 | deactivate_super(sb); |
357 | * unmount to continue. | ||
358 | */ | ||
359 | wait_event(server->active_wq, atomic_read(&server->active) == 0); | ||
360 | } | 371 | } |
361 | 372 | ||
362 | /* | 373 | /* |
@@ -664,25 +675,6 @@ static void nfs_umount_begin(struct super_block *sb) | |||
664 | } | 675 | } |
665 | 676 | ||
666 | /* | 677 | /* |
667 | * Set the port number in an address. Be agnostic about the address family. | ||
668 | */ | ||
669 | static void nfs_set_port(struct sockaddr *sap, unsigned short port) | ||
670 | { | ||
671 | switch (sap->sa_family) { | ||
672 | case AF_INET: { | ||
673 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
674 | ap->sin_port = htons(port); | ||
675 | break; | ||
676 | } | ||
677 | case AF_INET6: { | ||
678 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
679 | ap->sin6_port = htons(port); | ||
680 | break; | ||
681 | } | ||
682 | } | ||
683 | } | ||
684 | |||
685 | /* | ||
686 | * Sanity-check a server address provided by the mount command. | 678 | * Sanity-check a server address provided by the mount command. |
687 | * | 679 | * |
688 | * Address family must be initialized, and address must not be | 680 | * Address family must be initialized, and address must not be |
@@ -724,20 +716,22 @@ static void nfs_parse_ipv4_address(char *string, size_t str_len, | |||
724 | *addr_len = 0; | 716 | *addr_len = 0; |
725 | } | 717 | } |
726 | 718 | ||
727 | #define IPV6_SCOPE_DELIMITER '%' | ||
728 | |||
729 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 719 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
730 | static void nfs_parse_ipv6_scope_id(const char *string, const size_t str_len, | 720 | static int nfs_parse_ipv6_scope_id(const char *string, const size_t str_len, |
731 | const char *delim, | 721 | const char *delim, |
732 | struct sockaddr_in6 *sin6) | 722 | struct sockaddr_in6 *sin6) |
733 | { | 723 | { |
734 | char *p; | 724 | char *p; |
735 | size_t len; | 725 | size_t len; |
736 | 726 | ||
737 | if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) | 727 | if ((string + str_len) == delim) |
738 | return ; | 728 | return 1; |
729 | |||
739 | if (*delim != IPV6_SCOPE_DELIMITER) | 730 | if (*delim != IPV6_SCOPE_DELIMITER) |
740 | return; | 731 | return 0; |
732 | |||
733 | if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) | ||
734 | return 0; | ||
741 | 735 | ||
742 | len = (string + str_len) - delim - 1; | 736 | len = (string + str_len) - delim - 1; |
743 | p = kstrndup(delim + 1, len, GFP_KERNEL); | 737 | p = kstrndup(delim + 1, len, GFP_KERNEL); |
@@ -750,14 +744,20 @@ static void nfs_parse_ipv6_scope_id(const char *string, const size_t str_len, | |||
750 | scope_id = dev->ifindex; | 744 | scope_id = dev->ifindex; |
751 | dev_put(dev); | 745 | dev_put(dev); |
752 | } else { | 746 | } else { |
753 | /* scope_id is set to zero on error */ | 747 | if (strict_strtoul(p, 10, &scope_id) == 0) { |
754 | strict_strtoul(p, 10, &scope_id); | 748 | kfree(p); |
749 | return 0; | ||
750 | } | ||
755 | } | 751 | } |
756 | 752 | ||
757 | kfree(p); | 753 | kfree(p); |
754 | |||
758 | sin6->sin6_scope_id = scope_id; | 755 | sin6->sin6_scope_id = scope_id; |
759 | dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id); | 756 | dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id); |
757 | return 1; | ||
760 | } | 758 | } |
759 | |||
760 | return 0; | ||
761 | } | 761 | } |
762 | 762 | ||
763 | static void nfs_parse_ipv6_address(char *string, size_t str_len, | 763 | static void nfs_parse_ipv6_address(char *string, size_t str_len, |
@@ -773,9 +773,11 @@ static void nfs_parse_ipv6_address(char *string, size_t str_len, | |||
773 | 773 | ||
774 | sin6->sin6_family = AF_INET6; | 774 | sin6->sin6_family = AF_INET6; |
775 | *addr_len = sizeof(*sin6); | 775 | *addr_len = sizeof(*sin6); |
776 | if (in6_pton(string, str_len, addr, IPV6_SCOPE_DELIMITER, &delim)) { | 776 | if (in6_pton(string, str_len, addr, |
777 | nfs_parse_ipv6_scope_id(string, str_len, delim, sin6); | 777 | IPV6_SCOPE_DELIMITER, &delim) != 0) { |
778 | return; | 778 | if (nfs_parse_ipv6_scope_id(string, str_len, |
779 | delim, sin6) != 0) | ||
780 | return; | ||
779 | } | 781 | } |
780 | } | 782 | } |
781 | 783 | ||
@@ -798,7 +800,7 @@ static void nfs_parse_ipv6_address(char *string, size_t str_len, | |||
798 | * If there is a problem constructing the new sockaddr, set the address | 800 | * If there is a problem constructing the new sockaddr, set the address |
799 | * family to AF_UNSPEC. | 801 | * family to AF_UNSPEC. |
800 | */ | 802 | */ |
801 | static void nfs_parse_ip_address(char *string, size_t str_len, | 803 | void nfs_parse_ip_address(char *string, size_t str_len, |
802 | struct sockaddr *sap, size_t *addr_len) | 804 | struct sockaddr *sap, size_t *addr_len) |
803 | { | 805 | { |
804 | unsigned int i, colons; | 806 | unsigned int i, colons; |
@@ -1258,6 +1260,30 @@ static int nfs_parse_mount_options(char *raw, | |||
1258 | &mnt->mount_server.addrlen); | 1260 | &mnt->mount_server.addrlen); |
1259 | kfree(string); | 1261 | kfree(string); |
1260 | break; | 1262 | break; |
1263 | case Opt_lookupcache: | ||
1264 | string = match_strdup(args); | ||
1265 | if (string == NULL) | ||
1266 | goto out_nomem; | ||
1267 | token = match_token(string, | ||
1268 | nfs_lookupcache_tokens, args); | ||
1269 | kfree(string); | ||
1270 | switch (token) { | ||
1271 | case Opt_lookupcache_all: | ||
1272 | mnt->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE); | ||
1273 | break; | ||
1274 | case Opt_lookupcache_positive: | ||
1275 | mnt->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE; | ||
1276 | mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG; | ||
1277 | break; | ||
1278 | case Opt_lookupcache_none: | ||
1279 | mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; | ||
1280 | break; | ||
1281 | default: | ||
1282 | errors++; | ||
1283 | dfprintk(MOUNT, "NFS: invalid " | ||
1284 | "lookupcache argument\n"); | ||
1285 | }; | ||
1286 | break; | ||
1261 | 1287 | ||
1262 | /* | 1288 | /* |
1263 | * Special options | 1289 | * Special options |
@@ -1279,6 +1305,12 @@ static int nfs_parse_mount_options(char *raw, | |||
1279 | } | 1305 | } |
1280 | } | 1306 | } |
1281 | 1307 | ||
1308 | if (errors > 0) { | ||
1309 | dfprintk(MOUNT, "NFS: parsing encountered %d error%s\n", | ||
1310 | errors, (errors == 1 ? "" : "s")); | ||
1311 | if (!sloppy) | ||
1312 | return 0; | ||
1313 | } | ||
1282 | return 1; | 1314 | return 1; |
1283 | 1315 | ||
1284 | out_nomem: | 1316 | out_nomem: |
@@ -1552,7 +1584,7 @@ static int nfs_validate_mount_data(void *options, | |||
1552 | * Translate to nfs_parsed_mount_data, which nfs_fill_super | 1584 | * Translate to nfs_parsed_mount_data, which nfs_fill_super |
1553 | * can deal with. | 1585 | * can deal with. |
1554 | */ | 1586 | */ |
1555 | args->flags = data->flags; | 1587 | args->flags = data->flags & NFS_MOUNT_FLAGMASK; |
1556 | args->rsize = data->rsize; | 1588 | args->rsize = data->rsize; |
1557 | args->wsize = data->wsize; | 1589 | args->wsize = data->wsize; |
1558 | args->timeo = data->timeo; | 1590 | args->timeo = data->timeo; |