diff options
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r-- | fs/nfs/super.c | 882 |
1 files changed, 606 insertions, 276 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 614efeed5437..1b94e3650f5c 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <linux/inet.h> | 47 | #include <linux/inet.h> |
48 | #include <linux/in6.h> | 48 | #include <linux/in6.h> |
49 | #include <net/ipv6.h> | 49 | #include <net/ipv6.h> |
50 | #include <linux/netdevice.h> | ||
50 | #include <linux/nfs_xdr.h> | 51 | #include <linux/nfs_xdr.h> |
51 | #include <linux/magic.h> | 52 | #include <linux/magic.h> |
52 | #include <linux/parser.h> | 53 | #include <linux/parser.h> |
@@ -65,7 +66,6 @@ | |||
65 | enum { | 66 | enum { |
66 | /* Mount options that take no arguments */ | 67 | /* Mount options that take no arguments */ |
67 | Opt_soft, Opt_hard, | 68 | Opt_soft, Opt_hard, |
68 | Opt_intr, Opt_nointr, | ||
69 | Opt_posix, Opt_noposix, | 69 | Opt_posix, Opt_noposix, |
70 | Opt_cto, Opt_nocto, | 70 | Opt_cto, Opt_nocto, |
71 | Opt_ac, Opt_noac, | 71 | Opt_ac, Opt_noac, |
@@ -92,8 +92,8 @@ enum { | |||
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 | 94 | ||
95 | /* Mount options that are ignored */ | 95 | /* Special mount options */ |
96 | Opt_userspace, Opt_deprecated, | 96 | Opt_userspace, Opt_deprecated, Opt_sloppy, |
97 | 97 | ||
98 | Opt_err | 98 | Opt_err |
99 | }; | 99 | }; |
@@ -101,10 +101,14 @@ enum { | |||
101 | static match_table_t nfs_mount_option_tokens = { | 101 | static match_table_t nfs_mount_option_tokens = { |
102 | { Opt_userspace, "bg" }, | 102 | { Opt_userspace, "bg" }, |
103 | { Opt_userspace, "fg" }, | 103 | { Opt_userspace, "fg" }, |
104 | { Opt_userspace, "retry=%s" }, | ||
105 | |||
106 | { Opt_sloppy, "sloppy" }, | ||
107 | |||
104 | { Opt_soft, "soft" }, | 108 | { Opt_soft, "soft" }, |
105 | { Opt_hard, "hard" }, | 109 | { Opt_hard, "hard" }, |
106 | { Opt_intr, "intr" }, | 110 | { Opt_deprecated, "intr" }, |
107 | { Opt_nointr, "nointr" }, | 111 | { Opt_deprecated, "nointr" }, |
108 | { Opt_posix, "posix" }, | 112 | { Opt_posix, "posix" }, |
109 | { Opt_noposix, "noposix" }, | 113 | { Opt_noposix, "noposix" }, |
110 | { Opt_cto, "cto" }, | 114 | { Opt_cto, "cto" }, |
@@ -136,7 +140,6 @@ static match_table_t nfs_mount_option_tokens = { | |||
136 | { Opt_acdirmin, "acdirmin=%u" }, | 140 | { Opt_acdirmin, "acdirmin=%u" }, |
137 | { Opt_acdirmax, "acdirmax=%u" }, | 141 | { Opt_acdirmax, "acdirmax=%u" }, |
138 | { Opt_actimeo, "actimeo=%u" }, | 142 | { Opt_actimeo, "actimeo=%u" }, |
139 | { Opt_userspace, "retry=%u" }, | ||
140 | { Opt_namelen, "namlen=%u" }, | 143 | { Opt_namelen, "namlen=%u" }, |
141 | { Opt_mountport, "mountport=%u" }, | 144 | { Opt_mountport, "mountport=%u" }, |
142 | { Opt_mountvers, "mountvers=%u" }, | 145 | { Opt_mountvers, "mountvers=%u" }, |
@@ -207,6 +210,7 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, | |||
207 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 210 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
208 | static void nfs_kill_super(struct super_block *); | 211 | static void nfs_kill_super(struct super_block *); |
209 | static void nfs_put_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); | ||
210 | 214 | ||
211 | static struct file_system_type nfs_fs_type = { | 215 | static struct file_system_type nfs_fs_type = { |
212 | .owner = THIS_MODULE, | 216 | .owner = THIS_MODULE, |
@@ -234,6 +238,7 @@ static const struct super_operations nfs_sops = { | |||
234 | .umount_begin = nfs_umount_begin, | 238 | .umount_begin = nfs_umount_begin, |
235 | .show_options = nfs_show_options, | 239 | .show_options = nfs_show_options, |
236 | .show_stats = nfs_show_stats, | 240 | .show_stats = nfs_show_stats, |
241 | .remount_fs = nfs_remount, | ||
237 | }; | 242 | }; |
238 | 243 | ||
239 | #ifdef CONFIG_NFS_V4 | 244 | #ifdef CONFIG_NFS_V4 |
@@ -278,6 +283,7 @@ static const struct super_operations nfs4_sops = { | |||
278 | .umount_begin = nfs_umount_begin, | 283 | .umount_begin = nfs_umount_begin, |
279 | .show_options = nfs_show_options, | 284 | .show_options = nfs_show_options, |
280 | .show_stats = nfs_show_stats, | 285 | .show_stats = nfs_show_stats, |
286 | .remount_fs = nfs_remount, | ||
281 | }; | 287 | }; |
282 | #endif | 288 | #endif |
283 | 289 | ||
@@ -368,8 +374,6 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
368 | }; | 374 | }; |
369 | int error; | 375 | int error; |
370 | 376 | ||
371 | lock_kernel(); | ||
372 | |||
373 | error = server->nfs_client->rpc_ops->statfs(server, fh, &res); | 377 | error = server->nfs_client->rpc_ops->statfs(server, fh, &res); |
374 | if (error < 0) | 378 | if (error < 0) |
375 | goto out_err; | 379 | goto out_err; |
@@ -401,12 +405,10 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
401 | 405 | ||
402 | buf->f_namelen = server->namelen; | 406 | buf->f_namelen = server->namelen; |
403 | 407 | ||
404 | unlock_kernel(); | ||
405 | return 0; | 408 | return 0; |
406 | 409 | ||
407 | out_err: | 410 | out_err: |
408 | dprintk("%s: statfs error = %d\n", __func__, -error); | 411 | dprintk("%s: statfs error = %d\n", __func__, -error); |
409 | unlock_kernel(); | ||
410 | return error; | 412 | return error; |
411 | } | 413 | } |
412 | 414 | ||
@@ -514,13 +516,13 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
514 | if (nfss->bsize != 0) | 516 | if (nfss->bsize != 0) |
515 | seq_printf(m, ",bsize=%u", nfss->bsize); | 517 | seq_printf(m, ",bsize=%u", nfss->bsize); |
516 | seq_printf(m, ",namlen=%u", nfss->namelen); | 518 | seq_printf(m, ",namlen=%u", nfss->namelen); |
517 | if (nfss->acregmin != 3*HZ || showdefaults) | 519 | if (nfss->acregmin != NFS_DEF_ACREGMIN*HZ || showdefaults) |
518 | seq_printf(m, ",acregmin=%u", nfss->acregmin/HZ); | 520 | seq_printf(m, ",acregmin=%u", nfss->acregmin/HZ); |
519 | if (nfss->acregmax != 60*HZ || showdefaults) | 521 | if (nfss->acregmax != NFS_DEF_ACREGMAX*HZ || showdefaults) |
520 | seq_printf(m, ",acregmax=%u", nfss->acregmax/HZ); | 522 | seq_printf(m, ",acregmax=%u", nfss->acregmax/HZ); |
521 | if (nfss->acdirmin != 30*HZ || showdefaults) | 523 | if (nfss->acdirmin != NFS_DEF_ACDIRMIN*HZ || showdefaults) |
522 | seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ); | 524 | seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ); |
523 | if (nfss->acdirmax != 60*HZ || showdefaults) | 525 | if (nfss->acdirmax != NFS_DEF_ACDIRMAX*HZ || showdefaults) |
524 | seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ); | 526 | seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ); |
525 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { | 527 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { |
526 | if (nfss->flags & nfs_infop->flag) | 528 | if (nfss->flags & nfs_infop->flag) |
@@ -702,49 +704,233 @@ static int nfs_verify_server_address(struct sockaddr *addr) | |||
702 | return 0; | 704 | return 0; |
703 | } | 705 | } |
704 | 706 | ||
707 | static void nfs_parse_ipv4_address(char *string, size_t str_len, | ||
708 | struct sockaddr *sap, size_t *addr_len) | ||
709 | { | ||
710 | struct sockaddr_in *sin = (struct sockaddr_in *)sap; | ||
711 | u8 *addr = (u8 *)&sin->sin_addr.s_addr; | ||
712 | |||
713 | if (str_len <= INET_ADDRSTRLEN) { | ||
714 | dfprintk(MOUNT, "NFS: parsing IPv4 address %*s\n", | ||
715 | (int)str_len, string); | ||
716 | |||
717 | sin->sin_family = AF_INET; | ||
718 | *addr_len = sizeof(*sin); | ||
719 | if (in4_pton(string, str_len, addr, '\0', NULL)) | ||
720 | return; | ||
721 | } | ||
722 | |||
723 | sap->sa_family = AF_UNSPEC; | ||
724 | *addr_len = 0; | ||
725 | } | ||
726 | |||
727 | #define IPV6_SCOPE_DELIMITER '%' | ||
728 | |||
729 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
730 | static void nfs_parse_ipv6_scope_id(const char *string, const size_t str_len, | ||
731 | const char *delim, | ||
732 | struct sockaddr_in6 *sin6) | ||
733 | { | ||
734 | char *p; | ||
735 | size_t len; | ||
736 | |||
737 | if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) | ||
738 | return ; | ||
739 | if (*delim != IPV6_SCOPE_DELIMITER) | ||
740 | return; | ||
741 | |||
742 | len = (string + str_len) - delim - 1; | ||
743 | p = kstrndup(delim + 1, len, GFP_KERNEL); | ||
744 | if (p) { | ||
745 | unsigned long scope_id = 0; | ||
746 | struct net_device *dev; | ||
747 | |||
748 | dev = dev_get_by_name(&init_net, p); | ||
749 | if (dev != NULL) { | ||
750 | scope_id = dev->ifindex; | ||
751 | dev_put(dev); | ||
752 | } else { | ||
753 | /* scope_id is set to zero on error */ | ||
754 | strict_strtoul(p, 10, &scope_id); | ||
755 | } | ||
756 | |||
757 | kfree(p); | ||
758 | sin6->sin6_scope_id = scope_id; | ||
759 | dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id); | ||
760 | } | ||
761 | } | ||
762 | |||
763 | static void nfs_parse_ipv6_address(char *string, size_t str_len, | ||
764 | struct sockaddr *sap, size_t *addr_len) | ||
765 | { | ||
766 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | ||
767 | u8 *addr = (u8 *)&sin6->sin6_addr.in6_u; | ||
768 | const char *delim; | ||
769 | |||
770 | if (str_len <= INET6_ADDRSTRLEN) { | ||
771 | dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n", | ||
772 | (int)str_len, string); | ||
773 | |||
774 | sin6->sin6_family = AF_INET6; | ||
775 | *addr_len = sizeof(*sin6); | ||
776 | if (in6_pton(string, str_len, addr, IPV6_SCOPE_DELIMITER, &delim)) { | ||
777 | nfs_parse_ipv6_scope_id(string, str_len, delim, sin6); | ||
778 | return; | ||
779 | } | ||
780 | } | ||
781 | |||
782 | sap->sa_family = AF_UNSPEC; | ||
783 | *addr_len = 0; | ||
784 | } | ||
785 | #else | ||
786 | static void nfs_parse_ipv6_address(char *string, size_t str_len, | ||
787 | struct sockaddr *sap, size_t *addr_len) | ||
788 | { | ||
789 | sap->sa_family = AF_UNSPEC; | ||
790 | *addr_len = 0; | ||
791 | } | ||
792 | #endif | ||
793 | |||
705 | /* | 794 | /* |
706 | * Parse string addresses passed in via a mount option, | 795 | * Construct a sockaddr based on the contents of a string that contains |
707 | * and construct a sockaddr based on the result. | 796 | * an IP address in presentation format. |
708 | * | 797 | * |
709 | * If address parsing fails, set the sockaddr's address | 798 | * If there is a problem constructing the new sockaddr, set the address |
710 | * family to AF_UNSPEC to force nfs_verify_server_address() | 799 | * family to AF_UNSPEC. |
711 | * to punt the mount. | ||
712 | */ | 800 | */ |
713 | static void nfs_parse_server_address(char *value, | 801 | static void nfs_parse_ip_address(char *string, size_t str_len, |
714 | struct sockaddr *sap, | 802 | struct sockaddr *sap, size_t *addr_len) |
715 | size_t *len) | ||
716 | { | 803 | { |
717 | if (strchr(value, ':')) { | 804 | unsigned int i, colons; |
718 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
719 | u8 *addr = (u8 *)&ap->sin6_addr.in6_u; | ||
720 | 805 | ||
721 | ap->sin6_family = AF_INET6; | 806 | colons = 0; |
722 | *len = sizeof(*ap); | 807 | for (i = 0; i < str_len; i++) |
723 | if (in6_pton(value, -1, addr, '\0', NULL)) | 808 | if (string[i] == ':') |
724 | return; | 809 | colons++; |
725 | } else { | 810 | |
726 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | 811 | if (colons >= 2) |
727 | u8 *addr = (u8 *)&ap->sin_addr.s_addr; | 812 | nfs_parse_ipv6_address(string, str_len, sap, addr_len); |
813 | else | ||
814 | nfs_parse_ipv4_address(string, str_len, sap, addr_len); | ||
815 | } | ||
816 | |||
817 | /* | ||
818 | * Sanity check the NFS transport protocol. | ||
819 | * | ||
820 | */ | ||
821 | static void nfs_validate_transport_protocol(struct nfs_parsed_mount_data *mnt) | ||
822 | { | ||
823 | switch (mnt->nfs_server.protocol) { | ||
824 | case XPRT_TRANSPORT_UDP: | ||
825 | case XPRT_TRANSPORT_TCP: | ||
826 | case XPRT_TRANSPORT_RDMA: | ||
827 | break; | ||
828 | default: | ||
829 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; | ||
830 | } | ||
831 | } | ||
832 | |||
833 | /* | ||
834 | * For text based NFSv2/v3 mounts, the mount protocol transport default | ||
835 | * settings should depend upon the specified NFS transport. | ||
836 | */ | ||
837 | static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt) | ||
838 | { | ||
839 | nfs_validate_transport_protocol(mnt); | ||
728 | 840 | ||
729 | ap->sin_family = AF_INET; | 841 | if (mnt->mount_server.protocol == XPRT_TRANSPORT_UDP || |
730 | *len = sizeof(*ap); | 842 | mnt->mount_server.protocol == XPRT_TRANSPORT_TCP) |
731 | if (in4_pton(value, -1, addr, '\0', NULL)) | ||
732 | return; | 843 | return; |
844 | switch (mnt->nfs_server.protocol) { | ||
845 | case XPRT_TRANSPORT_UDP: | ||
846 | mnt->mount_server.protocol = XPRT_TRANSPORT_UDP; | ||
847 | break; | ||
848 | case XPRT_TRANSPORT_TCP: | ||
849 | case XPRT_TRANSPORT_RDMA: | ||
850 | mnt->mount_server.protocol = XPRT_TRANSPORT_TCP; | ||
733 | } | 851 | } |
852 | } | ||
734 | 853 | ||
735 | sap->sa_family = AF_UNSPEC; | 854 | /* |
736 | *len = 0; | 855 | * Parse the value of the 'sec=' option. |
856 | * | ||
857 | * The flavor_len setting is for v4 mounts. | ||
858 | */ | ||
859 | static int nfs_parse_security_flavors(char *value, | ||
860 | struct nfs_parsed_mount_data *mnt) | ||
861 | { | ||
862 | substring_t args[MAX_OPT_ARGS]; | ||
863 | |||
864 | dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value); | ||
865 | |||
866 | switch (match_token(value, nfs_secflavor_tokens, args)) { | ||
867 | case Opt_sec_none: | ||
868 | mnt->auth_flavor_len = 0; | ||
869 | mnt->auth_flavors[0] = RPC_AUTH_NULL; | ||
870 | break; | ||
871 | case Opt_sec_sys: | ||
872 | mnt->auth_flavor_len = 0; | ||
873 | mnt->auth_flavors[0] = RPC_AUTH_UNIX; | ||
874 | break; | ||
875 | case Opt_sec_krb5: | ||
876 | mnt->auth_flavor_len = 1; | ||
877 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; | ||
878 | break; | ||
879 | case Opt_sec_krb5i: | ||
880 | mnt->auth_flavor_len = 1; | ||
881 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; | ||
882 | break; | ||
883 | case Opt_sec_krb5p: | ||
884 | mnt->auth_flavor_len = 1; | ||
885 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; | ||
886 | break; | ||
887 | case Opt_sec_lkey: | ||
888 | mnt->auth_flavor_len = 1; | ||
889 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; | ||
890 | break; | ||
891 | case Opt_sec_lkeyi: | ||
892 | mnt->auth_flavor_len = 1; | ||
893 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; | ||
894 | break; | ||
895 | case Opt_sec_lkeyp: | ||
896 | mnt->auth_flavor_len = 1; | ||
897 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; | ||
898 | break; | ||
899 | case Opt_sec_spkm: | ||
900 | mnt->auth_flavor_len = 1; | ||
901 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; | ||
902 | break; | ||
903 | case Opt_sec_spkmi: | ||
904 | mnt->auth_flavor_len = 1; | ||
905 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; | ||
906 | break; | ||
907 | case Opt_sec_spkmp: | ||
908 | mnt->auth_flavor_len = 1; | ||
909 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; | ||
910 | break; | ||
911 | default: | ||
912 | return 0; | ||
913 | } | ||
914 | |||
915 | return 1; | ||
916 | } | ||
917 | |||
918 | static void nfs_parse_invalid_value(const char *option) | ||
919 | { | ||
920 | dfprintk(MOUNT, "NFS: bad value specified for %s option\n", option); | ||
737 | } | 921 | } |
738 | 922 | ||
739 | /* | 923 | /* |
740 | * Error-check and convert a string of mount options from user space into | 924 | * Error-check and convert a string of mount options from user space into |
741 | * a data structure | 925 | * a data structure. The whole mount string is processed; bad options are |
926 | * skipped as they are encountered. If there were no errors, return 1; | ||
927 | * otherwise return 0 (zero). | ||
742 | */ | 928 | */ |
743 | static int nfs_parse_mount_options(char *raw, | 929 | static int nfs_parse_mount_options(char *raw, |
744 | struct nfs_parsed_mount_data *mnt) | 930 | struct nfs_parsed_mount_data *mnt) |
745 | { | 931 | { |
746 | char *p, *string, *secdata; | 932 | char *p, *string, *secdata; |
747 | int rc; | 933 | int rc, sloppy = 0, errors = 0; |
748 | 934 | ||
749 | if (!raw) { | 935 | if (!raw) { |
750 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); | 936 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); |
@@ -777,15 +963,16 @@ static int nfs_parse_mount_options(char *raw, | |||
777 | 963 | ||
778 | token = match_token(p, nfs_mount_option_tokens, args); | 964 | token = match_token(p, nfs_mount_option_tokens, args); |
779 | switch (token) { | 965 | switch (token) { |
966 | |||
967 | /* | ||
968 | * boolean options: foo/nofoo | ||
969 | */ | ||
780 | case Opt_soft: | 970 | case Opt_soft: |
781 | mnt->flags |= NFS_MOUNT_SOFT; | 971 | mnt->flags |= NFS_MOUNT_SOFT; |
782 | break; | 972 | break; |
783 | case Opt_hard: | 973 | case Opt_hard: |
784 | mnt->flags &= ~NFS_MOUNT_SOFT; | 974 | mnt->flags &= ~NFS_MOUNT_SOFT; |
785 | break; | 975 | break; |
786 | case Opt_intr: | ||
787 | case Opt_nointr: | ||
788 | break; | ||
789 | case Opt_posix: | 976 | case Opt_posix: |
790 | mnt->flags |= NFS_MOUNT_POSIX; | 977 | mnt->flags |= NFS_MOUNT_POSIX; |
791 | break; | 978 | break; |
@@ -819,20 +1006,14 @@ static int nfs_parse_mount_options(char *raw, | |||
819 | case Opt_udp: | 1006 | case Opt_udp: |
820 | mnt->flags &= ~NFS_MOUNT_TCP; | 1007 | mnt->flags &= ~NFS_MOUNT_TCP; |
821 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1008 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
822 | mnt->timeo = 7; | ||
823 | mnt->retrans = 5; | ||
824 | break; | 1009 | break; |
825 | case Opt_tcp: | 1010 | case Opt_tcp: |
826 | mnt->flags |= NFS_MOUNT_TCP; | 1011 | mnt->flags |= NFS_MOUNT_TCP; |
827 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1012 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
828 | mnt->timeo = 600; | ||
829 | mnt->retrans = 2; | ||
830 | break; | 1013 | break; |
831 | case Opt_rdma: | 1014 | case Opt_rdma: |
832 | mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */ | 1015 | mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */ |
833 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; | 1016 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; |
834 | mnt->timeo = 600; | ||
835 | mnt->retrans = 2; | ||
836 | break; | 1017 | break; |
837 | case Opt_acl: | 1018 | case Opt_acl: |
838 | mnt->flags &= ~NFS_MOUNT_NOACL; | 1019 | mnt->flags &= ~NFS_MOUNT_NOACL; |
@@ -853,165 +1034,144 @@ static int nfs_parse_mount_options(char *raw, | |||
853 | mnt->flags |= NFS_MOUNT_UNSHARED; | 1034 | mnt->flags |= NFS_MOUNT_UNSHARED; |
854 | break; | 1035 | break; |
855 | 1036 | ||
1037 | /* | ||
1038 | * options that take numeric values | ||
1039 | */ | ||
856 | case Opt_port: | 1040 | case Opt_port: |
857 | if (match_int(args, &option)) | 1041 | if (match_int(args, &option) || |
858 | return 0; | 1042 | option < 0 || option > USHORT_MAX) { |
859 | if (option < 0 || option > 65535) | 1043 | errors++; |
860 | return 0; | 1044 | nfs_parse_invalid_value("port"); |
861 | mnt->nfs_server.port = option; | 1045 | } else |
1046 | mnt->nfs_server.port = option; | ||
862 | break; | 1047 | break; |
863 | case Opt_rsize: | 1048 | case Opt_rsize: |
864 | if (match_int(args, &mnt->rsize)) | 1049 | if (match_int(args, &option) || option < 0) { |
865 | return 0; | 1050 | errors++; |
1051 | nfs_parse_invalid_value("rsize"); | ||
1052 | } else | ||
1053 | mnt->rsize = option; | ||
866 | break; | 1054 | break; |
867 | case Opt_wsize: | 1055 | case Opt_wsize: |
868 | if (match_int(args, &mnt->wsize)) | 1056 | if (match_int(args, &option) || option < 0) { |
869 | return 0; | 1057 | errors++; |
1058 | nfs_parse_invalid_value("wsize"); | ||
1059 | } else | ||
1060 | mnt->wsize = option; | ||
870 | break; | 1061 | break; |
871 | case Opt_bsize: | 1062 | case Opt_bsize: |
872 | if (match_int(args, &option)) | 1063 | if (match_int(args, &option) || option < 0) { |
873 | return 0; | 1064 | errors++; |
874 | if (option < 0) | 1065 | nfs_parse_invalid_value("bsize"); |
875 | return 0; | 1066 | } else |
876 | mnt->bsize = option; | 1067 | mnt->bsize = option; |
877 | break; | 1068 | break; |
878 | case Opt_timeo: | 1069 | case Opt_timeo: |
879 | if (match_int(args, &mnt->timeo)) | 1070 | if (match_int(args, &option) || option <= 0) { |
880 | return 0; | 1071 | errors++; |
1072 | nfs_parse_invalid_value("timeo"); | ||
1073 | } else | ||
1074 | mnt->timeo = option; | ||
881 | break; | 1075 | break; |
882 | case Opt_retrans: | 1076 | case Opt_retrans: |
883 | if (match_int(args, &mnt->retrans)) | 1077 | if (match_int(args, &option) || option <= 0) { |
884 | return 0; | 1078 | errors++; |
1079 | nfs_parse_invalid_value("retrans"); | ||
1080 | } else | ||
1081 | mnt->retrans = option; | ||
885 | break; | 1082 | break; |
886 | case Opt_acregmin: | 1083 | case Opt_acregmin: |
887 | if (match_int(args, &mnt->acregmin)) | 1084 | if (match_int(args, &option) || option < 0) { |
888 | return 0; | 1085 | errors++; |
1086 | nfs_parse_invalid_value("acregmin"); | ||
1087 | } else | ||
1088 | mnt->acregmin = option; | ||
889 | break; | 1089 | break; |
890 | case Opt_acregmax: | 1090 | case Opt_acregmax: |
891 | if (match_int(args, &mnt->acregmax)) | 1091 | if (match_int(args, &option) || option < 0) { |
892 | return 0; | 1092 | errors++; |
1093 | nfs_parse_invalid_value("acregmax"); | ||
1094 | } else | ||
1095 | mnt->acregmax = option; | ||
893 | break; | 1096 | break; |
894 | case Opt_acdirmin: | 1097 | case Opt_acdirmin: |
895 | if (match_int(args, &mnt->acdirmin)) | 1098 | if (match_int(args, &option) || option < 0) { |
896 | return 0; | 1099 | errors++; |
1100 | nfs_parse_invalid_value("acdirmin"); | ||
1101 | } else | ||
1102 | mnt->acdirmin = option; | ||
897 | break; | 1103 | break; |
898 | case Opt_acdirmax: | 1104 | case Opt_acdirmax: |
899 | if (match_int(args, &mnt->acdirmax)) | 1105 | if (match_int(args, &option) || option < 0) { |
900 | return 0; | 1106 | errors++; |
1107 | nfs_parse_invalid_value("acdirmax"); | ||
1108 | } else | ||
1109 | mnt->acdirmax = option; | ||
901 | break; | 1110 | break; |
902 | case Opt_actimeo: | 1111 | case Opt_actimeo: |
903 | if (match_int(args, &option)) | 1112 | if (match_int(args, &option) || option < 0) { |
904 | return 0; | 1113 | errors++; |
905 | if (option < 0) | 1114 | nfs_parse_invalid_value("actimeo"); |
906 | return 0; | 1115 | } else |
907 | mnt->acregmin = | 1116 | mnt->acregmin = mnt->acregmax = |
908 | mnt->acregmax = | 1117 | mnt->acdirmin = mnt->acdirmax = option; |
909 | mnt->acdirmin = | ||
910 | mnt->acdirmax = option; | ||
911 | break; | 1118 | break; |
912 | case Opt_namelen: | 1119 | case Opt_namelen: |
913 | if (match_int(args, &mnt->namlen)) | 1120 | if (match_int(args, &option) || option < 0) { |
914 | return 0; | 1121 | errors++; |
1122 | nfs_parse_invalid_value("namlen"); | ||
1123 | } else | ||
1124 | mnt->namlen = option; | ||
915 | break; | 1125 | break; |
916 | case Opt_mountport: | 1126 | case Opt_mountport: |
917 | if (match_int(args, &option)) | 1127 | if (match_int(args, &option) || |
918 | return 0; | 1128 | option < 0 || option > USHORT_MAX) { |
919 | if (option < 0 || option > 65535) | 1129 | errors++; |
920 | return 0; | 1130 | nfs_parse_invalid_value("mountport"); |
921 | mnt->mount_server.port = option; | 1131 | } else |
1132 | mnt->mount_server.port = option; | ||
922 | break; | 1133 | break; |
923 | case Opt_mountvers: | 1134 | case Opt_mountvers: |
924 | if (match_int(args, &option)) | 1135 | if (match_int(args, &option) || |
925 | return 0; | 1136 | option < NFS_MNT_VERSION || |
926 | if (option < 0) | 1137 | option > NFS_MNT3_VERSION) { |
927 | return 0; | 1138 | errors++; |
928 | mnt->mount_server.version = option; | 1139 | nfs_parse_invalid_value("mountvers"); |
1140 | } else | ||
1141 | mnt->mount_server.version = option; | ||
929 | break; | 1142 | break; |
930 | case Opt_nfsvers: | 1143 | case Opt_nfsvers: |
931 | if (match_int(args, &option)) | 1144 | if (match_int(args, &option)) { |
932 | return 0; | 1145 | errors++; |
1146 | nfs_parse_invalid_value("nfsvers"); | ||
1147 | break; | ||
1148 | } | ||
933 | switch (option) { | 1149 | switch (option) { |
934 | case 2: | 1150 | case NFS2_VERSION: |
935 | mnt->flags &= ~NFS_MOUNT_VER3; | 1151 | mnt->flags &= ~NFS_MOUNT_VER3; |
936 | break; | 1152 | break; |
937 | case 3: | 1153 | case NFS3_VERSION: |
938 | mnt->flags |= NFS_MOUNT_VER3; | 1154 | mnt->flags |= NFS_MOUNT_VER3; |
939 | break; | 1155 | break; |
940 | default: | 1156 | default: |
941 | goto out_unrec_vers; | 1157 | errors++; |
1158 | nfs_parse_invalid_value("nfsvers"); | ||
942 | } | 1159 | } |
943 | break; | 1160 | break; |
944 | 1161 | ||
1162 | /* | ||
1163 | * options that take text values | ||
1164 | */ | ||
945 | case Opt_sec: | 1165 | case Opt_sec: |
946 | string = match_strdup(args); | 1166 | string = match_strdup(args); |
947 | if (string == NULL) | 1167 | if (string == NULL) |
948 | goto out_nomem; | 1168 | goto out_nomem; |
949 | token = match_token(string, nfs_secflavor_tokens, args); | 1169 | rc = nfs_parse_security_flavors(string, mnt); |
950 | kfree(string); | 1170 | kfree(string); |
951 | 1171 | if (!rc) { | |
952 | /* | 1172 | errors++; |
953 | * The flags setting is for v2/v3. The flavor_len | 1173 | dfprintk(MOUNT, "NFS: unrecognized " |
954 | * setting is for v4. v2/v3 also need to know the | 1174 | "security flavor\n"); |
955 | * difference between NULL and UNIX. | ||
956 | */ | ||
957 | switch (token) { | ||
958 | case Opt_sec_none: | ||
959 | mnt->flags &= ~NFS_MOUNT_SECFLAVOUR; | ||
960 | mnt->auth_flavor_len = 0; | ||
961 | mnt->auth_flavors[0] = RPC_AUTH_NULL; | ||
962 | break; | ||
963 | case Opt_sec_sys: | ||
964 | mnt->flags &= ~NFS_MOUNT_SECFLAVOUR; | ||
965 | mnt->auth_flavor_len = 0; | ||
966 | mnt->auth_flavors[0] = RPC_AUTH_UNIX; | ||
967 | break; | ||
968 | case Opt_sec_krb5: | ||
969 | mnt->flags |= NFS_MOUNT_SECFLAVOUR; | ||
970 | mnt->auth_flavor_len = 1; | ||
971 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; | ||
972 | break; | ||
973 | case Opt_sec_krb5i: | ||
974 | mnt->flags |= NFS_MOUNT_SECFLAVOUR; | ||
975 | mnt->auth_flavor_len = 1; | ||
976 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; | ||
977 | break; | ||
978 | case Opt_sec_krb5p: | ||
979 | mnt->flags |= NFS_MOUNT_SECFLAVOUR; | ||
980 | mnt->auth_flavor_len = 1; | ||
981 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; | ||
982 | break; | ||
983 | case Opt_sec_lkey: | ||
984 | mnt->flags |= NFS_MOUNT_SECFLAVOUR; | ||
985 | mnt->auth_flavor_len = 1; | ||
986 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; | ||
987 | break; | ||
988 | case Opt_sec_lkeyi: | ||
989 | mnt->flags |= NFS_MOUNT_SECFLAVOUR; | ||
990 | mnt->auth_flavor_len = 1; | ||
991 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; | ||
992 | break; | ||
993 | case Opt_sec_lkeyp: | ||
994 | mnt->flags |= NFS_MOUNT_SECFLAVOUR; | ||
995 | mnt->auth_flavor_len = 1; | ||
996 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; | ||
997 | break; | ||
998 | case Opt_sec_spkm: | ||
999 | mnt->flags |= NFS_MOUNT_SECFLAVOUR; | ||
1000 | mnt->auth_flavor_len = 1; | ||
1001 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; | ||
1002 | break; | ||
1003 | case Opt_sec_spkmi: | ||
1004 | mnt->flags |= NFS_MOUNT_SECFLAVOUR; | ||
1005 | mnt->auth_flavor_len = 1; | ||
1006 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; | ||
1007 | break; | ||
1008 | case Opt_sec_spkmp: | ||
1009 | mnt->flags |= NFS_MOUNT_SECFLAVOUR; | ||
1010 | mnt->auth_flavor_len = 1; | ||
1011 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; | ||
1012 | break; | ||
1013 | default: | ||
1014 | goto out_unrec_sec; | ||
1015 | } | 1175 | } |
1016 | break; | 1176 | break; |
1017 | case Opt_proto: | 1177 | case Opt_proto: |
@@ -1026,24 +1186,20 @@ static int nfs_parse_mount_options(char *raw, | |||
1026 | case Opt_xprt_udp: | 1186 | case Opt_xprt_udp: |
1027 | mnt->flags &= ~NFS_MOUNT_TCP; | 1187 | mnt->flags &= ~NFS_MOUNT_TCP; |
1028 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1188 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
1029 | mnt->timeo = 7; | ||
1030 | mnt->retrans = 5; | ||
1031 | break; | 1189 | break; |
1032 | case Opt_xprt_tcp: | 1190 | case Opt_xprt_tcp: |
1033 | mnt->flags |= NFS_MOUNT_TCP; | 1191 | mnt->flags |= NFS_MOUNT_TCP; |
1034 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1192 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1035 | mnt->timeo = 600; | ||
1036 | mnt->retrans = 2; | ||
1037 | break; | 1193 | break; |
1038 | case Opt_xprt_rdma: | 1194 | case Opt_xprt_rdma: |
1039 | /* vector side protocols to TCP */ | 1195 | /* vector side protocols to TCP */ |
1040 | mnt->flags |= NFS_MOUNT_TCP; | 1196 | mnt->flags |= NFS_MOUNT_TCP; |
1041 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; | 1197 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; |
1042 | mnt->timeo = 600; | ||
1043 | mnt->retrans = 2; | ||
1044 | break; | 1198 | break; |
1045 | default: | 1199 | default: |
1046 | goto out_unrec_xprt; | 1200 | errors++; |
1201 | dfprintk(MOUNT, "NFS: unrecognized " | ||
1202 | "transport protocol\n"); | ||
1047 | } | 1203 | } |
1048 | break; | 1204 | break; |
1049 | case Opt_mountproto: | 1205 | case Opt_mountproto: |
@@ -1063,16 +1219,19 @@ static int nfs_parse_mount_options(char *raw, | |||
1063 | break; | 1219 | break; |
1064 | case Opt_xprt_rdma: /* not used for side protocols */ | 1220 | case Opt_xprt_rdma: /* not used for side protocols */ |
1065 | default: | 1221 | default: |
1066 | goto out_unrec_xprt; | 1222 | errors++; |
1223 | dfprintk(MOUNT, "NFS: unrecognized " | ||
1224 | "transport protocol\n"); | ||
1067 | } | 1225 | } |
1068 | break; | 1226 | break; |
1069 | case Opt_addr: | 1227 | case Opt_addr: |
1070 | string = match_strdup(args); | 1228 | string = match_strdup(args); |
1071 | if (string == NULL) | 1229 | if (string == NULL) |
1072 | goto out_nomem; | 1230 | goto out_nomem; |
1073 | nfs_parse_server_address(string, (struct sockaddr *) | 1231 | nfs_parse_ip_address(string, strlen(string), |
1074 | &mnt->nfs_server.address, | 1232 | (struct sockaddr *) |
1075 | &mnt->nfs_server.addrlen); | 1233 | &mnt->nfs_server.address, |
1234 | &mnt->nfs_server.addrlen); | ||
1076 | kfree(string); | 1235 | kfree(string); |
1077 | break; | 1236 | break; |
1078 | case Opt_clientaddr: | 1237 | case Opt_clientaddr: |
@@ -1093,24 +1252,33 @@ static int nfs_parse_mount_options(char *raw, | |||
1093 | string = match_strdup(args); | 1252 | string = match_strdup(args); |
1094 | if (string == NULL) | 1253 | if (string == NULL) |
1095 | goto out_nomem; | 1254 | goto out_nomem; |
1096 | nfs_parse_server_address(string, (struct sockaddr *) | 1255 | nfs_parse_ip_address(string, strlen(string), |
1097 | &mnt->mount_server.address, | 1256 | (struct sockaddr *) |
1098 | &mnt->mount_server.addrlen); | 1257 | &mnt->mount_server.address, |
1258 | &mnt->mount_server.addrlen); | ||
1099 | kfree(string); | 1259 | kfree(string); |
1100 | break; | 1260 | break; |
1101 | 1261 | ||
1262 | /* | ||
1263 | * Special options | ||
1264 | */ | ||
1265 | case Opt_sloppy: | ||
1266 | sloppy = 1; | ||
1267 | dfprintk(MOUNT, "NFS: relaxing parsing rules\n"); | ||
1268 | break; | ||
1102 | case Opt_userspace: | 1269 | case Opt_userspace: |
1103 | case Opt_deprecated: | 1270 | case Opt_deprecated: |
1271 | dfprintk(MOUNT, "NFS: ignoring mount option " | ||
1272 | "'%s'\n", p); | ||
1104 | break; | 1273 | break; |
1105 | 1274 | ||
1106 | default: | 1275 | default: |
1107 | goto out_unknown; | 1276 | errors++; |
1277 | dfprintk(MOUNT, "NFS: unrecognized mount option " | ||
1278 | "'%s'\n", p); | ||
1108 | } | 1279 | } |
1109 | } | 1280 | } |
1110 | 1281 | ||
1111 | nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, | ||
1112 | mnt->nfs_server.port); | ||
1113 | |||
1114 | return 1; | 1282 | return 1; |
1115 | 1283 | ||
1116 | out_nomem: | 1284 | out_nomem: |
@@ -1120,21 +1288,6 @@ out_security_failure: | |||
1120 | free_secdata(secdata); | 1288 | free_secdata(secdata); |
1121 | printk(KERN_INFO "NFS: security options invalid: %d\n", rc); | 1289 | printk(KERN_INFO "NFS: security options invalid: %d\n", rc); |
1122 | return 0; | 1290 | return 0; |
1123 | out_unrec_vers: | ||
1124 | printk(KERN_INFO "NFS: unrecognized NFS version number\n"); | ||
1125 | return 0; | ||
1126 | |||
1127 | out_unrec_xprt: | ||
1128 | printk(KERN_INFO "NFS: unrecognized transport protocol\n"); | ||
1129 | return 0; | ||
1130 | |||
1131 | out_unrec_sec: | ||
1132 | printk(KERN_INFO "NFS: unrecognized security flavor\n"); | ||
1133 | return 0; | ||
1134 | |||
1135 | out_unknown: | ||
1136 | printk(KERN_INFO "NFS: unknown mount option: %s\n", p); | ||
1137 | return 0; | ||
1138 | } | 1291 | } |
1139 | 1292 | ||
1140 | /* | 1293 | /* |
@@ -1188,11 +1341,146 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1188 | if (status == 0) | 1341 | if (status == 0) |
1189 | return 0; | 1342 | return 0; |
1190 | 1343 | ||
1191 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d", | 1344 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", |
1192 | hostname, status); | 1345 | hostname, status); |
1193 | return status; | 1346 | return status; |
1194 | } | 1347 | } |
1195 | 1348 | ||
1349 | static int nfs_parse_simple_hostname(const char *dev_name, | ||
1350 | char **hostname, size_t maxnamlen, | ||
1351 | char **export_path, size_t maxpathlen) | ||
1352 | { | ||
1353 | size_t len; | ||
1354 | char *colon, *comma; | ||
1355 | |||
1356 | colon = strchr(dev_name, ':'); | ||
1357 | if (colon == NULL) | ||
1358 | goto out_bad_devname; | ||
1359 | |||
1360 | len = colon - dev_name; | ||
1361 | if (len > maxnamlen) | ||
1362 | goto out_hostname; | ||
1363 | |||
1364 | /* N.B. caller will free nfs_server.hostname in all cases */ | ||
1365 | *hostname = kstrndup(dev_name, len, GFP_KERNEL); | ||
1366 | if (!*hostname) | ||
1367 | goto out_nomem; | ||
1368 | |||
1369 | /* kill possible hostname list: not supported */ | ||
1370 | comma = strchr(*hostname, ','); | ||
1371 | if (comma != NULL) { | ||
1372 | if (comma == *hostname) | ||
1373 | goto out_bad_devname; | ||
1374 | *comma = '\0'; | ||
1375 | } | ||
1376 | |||
1377 | colon++; | ||
1378 | len = strlen(colon); | ||
1379 | if (len > maxpathlen) | ||
1380 | goto out_path; | ||
1381 | *export_path = kstrndup(colon, len, GFP_KERNEL); | ||
1382 | if (!*export_path) | ||
1383 | goto out_nomem; | ||
1384 | |||
1385 | dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path); | ||
1386 | return 0; | ||
1387 | |||
1388 | out_bad_devname: | ||
1389 | dfprintk(MOUNT, "NFS: device name not in host:path format\n"); | ||
1390 | return -EINVAL; | ||
1391 | |||
1392 | out_nomem: | ||
1393 | dfprintk(MOUNT, "NFS: not enough memory to parse device name\n"); | ||
1394 | return -ENOMEM; | ||
1395 | |||
1396 | out_hostname: | ||
1397 | dfprintk(MOUNT, "NFS: server hostname too long\n"); | ||
1398 | return -ENAMETOOLONG; | ||
1399 | |||
1400 | out_path: | ||
1401 | dfprintk(MOUNT, "NFS: export pathname too long\n"); | ||
1402 | return -ENAMETOOLONG; | ||
1403 | } | ||
1404 | |||
1405 | /* | ||
1406 | * Hostname has square brackets around it because it contains one or | ||
1407 | * more colons. We look for the first closing square bracket, and a | ||
1408 | * colon must follow it. | ||
1409 | */ | ||
1410 | static int nfs_parse_protected_hostname(const char *dev_name, | ||
1411 | char **hostname, size_t maxnamlen, | ||
1412 | char **export_path, size_t maxpathlen) | ||
1413 | { | ||
1414 | size_t len; | ||
1415 | char *start, *end; | ||
1416 | |||
1417 | start = (char *)(dev_name + 1); | ||
1418 | |||
1419 | end = strchr(start, ']'); | ||
1420 | if (end == NULL) | ||
1421 | goto out_bad_devname; | ||
1422 | if (*(end + 1) != ':') | ||
1423 | goto out_bad_devname; | ||
1424 | |||
1425 | len = end - start; | ||
1426 | if (len > maxnamlen) | ||
1427 | goto out_hostname; | ||
1428 | |||
1429 | /* N.B. caller will free nfs_server.hostname in all cases */ | ||
1430 | *hostname = kstrndup(start, len, GFP_KERNEL); | ||
1431 | if (*hostname == NULL) | ||
1432 | goto out_nomem; | ||
1433 | |||
1434 | end += 2; | ||
1435 | len = strlen(end); | ||
1436 | if (len > maxpathlen) | ||
1437 | goto out_path; | ||
1438 | *export_path = kstrndup(end, len, GFP_KERNEL); | ||
1439 | if (!*export_path) | ||
1440 | goto out_nomem; | ||
1441 | |||
1442 | return 0; | ||
1443 | |||
1444 | out_bad_devname: | ||
1445 | dfprintk(MOUNT, "NFS: device name not in host:path format\n"); | ||
1446 | return -EINVAL; | ||
1447 | |||
1448 | out_nomem: | ||
1449 | dfprintk(MOUNT, "NFS: not enough memory to parse device name\n"); | ||
1450 | return -ENOMEM; | ||
1451 | |||
1452 | out_hostname: | ||
1453 | dfprintk(MOUNT, "NFS: server hostname too long\n"); | ||
1454 | return -ENAMETOOLONG; | ||
1455 | |||
1456 | out_path: | ||
1457 | dfprintk(MOUNT, "NFS: export pathname too long\n"); | ||
1458 | return -ENAMETOOLONG; | ||
1459 | } | ||
1460 | |||
1461 | /* | ||
1462 | * Split "dev_name" into "hostname:export_path". | ||
1463 | * | ||
1464 | * The leftmost colon demarks the split between the server's hostname | ||
1465 | * and the export path. If the hostname starts with a left square | ||
1466 | * bracket, then it may contain colons. | ||
1467 | * | ||
1468 | * Note: caller frees hostname and export path, even on error. | ||
1469 | */ | ||
1470 | static int nfs_parse_devname(const char *dev_name, | ||
1471 | char **hostname, size_t maxnamlen, | ||
1472 | char **export_path, size_t maxpathlen) | ||
1473 | { | ||
1474 | if (*dev_name == '[') | ||
1475 | return nfs_parse_protected_hostname(dev_name, | ||
1476 | hostname, maxnamlen, | ||
1477 | export_path, maxpathlen); | ||
1478 | |||
1479 | return nfs_parse_simple_hostname(dev_name, | ||
1480 | hostname, maxnamlen, | ||
1481 | export_path, maxpathlen); | ||
1482 | } | ||
1483 | |||
1196 | /* | 1484 | /* |
1197 | * Validate the NFS2/NFS3 mount data | 1485 | * Validate the NFS2/NFS3 mount data |
1198 | * - fills in the mount root filehandle | 1486 | * - fills in the mount root filehandle |
@@ -1222,16 +1510,14 @@ static int nfs_validate_mount_data(void *options, | |||
1222 | args->flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP); | 1510 | args->flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP); |
1223 | args->rsize = NFS_MAX_FILE_IO_SIZE; | 1511 | args->rsize = NFS_MAX_FILE_IO_SIZE; |
1224 | args->wsize = NFS_MAX_FILE_IO_SIZE; | 1512 | args->wsize = NFS_MAX_FILE_IO_SIZE; |
1225 | args->timeo = 600; | 1513 | args->acregmin = NFS_DEF_ACREGMIN; |
1226 | args->retrans = 2; | 1514 | args->acregmax = NFS_DEF_ACREGMAX; |
1227 | args->acregmin = 3; | 1515 | args->acdirmin = NFS_DEF_ACDIRMIN; |
1228 | args->acregmax = 60; | 1516 | args->acdirmax = NFS_DEF_ACDIRMAX; |
1229 | args->acdirmin = 30; | ||
1230 | args->acdirmax = 60; | ||
1231 | args->mount_server.port = 0; /* autobind unless user sets port */ | 1517 | args->mount_server.port = 0; /* autobind unless user sets port */ |
1232 | args->mount_server.protocol = XPRT_TRANSPORT_UDP; | ||
1233 | args->nfs_server.port = 0; /* autobind unless user sets port */ | 1518 | args->nfs_server.port = 0; /* autobind unless user sets port */ |
1234 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1519 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1520 | args->auth_flavors[0] = RPC_AUTH_UNIX; | ||
1235 | 1521 | ||
1236 | switch (data->version) { | 1522 | switch (data->version) { |
1237 | case 1: | 1523 | case 1: |
@@ -1289,7 +1575,9 @@ static int nfs_validate_mount_data(void *options, | |||
1289 | args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); | 1575 | args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); |
1290 | args->namlen = data->namlen; | 1576 | args->namlen = data->namlen; |
1291 | args->bsize = data->bsize; | 1577 | args->bsize = data->bsize; |
1292 | args->auth_flavors[0] = data->pseudoflavor; | 1578 | |
1579 | if (data->flags & NFS_MOUNT_SECFLAVOUR) | ||
1580 | args->auth_flavors[0] = data->pseudoflavor; | ||
1293 | if (!args->nfs_server.hostname) | 1581 | if (!args->nfs_server.hostname) |
1294 | goto out_nomem; | 1582 | goto out_nomem; |
1295 | 1583 | ||
@@ -1321,8 +1609,6 @@ static int nfs_validate_mount_data(void *options, | |||
1321 | 1609 | ||
1322 | break; | 1610 | break; |
1323 | default: { | 1611 | default: { |
1324 | unsigned int len; | ||
1325 | char *c; | ||
1326 | int status; | 1612 | int status; |
1327 | 1613 | ||
1328 | if (nfs_parse_mount_options((char *)options, args) == 0) | 1614 | if (nfs_parse_mount_options((char *)options, args) == 0) |
@@ -1332,21 +1618,22 @@ static int nfs_validate_mount_data(void *options, | |||
1332 | &args->nfs_server.address)) | 1618 | &args->nfs_server.address)) |
1333 | goto out_no_address; | 1619 | goto out_no_address; |
1334 | 1620 | ||
1335 | c = strchr(dev_name, ':'); | 1621 | nfs_set_port((struct sockaddr *)&args->nfs_server.address, |
1336 | if (c == NULL) | 1622 | args->nfs_server.port); |
1337 | return -EINVAL; | ||
1338 | len = c - dev_name; | ||
1339 | /* N.B. caller will free nfs_server.hostname in all cases */ | ||
1340 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); | ||
1341 | if (!args->nfs_server.hostname) | ||
1342 | goto out_nomem; | ||
1343 | 1623 | ||
1344 | c++; | 1624 | nfs_set_mount_transport_protocol(args); |
1345 | if (strlen(c) > NFS_MAXPATHLEN) | 1625 | |
1346 | return -ENAMETOOLONG; | 1626 | status = nfs_parse_devname(dev_name, |
1347 | args->nfs_server.export_path = c; | 1627 | &args->nfs_server.hostname, |
1628 | PAGE_SIZE, | ||
1629 | &args->nfs_server.export_path, | ||
1630 | NFS_MAXPATHLEN); | ||
1631 | if (!status) | ||
1632 | status = nfs_try_mount(args, mntfh); | ||
1633 | |||
1634 | kfree(args->nfs_server.export_path); | ||
1635 | args->nfs_server.export_path = NULL; | ||
1348 | 1636 | ||
1349 | status = nfs_try_mount(args, mntfh); | ||
1350 | if (status) | 1637 | if (status) |
1351 | return status; | 1638 | return status; |
1352 | 1639 | ||
@@ -1354,9 +1641,6 @@ static int nfs_validate_mount_data(void *options, | |||
1354 | } | 1641 | } |
1355 | } | 1642 | } |
1356 | 1643 | ||
1357 | if (!(args->flags & NFS_MOUNT_SECFLAVOUR)) | ||
1358 | args->auth_flavors[0] = RPC_AUTH_UNIX; | ||
1359 | |||
1360 | #ifndef CONFIG_NFS_V3 | 1644 | #ifndef CONFIG_NFS_V3 |
1361 | if (args->flags & NFS_MOUNT_VER3) | 1645 | if (args->flags & NFS_MOUNT_VER3) |
1362 | goto out_v3_not_compiled; | 1646 | goto out_v3_not_compiled; |
@@ -1396,6 +1680,80 @@ out_invalid_fh: | |||
1396 | return -EINVAL; | 1680 | return -EINVAL; |
1397 | } | 1681 | } |
1398 | 1682 | ||
1683 | static int | ||
1684 | nfs_compare_remount_data(struct nfs_server *nfss, | ||
1685 | struct nfs_parsed_mount_data *data) | ||
1686 | { | ||
1687 | if (data->flags != nfss->flags || | ||
1688 | data->rsize != nfss->rsize || | ||
1689 | data->wsize != nfss->wsize || | ||
1690 | data->retrans != nfss->client->cl_timeout->to_retries || | ||
1691 | data->auth_flavors[0] != nfss->client->cl_auth->au_flavor || | ||
1692 | data->acregmin != nfss->acregmin / HZ || | ||
1693 | data->acregmax != nfss->acregmax / HZ || | ||
1694 | data->acdirmin != nfss->acdirmin / HZ || | ||
1695 | data->acdirmax != nfss->acdirmax / HZ || | ||
1696 | data->timeo != (10U * nfss->client->cl_timeout->to_initval / HZ) || | ||
1697 | data->nfs_server.addrlen != nfss->nfs_client->cl_addrlen || | ||
1698 | memcmp(&data->nfs_server.address, &nfss->nfs_client->cl_addr, | ||
1699 | data->nfs_server.addrlen) != 0) | ||
1700 | return -EINVAL; | ||
1701 | |||
1702 | return 0; | ||
1703 | } | ||
1704 | |||
1705 | static int | ||
1706 | nfs_remount(struct super_block *sb, int *flags, char *raw_data) | ||
1707 | { | ||
1708 | int error; | ||
1709 | struct nfs_server *nfss = sb->s_fs_info; | ||
1710 | struct nfs_parsed_mount_data *data; | ||
1711 | struct nfs_mount_data *options = (struct nfs_mount_data *)raw_data; | ||
1712 | struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data; | ||
1713 | u32 nfsvers = nfss->nfs_client->rpc_ops->version; | ||
1714 | |||
1715 | /* | ||
1716 | * Userspace mount programs that send binary options generally send | ||
1717 | * them populated with default values. We have no way to know which | ||
1718 | * ones were explicitly specified. Fall back to legacy behavior and | ||
1719 | * just return success. | ||
1720 | */ | ||
1721 | if ((nfsvers == 4 && options4->version == 1) || | ||
1722 | (nfsvers <= 3 && options->version >= 1 && | ||
1723 | options->version <= 6)) | ||
1724 | return 0; | ||
1725 | |||
1726 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
1727 | if (data == NULL) | ||
1728 | return -ENOMEM; | ||
1729 | |||
1730 | /* fill out struct with values from existing mount */ | ||
1731 | data->flags = nfss->flags; | ||
1732 | data->rsize = nfss->rsize; | ||
1733 | data->wsize = nfss->wsize; | ||
1734 | data->retrans = nfss->client->cl_timeout->to_retries; | ||
1735 | data->auth_flavors[0] = nfss->client->cl_auth->au_flavor; | ||
1736 | data->acregmin = nfss->acregmin / HZ; | ||
1737 | data->acregmax = nfss->acregmax / HZ; | ||
1738 | data->acdirmin = nfss->acdirmin / HZ; | ||
1739 | data->acdirmax = nfss->acdirmax / HZ; | ||
1740 | data->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ; | ||
1741 | data->nfs_server.addrlen = nfss->nfs_client->cl_addrlen; | ||
1742 | memcpy(&data->nfs_server.address, &nfss->nfs_client->cl_addr, | ||
1743 | data->nfs_server.addrlen); | ||
1744 | |||
1745 | /* overwrite those values with any that were specified */ | ||
1746 | error = nfs_parse_mount_options((char *)options, data); | ||
1747 | if (error < 0) | ||
1748 | goto out; | ||
1749 | |||
1750 | /* compare new mount options with old ones */ | ||
1751 | error = nfs_compare_remount_data(nfss, data); | ||
1752 | out: | ||
1753 | kfree(data); | ||
1754 | return error; | ||
1755 | } | ||
1756 | |||
1399 | /* | 1757 | /* |
1400 | * Initialise the common bits of the superblock | 1758 | * Initialise the common bits of the superblock |
1401 | */ | 1759 | */ |
@@ -1811,14 +2169,13 @@ static int nfs4_validate_mount_data(void *options, | |||
1811 | 2169 | ||
1812 | args->rsize = NFS_MAX_FILE_IO_SIZE; | 2170 | args->rsize = NFS_MAX_FILE_IO_SIZE; |
1813 | args->wsize = NFS_MAX_FILE_IO_SIZE; | 2171 | args->wsize = NFS_MAX_FILE_IO_SIZE; |
1814 | args->timeo = 600; | 2172 | args->acregmin = NFS_DEF_ACREGMIN; |
1815 | args->retrans = 2; | 2173 | args->acregmax = NFS_DEF_ACREGMAX; |
1816 | args->acregmin = 3; | 2174 | args->acdirmin = NFS_DEF_ACDIRMIN; |
1817 | args->acregmax = 60; | 2175 | args->acdirmax = NFS_DEF_ACDIRMAX; |
1818 | args->acdirmin = 30; | ||
1819 | args->acdirmax = 60; | ||
1820 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | 2176 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ |
1821 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 2177 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
2178 | args->auth_flavor_len = 0; | ||
1822 | 2179 | ||
1823 | switch (data->version) { | 2180 | switch (data->version) { |
1824 | case 1: | 2181 | case 1: |
@@ -1834,18 +2191,13 @@ static int nfs4_validate_mount_data(void *options, | |||
1834 | &args->nfs_server.address)) | 2191 | &args->nfs_server.address)) |
1835 | goto out_no_address; | 2192 | goto out_no_address; |
1836 | 2193 | ||
1837 | switch (data->auth_flavourlen) { | 2194 | if (data->auth_flavourlen) { |
1838 | case 0: | 2195 | if (data->auth_flavourlen > 1) |
1839 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 2196 | goto out_inval_auth; |
1840 | break; | ||
1841 | case 1: | ||
1842 | if (copy_from_user(&args->auth_flavors[0], | 2197 | if (copy_from_user(&args->auth_flavors[0], |
1843 | data->auth_flavours, | 2198 | data->auth_flavours, |
1844 | sizeof(args->auth_flavors[0]))) | 2199 | sizeof(args->auth_flavors[0]))) |
1845 | return -EFAULT; | 2200 | return -EFAULT; |
1846 | break; | ||
1847 | default: | ||
1848 | goto out_inval_auth; | ||
1849 | } | 2201 | } |
1850 | 2202 | ||
1851 | c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN); | 2203 | c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN); |
@@ -1879,10 +2231,11 @@ static int nfs4_validate_mount_data(void *options, | |||
1879 | args->acdirmin = data->acdirmin; | 2231 | args->acdirmin = data->acdirmin; |
1880 | args->acdirmax = data->acdirmax; | 2232 | args->acdirmax = data->acdirmax; |
1881 | args->nfs_server.protocol = data->proto; | 2233 | args->nfs_server.protocol = data->proto; |
2234 | nfs_validate_transport_protocol(args); | ||
1882 | 2235 | ||
1883 | break; | 2236 | break; |
1884 | default: { | 2237 | default: { |
1885 | unsigned int len; | 2238 | int status; |
1886 | 2239 | ||
1887 | if (nfs_parse_mount_options((char *)options, args) == 0) | 2240 | if (nfs_parse_mount_options((char *)options, args) == 0) |
1888 | return -EINVAL; | 2241 | return -EINVAL; |
@@ -1891,44 +2244,25 @@ static int nfs4_validate_mount_data(void *options, | |||
1891 | &args->nfs_server.address)) | 2244 | &args->nfs_server.address)) |
1892 | return -EINVAL; | 2245 | return -EINVAL; |
1893 | 2246 | ||
1894 | switch (args->auth_flavor_len) { | 2247 | nfs_set_port((struct sockaddr *)&args->nfs_server.address, |
1895 | case 0: | 2248 | args->nfs_server.port); |
1896 | args->auth_flavors[0] = RPC_AUTH_UNIX; | ||
1897 | break; | ||
1898 | case 1: | ||
1899 | break; | ||
1900 | default: | ||
1901 | goto out_inval_auth; | ||
1902 | } | ||
1903 | 2249 | ||
1904 | /* | 2250 | nfs_validate_transport_protocol(args); |
1905 | * Split "dev_name" into "hostname:mntpath". | ||
1906 | */ | ||
1907 | c = strchr(dev_name, ':'); | ||
1908 | if (c == NULL) | ||
1909 | return -EINVAL; | ||
1910 | /* while calculating len, pretend ':' is '\0' */ | ||
1911 | len = c - dev_name; | ||
1912 | if (len > NFS4_MAXNAMLEN) | ||
1913 | return -ENAMETOOLONG; | ||
1914 | /* N.B. caller will free nfs_server.hostname in all cases */ | ||
1915 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); | ||
1916 | if (!args->nfs_server.hostname) | ||
1917 | goto out_nomem; | ||
1918 | |||
1919 | c++; /* step over the ':' */ | ||
1920 | len = strlen(c); | ||
1921 | if (len > NFS4_MAXPATHLEN) | ||
1922 | return -ENAMETOOLONG; | ||
1923 | args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL); | ||
1924 | if (!args->nfs_server.export_path) | ||
1925 | goto out_nomem; | ||
1926 | 2251 | ||
1927 | dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path); | 2252 | if (args->auth_flavor_len > 1) |
2253 | goto out_inval_auth; | ||
1928 | 2254 | ||
1929 | if (args->client_address == NULL) | 2255 | if (args->client_address == NULL) |
1930 | goto out_no_client_address; | 2256 | goto out_no_client_address; |
1931 | 2257 | ||
2258 | status = nfs_parse_devname(dev_name, | ||
2259 | &args->nfs_server.hostname, | ||
2260 | NFS4_MAXNAMLEN, | ||
2261 | &args->nfs_server.export_path, | ||
2262 | NFS4_MAXPATHLEN); | ||
2263 | if (status < 0) | ||
2264 | return status; | ||
2265 | |||
1932 | break; | 2266 | break; |
1933 | } | 2267 | } |
1934 | } | 2268 | } |
@@ -1944,10 +2278,6 @@ out_inval_auth: | |||
1944 | data->auth_flavourlen); | 2278 | data->auth_flavourlen); |
1945 | return -EINVAL; | 2279 | return -EINVAL; |
1946 | 2280 | ||
1947 | out_nomem: | ||
1948 | dfprintk(MOUNT, "NFS4: not enough memory to handle mount options\n"); | ||
1949 | return -ENOMEM; | ||
1950 | |||
1951 | out_no_address: | 2281 | out_no_address: |
1952 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); | 2282 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); |
1953 | return -EINVAL; | 2283 | return -EINVAL; |