diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-07-15 18:34:16 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-07-15 18:34:16 -0400 |
commit | e89e896d31b11a51a54ddcd3f72a76bd286dd86c (patch) | |
tree | 105a9a93a4021caeeba76e479778ad2dd2b87b57 /fs/nfs/super.c | |
parent | 3a628b0fd42f7eaf9d052447784d48ceae9ffb8e (diff) | |
parent | d67d1c7bf948341fd8678c8e337ec27f4b46b206 (diff) |
Merge branch 'devel' into next
Conflicts:
fs/nfs/file.c
Fix up the conflict with Jon Corbet's bkl-removal tree
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r-- | fs/nfs/super.c | 878 |
1 files changed, 606 insertions, 272 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 614efeed5437..47cf83e917be 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 | ||
@@ -514,13 +520,13 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
514 | if (nfss->bsize != 0) | 520 | if (nfss->bsize != 0) |
515 | seq_printf(m, ",bsize=%u", nfss->bsize); | 521 | seq_printf(m, ",bsize=%u", nfss->bsize); |
516 | seq_printf(m, ",namlen=%u", nfss->namelen); | 522 | seq_printf(m, ",namlen=%u", nfss->namelen); |
517 | if (nfss->acregmin != 3*HZ || showdefaults) | 523 | if (nfss->acregmin != NFS_DEF_ACREGMIN*HZ || showdefaults) |
518 | seq_printf(m, ",acregmin=%u", nfss->acregmin/HZ); | 524 | seq_printf(m, ",acregmin=%u", nfss->acregmin/HZ); |
519 | if (nfss->acregmax != 60*HZ || showdefaults) | 525 | if (nfss->acregmax != NFS_DEF_ACREGMAX*HZ || showdefaults) |
520 | seq_printf(m, ",acregmax=%u", nfss->acregmax/HZ); | 526 | seq_printf(m, ",acregmax=%u", nfss->acregmax/HZ); |
521 | if (nfss->acdirmin != 30*HZ || showdefaults) | 527 | if (nfss->acdirmin != NFS_DEF_ACDIRMIN*HZ || showdefaults) |
522 | seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ); | 528 | seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ); |
523 | if (nfss->acdirmax != 60*HZ || showdefaults) | 529 | if (nfss->acdirmax != NFS_DEF_ACDIRMAX*HZ || showdefaults) |
524 | seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ); | 530 | seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ); |
525 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { | 531 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { |
526 | if (nfss->flags & nfs_infop->flag) | 532 | if (nfss->flags & nfs_infop->flag) |
@@ -702,49 +708,233 @@ static int nfs_verify_server_address(struct sockaddr *addr) | |||
702 | return 0; | 708 | return 0; |
703 | } | 709 | } |
704 | 710 | ||
711 | static void nfs_parse_ipv4_address(char *string, size_t str_len, | ||
712 | struct sockaddr *sap, size_t *addr_len) | ||
713 | { | ||
714 | struct sockaddr_in *sin = (struct sockaddr_in *)sap; | ||
715 | u8 *addr = (u8 *)&sin->sin_addr.s_addr; | ||
716 | |||
717 | if (str_len <= INET_ADDRSTRLEN) { | ||
718 | dfprintk(MOUNT, "NFS: parsing IPv4 address %*s\n", | ||
719 | (int)str_len, string); | ||
720 | |||
721 | sin->sin_family = AF_INET; | ||
722 | *addr_len = sizeof(*sin); | ||
723 | if (in4_pton(string, str_len, addr, '\0', NULL)) | ||
724 | return; | ||
725 | } | ||
726 | |||
727 | sap->sa_family = AF_UNSPEC; | ||
728 | *addr_len = 0; | ||
729 | } | ||
730 | |||
731 | #define IPV6_SCOPE_DELIMITER '%' | ||
732 | |||
733 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
734 | static void nfs_parse_ipv6_scope_id(const char *string, const size_t str_len, | ||
735 | const char *delim, | ||
736 | struct sockaddr_in6 *sin6) | ||
737 | { | ||
738 | char *p; | ||
739 | size_t len; | ||
740 | |||
741 | if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) | ||
742 | return ; | ||
743 | if (*delim != IPV6_SCOPE_DELIMITER) | ||
744 | return; | ||
745 | |||
746 | len = (string + str_len) - delim - 1; | ||
747 | p = kstrndup(delim + 1, len, GFP_KERNEL); | ||
748 | if (p) { | ||
749 | unsigned long scope_id = 0; | ||
750 | struct net_device *dev; | ||
751 | |||
752 | dev = dev_get_by_name(&init_net, p); | ||
753 | if (dev != NULL) { | ||
754 | scope_id = dev->ifindex; | ||
755 | dev_put(dev); | ||
756 | } else { | ||
757 | /* scope_id is set to zero on error */ | ||
758 | strict_strtoul(p, 10, &scope_id); | ||
759 | } | ||
760 | |||
761 | kfree(p); | ||
762 | sin6->sin6_scope_id = scope_id; | ||
763 | dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id); | ||
764 | } | ||
765 | } | ||
766 | |||
767 | static void nfs_parse_ipv6_address(char *string, size_t str_len, | ||
768 | struct sockaddr *sap, size_t *addr_len) | ||
769 | { | ||
770 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | ||
771 | u8 *addr = (u8 *)&sin6->sin6_addr.in6_u; | ||
772 | const char *delim; | ||
773 | |||
774 | if (str_len <= INET6_ADDRSTRLEN) { | ||
775 | dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n", | ||
776 | (int)str_len, string); | ||
777 | |||
778 | sin6->sin6_family = AF_INET6; | ||
779 | *addr_len = sizeof(*sin6); | ||
780 | if (in6_pton(string, str_len, addr, IPV6_SCOPE_DELIMITER, &delim)) { | ||
781 | nfs_parse_ipv6_scope_id(string, str_len, delim, sin6); | ||
782 | return; | ||
783 | } | ||
784 | } | ||
785 | |||
786 | sap->sa_family = AF_UNSPEC; | ||
787 | *addr_len = 0; | ||
788 | } | ||
789 | #else | ||
790 | static void nfs_parse_ipv6_address(char *string, size_t str_len, | ||
791 | struct sockaddr *sap, size_t *addr_len) | ||
792 | { | ||
793 | sap->sa_family = AF_UNSPEC; | ||
794 | *addr_len = 0; | ||
795 | } | ||
796 | #endif | ||
797 | |||
705 | /* | 798 | /* |
706 | * Parse string addresses passed in via a mount option, | 799 | * Construct a sockaddr based on the contents of a string that contains |
707 | * and construct a sockaddr based on the result. | 800 | * an IP address in presentation format. |
708 | * | 801 | * |
709 | * If address parsing fails, set the sockaddr's address | 802 | * If there is a problem constructing the new sockaddr, set the address |
710 | * family to AF_UNSPEC to force nfs_verify_server_address() | 803 | * family to AF_UNSPEC. |
711 | * to punt the mount. | ||
712 | */ | 804 | */ |
713 | static void nfs_parse_server_address(char *value, | 805 | static void nfs_parse_ip_address(char *string, size_t str_len, |
714 | struct sockaddr *sap, | 806 | struct sockaddr *sap, size_t *addr_len) |
715 | size_t *len) | ||
716 | { | 807 | { |
717 | if (strchr(value, ':')) { | 808 | unsigned int i, colons; |
718 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
719 | u8 *addr = (u8 *)&ap->sin6_addr.in6_u; | ||
720 | 809 | ||
721 | ap->sin6_family = AF_INET6; | 810 | colons = 0; |
722 | *len = sizeof(*ap); | 811 | for (i = 0; i < str_len; i++) |
723 | if (in6_pton(value, -1, addr, '\0', NULL)) | 812 | if (string[i] == ':') |
724 | return; | 813 | colons++; |
725 | } else { | ||
726 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
727 | u8 *addr = (u8 *)&ap->sin_addr.s_addr; | ||
728 | 814 | ||
729 | ap->sin_family = AF_INET; | 815 | if (colons >= 2) |
730 | *len = sizeof(*ap); | 816 | nfs_parse_ipv6_address(string, str_len, sap, addr_len); |
731 | if (in4_pton(value, -1, addr, '\0', NULL)) | 817 | else |
818 | nfs_parse_ipv4_address(string, str_len, sap, addr_len); | ||
819 | } | ||
820 | |||
821 | /* | ||
822 | * Sanity check the NFS transport protocol. | ||
823 | * | ||
824 | */ | ||
825 | static void nfs_validate_transport_protocol(struct nfs_parsed_mount_data *mnt) | ||
826 | { | ||
827 | switch (mnt->nfs_server.protocol) { | ||
828 | case XPRT_TRANSPORT_UDP: | ||
829 | case XPRT_TRANSPORT_TCP: | ||
830 | case XPRT_TRANSPORT_RDMA: | ||
831 | break; | ||
832 | default: | ||
833 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; | ||
834 | } | ||
835 | } | ||
836 | |||
837 | /* | ||
838 | * For text based NFSv2/v3 mounts, the mount protocol transport default | ||
839 | * settings should depend upon the specified NFS transport. | ||
840 | */ | ||
841 | static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt) | ||
842 | { | ||
843 | nfs_validate_transport_protocol(mnt); | ||
844 | |||
845 | if (mnt->mount_server.protocol == XPRT_TRANSPORT_UDP || | ||
846 | mnt->mount_server.protocol == XPRT_TRANSPORT_TCP) | ||
732 | return; | 847 | return; |
848 | switch (mnt->nfs_server.protocol) { | ||
849 | case XPRT_TRANSPORT_UDP: | ||
850 | mnt->mount_server.protocol = XPRT_TRANSPORT_UDP; | ||
851 | break; | ||
852 | case XPRT_TRANSPORT_TCP: | ||
853 | case XPRT_TRANSPORT_RDMA: | ||
854 | mnt->mount_server.protocol = XPRT_TRANSPORT_TCP; | ||
733 | } | 855 | } |
856 | } | ||
734 | 857 | ||
735 | sap->sa_family = AF_UNSPEC; | 858 | /* |
736 | *len = 0; | 859 | * Parse the value of the 'sec=' option. |
860 | * | ||
861 | * The flavor_len setting is for v4 mounts. | ||
862 | */ | ||
863 | static int nfs_parse_security_flavors(char *value, | ||
864 | struct nfs_parsed_mount_data *mnt) | ||
865 | { | ||
866 | substring_t args[MAX_OPT_ARGS]; | ||
867 | |||
868 | dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value); | ||
869 | |||
870 | switch (match_token(value, nfs_secflavor_tokens, args)) { | ||
871 | case Opt_sec_none: | ||
872 | mnt->auth_flavor_len = 0; | ||
873 | mnt->auth_flavors[0] = RPC_AUTH_NULL; | ||
874 | break; | ||
875 | case Opt_sec_sys: | ||
876 | mnt->auth_flavor_len = 0; | ||
877 | mnt->auth_flavors[0] = RPC_AUTH_UNIX; | ||
878 | break; | ||
879 | case Opt_sec_krb5: | ||
880 | mnt->auth_flavor_len = 1; | ||
881 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; | ||
882 | break; | ||
883 | case Opt_sec_krb5i: | ||
884 | mnt->auth_flavor_len = 1; | ||
885 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; | ||
886 | break; | ||
887 | case Opt_sec_krb5p: | ||
888 | mnt->auth_flavor_len = 1; | ||
889 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; | ||
890 | break; | ||
891 | case Opt_sec_lkey: | ||
892 | mnt->auth_flavor_len = 1; | ||
893 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; | ||
894 | break; | ||
895 | case Opt_sec_lkeyi: | ||
896 | mnt->auth_flavor_len = 1; | ||
897 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; | ||
898 | break; | ||
899 | case Opt_sec_lkeyp: | ||
900 | mnt->auth_flavor_len = 1; | ||
901 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; | ||
902 | break; | ||
903 | case Opt_sec_spkm: | ||
904 | mnt->auth_flavor_len = 1; | ||
905 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; | ||
906 | break; | ||
907 | case Opt_sec_spkmi: | ||
908 | mnt->auth_flavor_len = 1; | ||
909 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; | ||
910 | break; | ||
911 | case Opt_sec_spkmp: | ||
912 | mnt->auth_flavor_len = 1; | ||
913 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; | ||
914 | break; | ||
915 | default: | ||
916 | return 0; | ||
917 | } | ||
918 | |||
919 | return 1; | ||
920 | } | ||
921 | |||
922 | static void nfs_parse_invalid_value(const char *option) | ||
923 | { | ||
924 | dfprintk(MOUNT, "NFS: bad value specified for %s option\n", option); | ||
737 | } | 925 | } |
738 | 926 | ||
739 | /* | 927 | /* |
740 | * Error-check and convert a string of mount options from user space into | 928 | * Error-check and convert a string of mount options from user space into |
741 | * a data structure | 929 | * a data structure. The whole mount string is processed; bad options are |
930 | * skipped as they are encountered. If there were no errors, return 1; | ||
931 | * otherwise return 0 (zero). | ||
742 | */ | 932 | */ |
743 | static int nfs_parse_mount_options(char *raw, | 933 | static int nfs_parse_mount_options(char *raw, |
744 | struct nfs_parsed_mount_data *mnt) | 934 | struct nfs_parsed_mount_data *mnt) |
745 | { | 935 | { |
746 | char *p, *string, *secdata; | 936 | char *p, *string, *secdata; |
747 | int rc; | 937 | int rc, sloppy = 0, errors = 0; |
748 | 938 | ||
749 | if (!raw) { | 939 | if (!raw) { |
750 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); | 940 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); |
@@ -777,15 +967,16 @@ static int nfs_parse_mount_options(char *raw, | |||
777 | 967 | ||
778 | token = match_token(p, nfs_mount_option_tokens, args); | 968 | token = match_token(p, nfs_mount_option_tokens, args); |
779 | switch (token) { | 969 | switch (token) { |
970 | |||
971 | /* | ||
972 | * boolean options: foo/nofoo | ||
973 | */ | ||
780 | case Opt_soft: | 974 | case Opt_soft: |
781 | mnt->flags |= NFS_MOUNT_SOFT; | 975 | mnt->flags |= NFS_MOUNT_SOFT; |
782 | break; | 976 | break; |
783 | case Opt_hard: | 977 | case Opt_hard: |
784 | mnt->flags &= ~NFS_MOUNT_SOFT; | 978 | mnt->flags &= ~NFS_MOUNT_SOFT; |
785 | break; | 979 | break; |
786 | case Opt_intr: | ||
787 | case Opt_nointr: | ||
788 | break; | ||
789 | case Opt_posix: | 980 | case Opt_posix: |
790 | mnt->flags |= NFS_MOUNT_POSIX; | 981 | mnt->flags |= NFS_MOUNT_POSIX; |
791 | break; | 982 | break; |
@@ -819,20 +1010,14 @@ static int nfs_parse_mount_options(char *raw, | |||
819 | case Opt_udp: | 1010 | case Opt_udp: |
820 | mnt->flags &= ~NFS_MOUNT_TCP; | 1011 | mnt->flags &= ~NFS_MOUNT_TCP; |
821 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1012 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
822 | mnt->timeo = 7; | ||
823 | mnt->retrans = 5; | ||
824 | break; | 1013 | break; |
825 | case Opt_tcp: | 1014 | case Opt_tcp: |
826 | mnt->flags |= NFS_MOUNT_TCP; | 1015 | mnt->flags |= NFS_MOUNT_TCP; |
827 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1016 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
828 | mnt->timeo = 600; | ||
829 | mnt->retrans = 2; | ||
830 | break; | 1017 | break; |
831 | case Opt_rdma: | 1018 | case Opt_rdma: |
832 | mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */ | 1019 | mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */ |
833 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; | 1020 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; |
834 | mnt->timeo = 600; | ||
835 | mnt->retrans = 2; | ||
836 | break; | 1021 | break; |
837 | case Opt_acl: | 1022 | case Opt_acl: |
838 | mnt->flags &= ~NFS_MOUNT_NOACL; | 1023 | mnt->flags &= ~NFS_MOUNT_NOACL; |
@@ -853,165 +1038,144 @@ static int nfs_parse_mount_options(char *raw, | |||
853 | mnt->flags |= NFS_MOUNT_UNSHARED; | 1038 | mnt->flags |= NFS_MOUNT_UNSHARED; |
854 | break; | 1039 | break; |
855 | 1040 | ||
1041 | /* | ||
1042 | * options that take numeric values | ||
1043 | */ | ||
856 | case Opt_port: | 1044 | case Opt_port: |
857 | if (match_int(args, &option)) | 1045 | if (match_int(args, &option) || |
858 | return 0; | 1046 | option < 0 || option > USHORT_MAX) { |
859 | if (option < 0 || option > 65535) | 1047 | errors++; |
860 | return 0; | 1048 | nfs_parse_invalid_value("port"); |
861 | mnt->nfs_server.port = option; | 1049 | } else |
1050 | mnt->nfs_server.port = option; | ||
862 | break; | 1051 | break; |
863 | case Opt_rsize: | 1052 | case Opt_rsize: |
864 | if (match_int(args, &mnt->rsize)) | 1053 | if (match_int(args, &option) || option < 0) { |
865 | return 0; | 1054 | errors++; |
1055 | nfs_parse_invalid_value("rsize"); | ||
1056 | } else | ||
1057 | mnt->rsize = option; | ||
866 | break; | 1058 | break; |
867 | case Opt_wsize: | 1059 | case Opt_wsize: |
868 | if (match_int(args, &mnt->wsize)) | 1060 | if (match_int(args, &option) || option < 0) { |
869 | return 0; | 1061 | errors++; |
1062 | nfs_parse_invalid_value("wsize"); | ||
1063 | } else | ||
1064 | mnt->wsize = option; | ||
870 | break; | 1065 | break; |
871 | case Opt_bsize: | 1066 | case Opt_bsize: |
872 | if (match_int(args, &option)) | 1067 | if (match_int(args, &option) || option < 0) { |
873 | return 0; | 1068 | errors++; |
874 | if (option < 0) | 1069 | nfs_parse_invalid_value("bsize"); |
875 | return 0; | 1070 | } else |
876 | mnt->bsize = option; | 1071 | mnt->bsize = option; |
877 | break; | 1072 | break; |
878 | case Opt_timeo: | 1073 | case Opt_timeo: |
879 | if (match_int(args, &mnt->timeo)) | 1074 | if (match_int(args, &option) || option <= 0) { |
880 | return 0; | 1075 | errors++; |
1076 | nfs_parse_invalid_value("timeo"); | ||
1077 | } else | ||
1078 | mnt->timeo = option; | ||
881 | break; | 1079 | break; |
882 | case Opt_retrans: | 1080 | case Opt_retrans: |
883 | if (match_int(args, &mnt->retrans)) | 1081 | if (match_int(args, &option) || option <= 0) { |
884 | return 0; | 1082 | errors++; |
1083 | nfs_parse_invalid_value("retrans"); | ||
1084 | } else | ||
1085 | mnt->retrans = option; | ||
885 | break; | 1086 | break; |
886 | case Opt_acregmin: | 1087 | case Opt_acregmin: |
887 | if (match_int(args, &mnt->acregmin)) | 1088 | if (match_int(args, &option) || option < 0) { |
888 | return 0; | 1089 | errors++; |
1090 | nfs_parse_invalid_value("acregmin"); | ||
1091 | } else | ||
1092 | mnt->acregmin = option; | ||
889 | break; | 1093 | break; |
890 | case Opt_acregmax: | 1094 | case Opt_acregmax: |
891 | if (match_int(args, &mnt->acregmax)) | 1095 | if (match_int(args, &option) || option < 0) { |
892 | return 0; | 1096 | errors++; |
1097 | nfs_parse_invalid_value("acregmax"); | ||
1098 | } else | ||
1099 | mnt->acregmax = option; | ||
893 | break; | 1100 | break; |
894 | case Opt_acdirmin: | 1101 | case Opt_acdirmin: |
895 | if (match_int(args, &mnt->acdirmin)) | 1102 | if (match_int(args, &option) || option < 0) { |
896 | return 0; | 1103 | errors++; |
1104 | nfs_parse_invalid_value("acdirmin"); | ||
1105 | } else | ||
1106 | mnt->acdirmin = option; | ||
897 | break; | 1107 | break; |
898 | case Opt_acdirmax: | 1108 | case Opt_acdirmax: |
899 | if (match_int(args, &mnt->acdirmax)) | 1109 | if (match_int(args, &option) || option < 0) { |
900 | return 0; | 1110 | errors++; |
1111 | nfs_parse_invalid_value("acdirmax"); | ||
1112 | } else | ||
1113 | mnt->acdirmax = option; | ||
901 | break; | 1114 | break; |
902 | case Opt_actimeo: | 1115 | case Opt_actimeo: |
903 | if (match_int(args, &option)) | 1116 | if (match_int(args, &option) || option < 0) { |
904 | return 0; | 1117 | errors++; |
905 | if (option < 0) | 1118 | nfs_parse_invalid_value("actimeo"); |
906 | return 0; | 1119 | } else |
907 | mnt->acregmin = | 1120 | mnt->acregmin = mnt->acregmax = |
908 | mnt->acregmax = | 1121 | mnt->acdirmin = mnt->acdirmax = option; |
909 | mnt->acdirmin = | ||
910 | mnt->acdirmax = option; | ||
911 | break; | 1122 | break; |
912 | case Opt_namelen: | 1123 | case Opt_namelen: |
913 | if (match_int(args, &mnt->namlen)) | 1124 | if (match_int(args, &option) || option < 0) { |
914 | return 0; | 1125 | errors++; |
1126 | nfs_parse_invalid_value("namlen"); | ||
1127 | } else | ||
1128 | mnt->namlen = option; | ||
915 | break; | 1129 | break; |
916 | case Opt_mountport: | 1130 | case Opt_mountport: |
917 | if (match_int(args, &option)) | 1131 | if (match_int(args, &option) || |
918 | return 0; | 1132 | option < 0 || option > USHORT_MAX) { |
919 | if (option < 0 || option > 65535) | 1133 | errors++; |
920 | return 0; | 1134 | nfs_parse_invalid_value("mountport"); |
921 | mnt->mount_server.port = option; | 1135 | } else |
1136 | mnt->mount_server.port = option; | ||
922 | break; | 1137 | break; |
923 | case Opt_mountvers: | 1138 | case Opt_mountvers: |
924 | if (match_int(args, &option)) | 1139 | if (match_int(args, &option) || |
925 | return 0; | 1140 | option < NFS_MNT_VERSION || |
926 | if (option < 0) | 1141 | option > NFS_MNT3_VERSION) { |
927 | return 0; | 1142 | errors++; |
928 | mnt->mount_server.version = option; | 1143 | nfs_parse_invalid_value("mountvers"); |
1144 | } else | ||
1145 | mnt->mount_server.version = option; | ||
929 | break; | 1146 | break; |
930 | case Opt_nfsvers: | 1147 | case Opt_nfsvers: |
931 | if (match_int(args, &option)) | 1148 | if (match_int(args, &option)) { |
932 | return 0; | 1149 | errors++; |
1150 | nfs_parse_invalid_value("nfsvers"); | ||
1151 | break; | ||
1152 | } | ||
933 | switch (option) { | 1153 | switch (option) { |
934 | case 2: | 1154 | case NFS2_VERSION: |
935 | mnt->flags &= ~NFS_MOUNT_VER3; | 1155 | mnt->flags &= ~NFS_MOUNT_VER3; |
936 | break; | 1156 | break; |
937 | case 3: | 1157 | case NFS3_VERSION: |
938 | mnt->flags |= NFS_MOUNT_VER3; | 1158 | mnt->flags |= NFS_MOUNT_VER3; |
939 | break; | 1159 | break; |
940 | default: | 1160 | default: |
941 | goto out_unrec_vers; | 1161 | errors++; |
1162 | nfs_parse_invalid_value("nfsvers"); | ||
942 | } | 1163 | } |
943 | break; | 1164 | break; |
944 | 1165 | ||
1166 | /* | ||
1167 | * options that take text values | ||
1168 | */ | ||
945 | case Opt_sec: | 1169 | case Opt_sec: |
946 | string = match_strdup(args); | 1170 | string = match_strdup(args); |
947 | if (string == NULL) | 1171 | if (string == NULL) |
948 | goto out_nomem; | 1172 | goto out_nomem; |
949 | token = match_token(string, nfs_secflavor_tokens, args); | 1173 | rc = nfs_parse_security_flavors(string, mnt); |
950 | kfree(string); | 1174 | kfree(string); |
951 | 1175 | if (!rc) { | |
952 | /* | 1176 | errors++; |
953 | * The flags setting is for v2/v3. The flavor_len | 1177 | dfprintk(MOUNT, "NFS: unrecognized " |
954 | * setting is for v4. v2/v3 also need to know the | 1178 | "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 | } | 1179 | } |
1016 | break; | 1180 | break; |
1017 | case Opt_proto: | 1181 | case Opt_proto: |
@@ -1026,24 +1190,20 @@ static int nfs_parse_mount_options(char *raw, | |||
1026 | case Opt_xprt_udp: | 1190 | case Opt_xprt_udp: |
1027 | mnt->flags &= ~NFS_MOUNT_TCP; | 1191 | mnt->flags &= ~NFS_MOUNT_TCP; |
1028 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1192 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
1029 | mnt->timeo = 7; | ||
1030 | mnt->retrans = 5; | ||
1031 | break; | 1193 | break; |
1032 | case Opt_xprt_tcp: | 1194 | case Opt_xprt_tcp: |
1033 | mnt->flags |= NFS_MOUNT_TCP; | 1195 | mnt->flags |= NFS_MOUNT_TCP; |
1034 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1196 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1035 | mnt->timeo = 600; | ||
1036 | mnt->retrans = 2; | ||
1037 | break; | 1197 | break; |
1038 | case Opt_xprt_rdma: | 1198 | case Opt_xprt_rdma: |
1039 | /* vector side protocols to TCP */ | 1199 | /* vector side protocols to TCP */ |
1040 | mnt->flags |= NFS_MOUNT_TCP; | 1200 | mnt->flags |= NFS_MOUNT_TCP; |
1041 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; | 1201 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; |
1042 | mnt->timeo = 600; | ||
1043 | mnt->retrans = 2; | ||
1044 | break; | 1202 | break; |
1045 | default: | 1203 | default: |
1046 | goto out_unrec_xprt; | 1204 | errors++; |
1205 | dfprintk(MOUNT, "NFS: unrecognized " | ||
1206 | "transport protocol\n"); | ||
1047 | } | 1207 | } |
1048 | break; | 1208 | break; |
1049 | case Opt_mountproto: | 1209 | case Opt_mountproto: |
@@ -1063,16 +1223,19 @@ static int nfs_parse_mount_options(char *raw, | |||
1063 | break; | 1223 | break; |
1064 | case Opt_xprt_rdma: /* not used for side protocols */ | 1224 | case Opt_xprt_rdma: /* not used for side protocols */ |
1065 | default: | 1225 | default: |
1066 | goto out_unrec_xprt; | 1226 | errors++; |
1227 | dfprintk(MOUNT, "NFS: unrecognized " | ||
1228 | "transport protocol\n"); | ||
1067 | } | 1229 | } |
1068 | break; | 1230 | break; |
1069 | case Opt_addr: | 1231 | case Opt_addr: |
1070 | string = match_strdup(args); | 1232 | string = match_strdup(args); |
1071 | if (string == NULL) | 1233 | if (string == NULL) |
1072 | goto out_nomem; | 1234 | goto out_nomem; |
1073 | nfs_parse_server_address(string, (struct sockaddr *) | 1235 | nfs_parse_ip_address(string, strlen(string), |
1074 | &mnt->nfs_server.address, | 1236 | (struct sockaddr *) |
1075 | &mnt->nfs_server.addrlen); | 1237 | &mnt->nfs_server.address, |
1238 | &mnt->nfs_server.addrlen); | ||
1076 | kfree(string); | 1239 | kfree(string); |
1077 | break; | 1240 | break; |
1078 | case Opt_clientaddr: | 1241 | case Opt_clientaddr: |
@@ -1093,24 +1256,33 @@ static int nfs_parse_mount_options(char *raw, | |||
1093 | string = match_strdup(args); | 1256 | string = match_strdup(args); |
1094 | if (string == NULL) | 1257 | if (string == NULL) |
1095 | goto out_nomem; | 1258 | goto out_nomem; |
1096 | nfs_parse_server_address(string, (struct sockaddr *) | 1259 | nfs_parse_ip_address(string, strlen(string), |
1097 | &mnt->mount_server.address, | 1260 | (struct sockaddr *) |
1098 | &mnt->mount_server.addrlen); | 1261 | &mnt->mount_server.address, |
1262 | &mnt->mount_server.addrlen); | ||
1099 | kfree(string); | 1263 | kfree(string); |
1100 | break; | 1264 | break; |
1101 | 1265 | ||
1266 | /* | ||
1267 | * Special options | ||
1268 | */ | ||
1269 | case Opt_sloppy: | ||
1270 | sloppy = 1; | ||
1271 | dfprintk(MOUNT, "NFS: relaxing parsing rules\n"); | ||
1272 | break; | ||
1102 | case Opt_userspace: | 1273 | case Opt_userspace: |
1103 | case Opt_deprecated: | 1274 | case Opt_deprecated: |
1275 | dfprintk(MOUNT, "NFS: ignoring mount option " | ||
1276 | "'%s'\n", p); | ||
1104 | break; | 1277 | break; |
1105 | 1278 | ||
1106 | default: | 1279 | default: |
1107 | goto out_unknown; | 1280 | errors++; |
1281 | dfprintk(MOUNT, "NFS: unrecognized mount option " | ||
1282 | "'%s'\n", p); | ||
1108 | } | 1283 | } |
1109 | } | 1284 | } |
1110 | 1285 | ||
1111 | nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, | ||
1112 | mnt->nfs_server.port); | ||
1113 | |||
1114 | return 1; | 1286 | return 1; |
1115 | 1287 | ||
1116 | out_nomem: | 1288 | out_nomem: |
@@ -1120,21 +1292,6 @@ out_security_failure: | |||
1120 | free_secdata(secdata); | 1292 | free_secdata(secdata); |
1121 | printk(KERN_INFO "NFS: security options invalid: %d\n", rc); | 1293 | printk(KERN_INFO "NFS: security options invalid: %d\n", rc); |
1122 | return 0; | 1294 | 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 | } | 1295 | } |
1139 | 1296 | ||
1140 | /* | 1297 | /* |
@@ -1188,11 +1345,146 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1188 | if (status == 0) | 1345 | if (status == 0) |
1189 | return 0; | 1346 | return 0; |
1190 | 1347 | ||
1191 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d", | 1348 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", |
1192 | hostname, status); | 1349 | hostname, status); |
1193 | return status; | 1350 | return status; |
1194 | } | 1351 | } |
1195 | 1352 | ||
1353 | static int nfs_parse_simple_hostname(const char *dev_name, | ||
1354 | char **hostname, size_t maxnamlen, | ||
1355 | char **export_path, size_t maxpathlen) | ||
1356 | { | ||
1357 | size_t len; | ||
1358 | char *colon, *comma; | ||
1359 | |||
1360 | colon = strchr(dev_name, ':'); | ||
1361 | if (colon == NULL) | ||
1362 | goto out_bad_devname; | ||
1363 | |||
1364 | len = colon - dev_name; | ||
1365 | if (len > maxnamlen) | ||
1366 | goto out_hostname; | ||
1367 | |||
1368 | /* N.B. caller will free nfs_server.hostname in all cases */ | ||
1369 | *hostname = kstrndup(dev_name, len, GFP_KERNEL); | ||
1370 | if (!*hostname) | ||
1371 | goto out_nomem; | ||
1372 | |||
1373 | /* kill possible hostname list: not supported */ | ||
1374 | comma = strchr(*hostname, ','); | ||
1375 | if (comma != NULL) { | ||
1376 | if (comma == *hostname) | ||
1377 | goto out_bad_devname; | ||
1378 | *comma = '\0'; | ||
1379 | } | ||
1380 | |||
1381 | colon++; | ||
1382 | len = strlen(colon); | ||
1383 | if (len > maxpathlen) | ||
1384 | goto out_path; | ||
1385 | *export_path = kstrndup(colon, len, GFP_KERNEL); | ||
1386 | if (!*export_path) | ||
1387 | goto out_nomem; | ||
1388 | |||
1389 | dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path); | ||
1390 | return 0; | ||
1391 | |||
1392 | out_bad_devname: | ||
1393 | dfprintk(MOUNT, "NFS: device name not in host:path format\n"); | ||
1394 | return -EINVAL; | ||
1395 | |||
1396 | out_nomem: | ||
1397 | dfprintk(MOUNT, "NFS: not enough memory to parse device name\n"); | ||
1398 | return -ENOMEM; | ||
1399 | |||
1400 | out_hostname: | ||
1401 | dfprintk(MOUNT, "NFS: server hostname too long\n"); | ||
1402 | return -ENAMETOOLONG; | ||
1403 | |||
1404 | out_path: | ||
1405 | dfprintk(MOUNT, "NFS: export pathname too long\n"); | ||
1406 | return -ENAMETOOLONG; | ||
1407 | } | ||
1408 | |||
1409 | /* | ||
1410 | * Hostname has square brackets around it because it contains one or | ||
1411 | * more colons. We look for the first closing square bracket, and a | ||
1412 | * colon must follow it. | ||
1413 | */ | ||
1414 | static int nfs_parse_protected_hostname(const char *dev_name, | ||
1415 | char **hostname, size_t maxnamlen, | ||
1416 | char **export_path, size_t maxpathlen) | ||
1417 | { | ||
1418 | size_t len; | ||
1419 | char *start, *end; | ||
1420 | |||
1421 | start = (char *)(dev_name + 1); | ||
1422 | |||
1423 | end = strchr(start, ']'); | ||
1424 | if (end == NULL) | ||
1425 | goto out_bad_devname; | ||
1426 | if (*(end + 1) != ':') | ||
1427 | goto out_bad_devname; | ||
1428 | |||
1429 | len = end - start; | ||
1430 | if (len > maxnamlen) | ||
1431 | goto out_hostname; | ||
1432 | |||
1433 | /* N.B. caller will free nfs_server.hostname in all cases */ | ||
1434 | *hostname = kstrndup(start, len, GFP_KERNEL); | ||
1435 | if (*hostname == NULL) | ||
1436 | goto out_nomem; | ||
1437 | |||
1438 | end += 2; | ||
1439 | len = strlen(end); | ||
1440 | if (len > maxpathlen) | ||
1441 | goto out_path; | ||
1442 | *export_path = kstrndup(end, len, GFP_KERNEL); | ||
1443 | if (!*export_path) | ||
1444 | goto out_nomem; | ||
1445 | |||
1446 | return 0; | ||
1447 | |||
1448 | out_bad_devname: | ||
1449 | dfprintk(MOUNT, "NFS: device name not in host:path format\n"); | ||
1450 | return -EINVAL; | ||
1451 | |||
1452 | out_nomem: | ||
1453 | dfprintk(MOUNT, "NFS: not enough memory to parse device name\n"); | ||
1454 | return -ENOMEM; | ||
1455 | |||
1456 | out_hostname: | ||
1457 | dfprintk(MOUNT, "NFS: server hostname too long\n"); | ||
1458 | return -ENAMETOOLONG; | ||
1459 | |||
1460 | out_path: | ||
1461 | dfprintk(MOUNT, "NFS: export pathname too long\n"); | ||
1462 | return -ENAMETOOLONG; | ||
1463 | } | ||
1464 | |||
1465 | /* | ||
1466 | * Split "dev_name" into "hostname:export_path". | ||
1467 | * | ||
1468 | * The leftmost colon demarks the split between the server's hostname | ||
1469 | * and the export path. If the hostname starts with a left square | ||
1470 | * bracket, then it may contain colons. | ||
1471 | * | ||
1472 | * Note: caller frees hostname and export path, even on error. | ||
1473 | */ | ||
1474 | static int nfs_parse_devname(const char *dev_name, | ||
1475 | char **hostname, size_t maxnamlen, | ||
1476 | char **export_path, size_t maxpathlen) | ||
1477 | { | ||
1478 | if (*dev_name == '[') | ||
1479 | return nfs_parse_protected_hostname(dev_name, | ||
1480 | hostname, maxnamlen, | ||
1481 | export_path, maxpathlen); | ||
1482 | |||
1483 | return nfs_parse_simple_hostname(dev_name, | ||
1484 | hostname, maxnamlen, | ||
1485 | export_path, maxpathlen); | ||
1486 | } | ||
1487 | |||
1196 | /* | 1488 | /* |
1197 | * Validate the NFS2/NFS3 mount data | 1489 | * Validate the NFS2/NFS3 mount data |
1198 | * - fills in the mount root filehandle | 1490 | * - fills in the mount root filehandle |
@@ -1222,16 +1514,14 @@ static int nfs_validate_mount_data(void *options, | |||
1222 | args->flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP); | 1514 | args->flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP); |
1223 | args->rsize = NFS_MAX_FILE_IO_SIZE; | 1515 | args->rsize = NFS_MAX_FILE_IO_SIZE; |
1224 | args->wsize = NFS_MAX_FILE_IO_SIZE; | 1516 | args->wsize = NFS_MAX_FILE_IO_SIZE; |
1225 | args->timeo = 600; | 1517 | args->acregmin = NFS_DEF_ACREGMIN; |
1226 | args->retrans = 2; | 1518 | args->acregmax = NFS_DEF_ACREGMAX; |
1227 | args->acregmin = 3; | 1519 | args->acdirmin = NFS_DEF_ACDIRMIN; |
1228 | args->acregmax = 60; | 1520 | args->acdirmax = NFS_DEF_ACDIRMAX; |
1229 | args->acdirmin = 30; | ||
1230 | args->acdirmax = 60; | ||
1231 | args->mount_server.port = 0; /* autobind unless user sets port */ | 1521 | 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 */ | 1522 | args->nfs_server.port = 0; /* autobind unless user sets port */ |
1234 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1523 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1524 | args->auth_flavors[0] = RPC_AUTH_UNIX; | ||
1235 | 1525 | ||
1236 | switch (data->version) { | 1526 | switch (data->version) { |
1237 | case 1: | 1527 | case 1: |
@@ -1289,7 +1579,9 @@ static int nfs_validate_mount_data(void *options, | |||
1289 | args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); | 1579 | args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); |
1290 | args->namlen = data->namlen; | 1580 | args->namlen = data->namlen; |
1291 | args->bsize = data->bsize; | 1581 | args->bsize = data->bsize; |
1292 | args->auth_flavors[0] = data->pseudoflavor; | 1582 | |
1583 | if (data->flags & NFS_MOUNT_SECFLAVOUR) | ||
1584 | args->auth_flavors[0] = data->pseudoflavor; | ||
1293 | if (!args->nfs_server.hostname) | 1585 | if (!args->nfs_server.hostname) |
1294 | goto out_nomem; | 1586 | goto out_nomem; |
1295 | 1587 | ||
@@ -1321,8 +1613,6 @@ static int nfs_validate_mount_data(void *options, | |||
1321 | 1613 | ||
1322 | break; | 1614 | break; |
1323 | default: { | 1615 | default: { |
1324 | unsigned int len; | ||
1325 | char *c; | ||
1326 | int status; | 1616 | int status; |
1327 | 1617 | ||
1328 | if (nfs_parse_mount_options((char *)options, args) == 0) | 1618 | if (nfs_parse_mount_options((char *)options, args) == 0) |
@@ -1332,21 +1622,22 @@ static int nfs_validate_mount_data(void *options, | |||
1332 | &args->nfs_server.address)) | 1622 | &args->nfs_server.address)) |
1333 | goto out_no_address; | 1623 | goto out_no_address; |
1334 | 1624 | ||
1335 | c = strchr(dev_name, ':'); | 1625 | nfs_set_port((struct sockaddr *)&args->nfs_server.address, |
1336 | if (c == NULL) | 1626 | 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 | 1627 | ||
1344 | c++; | 1628 | nfs_set_mount_transport_protocol(args); |
1345 | if (strlen(c) > NFS_MAXPATHLEN) | 1629 | |
1346 | return -ENAMETOOLONG; | 1630 | status = nfs_parse_devname(dev_name, |
1347 | args->nfs_server.export_path = c; | 1631 | &args->nfs_server.hostname, |
1632 | PAGE_SIZE, | ||
1633 | &args->nfs_server.export_path, | ||
1634 | NFS_MAXPATHLEN); | ||
1635 | if (!status) | ||
1636 | status = nfs_try_mount(args, mntfh); | ||
1637 | |||
1638 | kfree(args->nfs_server.export_path); | ||
1639 | args->nfs_server.export_path = NULL; | ||
1348 | 1640 | ||
1349 | status = nfs_try_mount(args, mntfh); | ||
1350 | if (status) | 1641 | if (status) |
1351 | return status; | 1642 | return status; |
1352 | 1643 | ||
@@ -1354,9 +1645,6 @@ static int nfs_validate_mount_data(void *options, | |||
1354 | } | 1645 | } |
1355 | } | 1646 | } |
1356 | 1647 | ||
1357 | if (!(args->flags & NFS_MOUNT_SECFLAVOUR)) | ||
1358 | args->auth_flavors[0] = RPC_AUTH_UNIX; | ||
1359 | |||
1360 | #ifndef CONFIG_NFS_V3 | 1648 | #ifndef CONFIG_NFS_V3 |
1361 | if (args->flags & NFS_MOUNT_VER3) | 1649 | if (args->flags & NFS_MOUNT_VER3) |
1362 | goto out_v3_not_compiled; | 1650 | goto out_v3_not_compiled; |
@@ -1396,6 +1684,80 @@ out_invalid_fh: | |||
1396 | return -EINVAL; | 1684 | return -EINVAL; |
1397 | } | 1685 | } |
1398 | 1686 | ||
1687 | static int | ||
1688 | nfs_compare_remount_data(struct nfs_server *nfss, | ||
1689 | struct nfs_parsed_mount_data *data) | ||
1690 | { | ||
1691 | if (data->flags != nfss->flags || | ||
1692 | data->rsize != nfss->rsize || | ||
1693 | data->wsize != nfss->wsize || | ||
1694 | data->retrans != nfss->client->cl_timeout->to_retries || | ||
1695 | data->auth_flavors[0] != nfss->client->cl_auth->au_flavor || | ||
1696 | data->acregmin != nfss->acregmin / HZ || | ||
1697 | data->acregmax != nfss->acregmax / HZ || | ||
1698 | data->acdirmin != nfss->acdirmin / HZ || | ||
1699 | data->acdirmax != nfss->acdirmax / HZ || | ||
1700 | data->timeo != (10U * nfss->client->cl_timeout->to_initval / HZ) || | ||
1701 | data->nfs_server.addrlen != nfss->nfs_client->cl_addrlen || | ||
1702 | memcmp(&data->nfs_server.address, &nfss->nfs_client->cl_addr, | ||
1703 | data->nfs_server.addrlen) != 0) | ||
1704 | return -EINVAL; | ||
1705 | |||
1706 | return 0; | ||
1707 | } | ||
1708 | |||
1709 | static int | ||
1710 | nfs_remount(struct super_block *sb, int *flags, char *raw_data) | ||
1711 | { | ||
1712 | int error; | ||
1713 | struct nfs_server *nfss = sb->s_fs_info; | ||
1714 | struct nfs_parsed_mount_data *data; | ||
1715 | struct nfs_mount_data *options = (struct nfs_mount_data *)raw_data; | ||
1716 | struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data; | ||
1717 | u32 nfsvers = nfss->nfs_client->rpc_ops->version; | ||
1718 | |||
1719 | /* | ||
1720 | * Userspace mount programs that send binary options generally send | ||
1721 | * them populated with default values. We have no way to know which | ||
1722 | * ones were explicitly specified. Fall back to legacy behavior and | ||
1723 | * just return success. | ||
1724 | */ | ||
1725 | if ((nfsvers == 4 && options4->version == 1) || | ||
1726 | (nfsvers <= 3 && options->version >= 1 && | ||
1727 | options->version <= 6)) | ||
1728 | return 0; | ||
1729 | |||
1730 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
1731 | if (data == NULL) | ||
1732 | return -ENOMEM; | ||
1733 | |||
1734 | /* fill out struct with values from existing mount */ | ||
1735 | data->flags = nfss->flags; | ||
1736 | data->rsize = nfss->rsize; | ||
1737 | data->wsize = nfss->wsize; | ||
1738 | data->retrans = nfss->client->cl_timeout->to_retries; | ||
1739 | data->auth_flavors[0] = nfss->client->cl_auth->au_flavor; | ||
1740 | data->acregmin = nfss->acregmin / HZ; | ||
1741 | data->acregmax = nfss->acregmax / HZ; | ||
1742 | data->acdirmin = nfss->acdirmin / HZ; | ||
1743 | data->acdirmax = nfss->acdirmax / HZ; | ||
1744 | data->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ; | ||
1745 | data->nfs_server.addrlen = nfss->nfs_client->cl_addrlen; | ||
1746 | memcpy(&data->nfs_server.address, &nfss->nfs_client->cl_addr, | ||
1747 | data->nfs_server.addrlen); | ||
1748 | |||
1749 | /* overwrite those values with any that were specified */ | ||
1750 | error = nfs_parse_mount_options((char *)options, data); | ||
1751 | if (error < 0) | ||
1752 | goto out; | ||
1753 | |||
1754 | /* compare new mount options with old ones */ | ||
1755 | error = nfs_compare_remount_data(nfss, data); | ||
1756 | out: | ||
1757 | kfree(data); | ||
1758 | return error; | ||
1759 | } | ||
1760 | |||
1399 | /* | 1761 | /* |
1400 | * Initialise the common bits of the superblock | 1762 | * Initialise the common bits of the superblock |
1401 | */ | 1763 | */ |
@@ -1811,14 +2173,13 @@ static int nfs4_validate_mount_data(void *options, | |||
1811 | 2173 | ||
1812 | args->rsize = NFS_MAX_FILE_IO_SIZE; | 2174 | args->rsize = NFS_MAX_FILE_IO_SIZE; |
1813 | args->wsize = NFS_MAX_FILE_IO_SIZE; | 2175 | args->wsize = NFS_MAX_FILE_IO_SIZE; |
1814 | args->timeo = 600; | 2176 | args->acregmin = NFS_DEF_ACREGMIN; |
1815 | args->retrans = 2; | 2177 | args->acregmax = NFS_DEF_ACREGMAX; |
1816 | args->acregmin = 3; | 2178 | args->acdirmin = NFS_DEF_ACDIRMIN; |
1817 | args->acregmax = 60; | 2179 | 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= */ | 2180 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ |
1821 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 2181 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
2182 | args->auth_flavor_len = 0; | ||
1822 | 2183 | ||
1823 | switch (data->version) { | 2184 | switch (data->version) { |
1824 | case 1: | 2185 | case 1: |
@@ -1834,18 +2195,13 @@ static int nfs4_validate_mount_data(void *options, | |||
1834 | &args->nfs_server.address)) | 2195 | &args->nfs_server.address)) |
1835 | goto out_no_address; | 2196 | goto out_no_address; |
1836 | 2197 | ||
1837 | switch (data->auth_flavourlen) { | 2198 | if (data->auth_flavourlen) { |
1838 | case 0: | 2199 | if (data->auth_flavourlen > 1) |
1839 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 2200 | goto out_inval_auth; |
1840 | break; | ||
1841 | case 1: | ||
1842 | if (copy_from_user(&args->auth_flavors[0], | 2201 | if (copy_from_user(&args->auth_flavors[0], |
1843 | data->auth_flavours, | 2202 | data->auth_flavours, |
1844 | sizeof(args->auth_flavors[0]))) | 2203 | sizeof(args->auth_flavors[0]))) |
1845 | return -EFAULT; | 2204 | return -EFAULT; |
1846 | break; | ||
1847 | default: | ||
1848 | goto out_inval_auth; | ||
1849 | } | 2205 | } |
1850 | 2206 | ||
1851 | c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN); | 2207 | c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN); |
@@ -1879,10 +2235,11 @@ static int nfs4_validate_mount_data(void *options, | |||
1879 | args->acdirmin = data->acdirmin; | 2235 | args->acdirmin = data->acdirmin; |
1880 | args->acdirmax = data->acdirmax; | 2236 | args->acdirmax = data->acdirmax; |
1881 | args->nfs_server.protocol = data->proto; | 2237 | args->nfs_server.protocol = data->proto; |
2238 | nfs_validate_transport_protocol(args); | ||
1882 | 2239 | ||
1883 | break; | 2240 | break; |
1884 | default: { | 2241 | default: { |
1885 | unsigned int len; | 2242 | int status; |
1886 | 2243 | ||
1887 | if (nfs_parse_mount_options((char *)options, args) == 0) | 2244 | if (nfs_parse_mount_options((char *)options, args) == 0) |
1888 | return -EINVAL; | 2245 | return -EINVAL; |
@@ -1891,44 +2248,25 @@ static int nfs4_validate_mount_data(void *options, | |||
1891 | &args->nfs_server.address)) | 2248 | &args->nfs_server.address)) |
1892 | return -EINVAL; | 2249 | return -EINVAL; |
1893 | 2250 | ||
1894 | switch (args->auth_flavor_len) { | 2251 | nfs_set_port((struct sockaddr *)&args->nfs_server.address, |
1895 | case 0: | 2252 | 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 | 2253 | ||
1904 | /* | 2254 | 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 | 2255 | ||
1927 | dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path); | 2256 | if (args->auth_flavor_len > 1) |
2257 | goto out_inval_auth; | ||
1928 | 2258 | ||
1929 | if (args->client_address == NULL) | 2259 | if (args->client_address == NULL) |
1930 | goto out_no_client_address; | 2260 | goto out_no_client_address; |
1931 | 2261 | ||
2262 | status = nfs_parse_devname(dev_name, | ||
2263 | &args->nfs_server.hostname, | ||
2264 | NFS4_MAXNAMLEN, | ||
2265 | &args->nfs_server.export_path, | ||
2266 | NFS4_MAXPATHLEN); | ||
2267 | if (status < 0) | ||
2268 | return status; | ||
2269 | |||
1932 | break; | 2270 | break; |
1933 | } | 2271 | } |
1934 | } | 2272 | } |
@@ -1944,10 +2282,6 @@ out_inval_auth: | |||
1944 | data->auth_flavourlen); | 2282 | data->auth_flavourlen); |
1945 | return -EINVAL; | 2283 | return -EINVAL; |
1946 | 2284 | ||
1947 | out_nomem: | ||
1948 | dfprintk(MOUNT, "NFS4: not enough memory to handle mount options\n"); | ||
1949 | return -ENOMEM; | ||
1950 | |||
1951 | out_no_address: | 2285 | out_no_address: |
1952 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); | 2286 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); |
1953 | return -EINVAL; | 2287 | return -EINVAL; |