diff options
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r-- | fs/nfs/super.c | 521 |
1 files changed, 272 insertions, 249 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 0b4cbdc60abd..29786d3b9326 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -73,7 +73,7 @@ enum { | |||
73 | Opt_cto, Opt_nocto, | 73 | Opt_cto, Opt_nocto, |
74 | Opt_ac, Opt_noac, | 74 | Opt_ac, Opt_noac, |
75 | Opt_lock, Opt_nolock, | 75 | Opt_lock, Opt_nolock, |
76 | Opt_v2, Opt_v3, | 76 | Opt_v2, Opt_v3, Opt_v4, |
77 | Opt_udp, Opt_tcp, Opt_rdma, | 77 | Opt_udp, Opt_tcp, Opt_rdma, |
78 | Opt_acl, Opt_noacl, | 78 | Opt_acl, Opt_noacl, |
79 | Opt_rdirplus, Opt_nordirplus, | 79 | Opt_rdirplus, Opt_nordirplus, |
@@ -127,6 +127,7 @@ static const match_table_t nfs_mount_option_tokens = { | |||
127 | { Opt_nolock, "nolock" }, | 127 | { Opt_nolock, "nolock" }, |
128 | { Opt_v2, "v2" }, | 128 | { Opt_v2, "v2" }, |
129 | { Opt_v3, "v3" }, | 129 | { Opt_v3, "v3" }, |
130 | { Opt_v4, "v4" }, | ||
130 | { Opt_udp, "udp" }, | 131 | { Opt_udp, "udp" }, |
131 | { Opt_tcp, "tcp" }, | 132 | { Opt_tcp, "tcp" }, |
132 | { Opt_rdma, "rdma" }, | 133 | { Opt_rdma, "rdma" }, |
@@ -158,7 +159,7 @@ static const match_table_t nfs_mount_option_tokens = { | |||
158 | { Opt_mountvers, "mountvers=%s" }, | 159 | { Opt_mountvers, "mountvers=%s" }, |
159 | { Opt_nfsvers, "nfsvers=%s" }, | 160 | { Opt_nfsvers, "nfsvers=%s" }, |
160 | { Opt_nfsvers, "vers=%s" }, | 161 | { Opt_nfsvers, "vers=%s" }, |
161 | { Opt_minorversion, "minorversion=%u" }, | 162 | { Opt_minorversion, "minorversion=%s" }, |
162 | 163 | ||
163 | { Opt_sec, "sec=%s" }, | 164 | { Opt_sec, "sec=%s" }, |
164 | { Opt_proto, "proto=%s" }, | 165 | { Opt_proto, "proto=%s" }, |
@@ -272,6 +273,10 @@ static const struct super_operations nfs_sops = { | |||
272 | }; | 273 | }; |
273 | 274 | ||
274 | #ifdef CONFIG_NFS_V4 | 275 | #ifdef CONFIG_NFS_V4 |
276 | static int nfs4_validate_text_mount_data(void *options, | ||
277 | struct nfs_parsed_mount_data *args, const char *dev_name); | ||
278 | static int nfs4_try_mount(int flags, const char *dev_name, | ||
279 | struct nfs_parsed_mount_data *data, struct vfsmount *mnt); | ||
275 | static int nfs4_get_sb(struct file_system_type *fs_type, | 280 | static int nfs4_get_sb(struct file_system_type *fs_type, |
276 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 281 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
277 | static int nfs4_remote_get_sb(struct file_system_type *fs_type, | 282 | static int nfs4_remote_get_sb(struct file_system_type *fs_type, |
@@ -723,6 +728,27 @@ static void nfs_umount_begin(struct super_block *sb) | |||
723 | unlock_kernel(); | 728 | unlock_kernel(); |
724 | } | 729 | } |
725 | 730 | ||
731 | static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(int flags) | ||
732 | { | ||
733 | struct nfs_parsed_mount_data *data; | ||
734 | |||
735 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
736 | if (data) { | ||
737 | data->flags = flags; | ||
738 | data->rsize = NFS_MAX_FILE_IO_SIZE; | ||
739 | data->wsize = NFS_MAX_FILE_IO_SIZE; | ||
740 | data->acregmin = NFS_DEF_ACREGMIN; | ||
741 | data->acregmax = NFS_DEF_ACREGMAX; | ||
742 | data->acdirmin = NFS_DEF_ACDIRMIN; | ||
743 | data->acdirmax = NFS_DEF_ACDIRMAX; | ||
744 | data->nfs_server.port = NFS_UNSPEC_PORT; | ||
745 | data->auth_flavors[0] = RPC_AUTH_UNIX; | ||
746 | data->auth_flavor_len = 1; | ||
747 | data->minorversion = 0; | ||
748 | } | ||
749 | return data; | ||
750 | } | ||
751 | |||
726 | /* | 752 | /* |
727 | * Sanity-check a server address provided by the mount command. | 753 | * Sanity-check a server address provided by the mount command. |
728 | * | 754 | * |
@@ -742,127 +768,23 @@ static int nfs_verify_server_address(struct sockaddr *addr) | |||
742 | } | 768 | } |
743 | } | 769 | } |
744 | 770 | ||
771 | dfprintk(MOUNT, "NFS: Invalid IP address specified\n"); | ||
745 | return 0; | 772 | return 0; |
746 | } | 773 | } |
747 | 774 | ||
748 | static void nfs_parse_ipv4_address(char *string, size_t str_len, | ||
749 | struct sockaddr *sap, size_t *addr_len) | ||
750 | { | ||
751 | struct sockaddr_in *sin = (struct sockaddr_in *)sap; | ||
752 | u8 *addr = (u8 *)&sin->sin_addr.s_addr; | ||
753 | |||
754 | if (str_len <= INET_ADDRSTRLEN) { | ||
755 | dfprintk(MOUNT, "NFS: parsing IPv4 address %*s\n", | ||
756 | (int)str_len, string); | ||
757 | |||
758 | sin->sin_family = AF_INET; | ||
759 | *addr_len = sizeof(*sin); | ||
760 | if (in4_pton(string, str_len, addr, '\0', NULL)) | ||
761 | return; | ||
762 | } | ||
763 | |||
764 | sap->sa_family = AF_UNSPEC; | ||
765 | *addr_len = 0; | ||
766 | } | ||
767 | |||
768 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
769 | static int nfs_parse_ipv6_scope_id(const char *string, const size_t str_len, | ||
770 | const char *delim, | ||
771 | struct sockaddr_in6 *sin6) | ||
772 | { | ||
773 | char *p; | ||
774 | size_t len; | ||
775 | |||
776 | if ((string + str_len) == delim) | ||
777 | return 1; | ||
778 | |||
779 | if (*delim != IPV6_SCOPE_DELIMITER) | ||
780 | return 0; | ||
781 | |||
782 | if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) | ||
783 | return 0; | ||
784 | |||
785 | len = (string + str_len) - delim - 1; | ||
786 | p = kstrndup(delim + 1, len, GFP_KERNEL); | ||
787 | if (p) { | ||
788 | unsigned long scope_id = 0; | ||
789 | struct net_device *dev; | ||
790 | |||
791 | dev = dev_get_by_name(&init_net, p); | ||
792 | if (dev != NULL) { | ||
793 | scope_id = dev->ifindex; | ||
794 | dev_put(dev); | ||
795 | } else { | ||
796 | if (strict_strtoul(p, 10, &scope_id) == 0) { | ||
797 | kfree(p); | ||
798 | return 0; | ||
799 | } | ||
800 | } | ||
801 | |||
802 | kfree(p); | ||
803 | |||
804 | sin6->sin6_scope_id = scope_id; | ||
805 | dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id); | ||
806 | return 1; | ||
807 | } | ||
808 | |||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | static void nfs_parse_ipv6_address(char *string, size_t str_len, | ||
813 | struct sockaddr *sap, size_t *addr_len) | ||
814 | { | ||
815 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | ||
816 | u8 *addr = (u8 *)&sin6->sin6_addr.in6_u; | ||
817 | const char *delim; | ||
818 | |||
819 | if (str_len <= INET6_ADDRSTRLEN) { | ||
820 | dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n", | ||
821 | (int)str_len, string); | ||
822 | |||
823 | sin6->sin6_family = AF_INET6; | ||
824 | *addr_len = sizeof(*sin6); | ||
825 | if (in6_pton(string, str_len, addr, | ||
826 | IPV6_SCOPE_DELIMITER, &delim) != 0) { | ||
827 | if (nfs_parse_ipv6_scope_id(string, str_len, | ||
828 | delim, sin6) != 0) | ||
829 | return; | ||
830 | } | ||
831 | } | ||
832 | |||
833 | sap->sa_family = AF_UNSPEC; | ||
834 | *addr_len = 0; | ||
835 | } | ||
836 | #else | ||
837 | static void nfs_parse_ipv6_address(char *string, size_t str_len, | ||
838 | struct sockaddr *sap, size_t *addr_len) | ||
839 | { | ||
840 | sap->sa_family = AF_UNSPEC; | ||
841 | *addr_len = 0; | ||
842 | } | ||
843 | #endif | ||
844 | |||
845 | /* | 775 | /* |
846 | * Construct a sockaddr based on the contents of a string that contains | 776 | * Select between a default port value and a user-specified port value. |
847 | * an IP address in presentation format. | 777 | * If a zero value is set, then autobind will be used. |
848 | * | ||
849 | * If there is a problem constructing the new sockaddr, set the address | ||
850 | * family to AF_UNSPEC. | ||
851 | */ | 778 | */ |
852 | void nfs_parse_ip_address(char *string, size_t str_len, | 779 | static void nfs_set_default_port(struct sockaddr *sap, const int parsed_port, |
853 | struct sockaddr *sap, size_t *addr_len) | 780 | const unsigned short default_port) |
854 | { | 781 | { |
855 | unsigned int i, colons; | 782 | unsigned short port = default_port; |
856 | 783 | ||
857 | colons = 0; | 784 | if (parsed_port != NFS_UNSPEC_PORT) |
858 | for (i = 0; i < str_len; i++) | 785 | port = parsed_port; |
859 | if (string[i] == ':') | ||
860 | colons++; | ||
861 | 786 | ||
862 | if (colons >= 2) | 787 | rpc_set_port(sap, port); |
863 | nfs_parse_ipv6_address(string, str_len, sap, addr_len); | ||
864 | else | ||
865 | nfs_parse_ipv4_address(string, str_len, sap, addr_len); | ||
866 | } | 788 | } |
867 | 789 | ||
868 | /* | 790 | /* |
@@ -904,8 +826,6 @@ static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt) | |||
904 | 826 | ||
905 | /* | 827 | /* |
906 | * Parse the value of the 'sec=' option. | 828 | * Parse the value of the 'sec=' option. |
907 | * | ||
908 | * The flavor_len setting is for v4 mounts. | ||
909 | */ | 829 | */ |
910 | static int nfs_parse_security_flavors(char *value, | 830 | static int nfs_parse_security_flavors(char *value, |
911 | struct nfs_parsed_mount_data *mnt) | 831 | struct nfs_parsed_mount_data *mnt) |
@@ -916,53 +836,43 @@ static int nfs_parse_security_flavors(char *value, | |||
916 | 836 | ||
917 | switch (match_token(value, nfs_secflavor_tokens, args)) { | 837 | switch (match_token(value, nfs_secflavor_tokens, args)) { |
918 | case Opt_sec_none: | 838 | case Opt_sec_none: |
919 | mnt->auth_flavor_len = 0; | ||
920 | mnt->auth_flavors[0] = RPC_AUTH_NULL; | 839 | mnt->auth_flavors[0] = RPC_AUTH_NULL; |
921 | break; | 840 | break; |
922 | case Opt_sec_sys: | 841 | case Opt_sec_sys: |
923 | mnt->auth_flavor_len = 0; | ||
924 | mnt->auth_flavors[0] = RPC_AUTH_UNIX; | 842 | mnt->auth_flavors[0] = RPC_AUTH_UNIX; |
925 | break; | 843 | break; |
926 | case Opt_sec_krb5: | 844 | case Opt_sec_krb5: |
927 | mnt->auth_flavor_len = 1; | ||
928 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; | 845 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; |
929 | break; | 846 | break; |
930 | case Opt_sec_krb5i: | 847 | case Opt_sec_krb5i: |
931 | mnt->auth_flavor_len = 1; | ||
932 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; | 848 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; |
933 | break; | 849 | break; |
934 | case Opt_sec_krb5p: | 850 | case Opt_sec_krb5p: |
935 | mnt->auth_flavor_len = 1; | ||
936 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; | 851 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; |
937 | break; | 852 | break; |
938 | case Opt_sec_lkey: | 853 | case Opt_sec_lkey: |
939 | mnt->auth_flavor_len = 1; | ||
940 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; | 854 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; |
941 | break; | 855 | break; |
942 | case Opt_sec_lkeyi: | 856 | case Opt_sec_lkeyi: |
943 | mnt->auth_flavor_len = 1; | ||
944 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; | 857 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; |
945 | break; | 858 | break; |
946 | case Opt_sec_lkeyp: | 859 | case Opt_sec_lkeyp: |
947 | mnt->auth_flavor_len = 1; | ||
948 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; | 860 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; |
949 | break; | 861 | break; |
950 | case Opt_sec_spkm: | 862 | case Opt_sec_spkm: |
951 | mnt->auth_flavor_len = 1; | ||
952 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; | 863 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; |
953 | break; | 864 | break; |
954 | case Opt_sec_spkmi: | 865 | case Opt_sec_spkmi: |
955 | mnt->auth_flavor_len = 1; | ||
956 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; | 866 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; |
957 | break; | 867 | break; |
958 | case Opt_sec_spkmp: | 868 | case Opt_sec_spkmp: |
959 | mnt->auth_flavor_len = 1; | ||
960 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; | 869 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; |
961 | break; | 870 | break; |
962 | default: | 871 | default: |
963 | return 0; | 872 | return 0; |
964 | } | 873 | } |
965 | 874 | ||
875 | mnt->auth_flavor_len = 1; | ||
966 | return 1; | 876 | return 1; |
967 | } | 877 | } |
968 | 878 | ||
@@ -1001,7 +911,6 @@ static int nfs_parse_mount_options(char *raw, | |||
1001 | while ((p = strsep(&raw, ",")) != NULL) { | 911 | while ((p = strsep(&raw, ",")) != NULL) { |
1002 | substring_t args[MAX_OPT_ARGS]; | 912 | substring_t args[MAX_OPT_ARGS]; |
1003 | unsigned long option; | 913 | unsigned long option; |
1004 | int int_option; | ||
1005 | int token; | 914 | int token; |
1006 | 915 | ||
1007 | if (!*p) | 916 | if (!*p) |
@@ -1047,10 +956,18 @@ static int nfs_parse_mount_options(char *raw, | |||
1047 | break; | 956 | break; |
1048 | case Opt_v2: | 957 | case Opt_v2: |
1049 | mnt->flags &= ~NFS_MOUNT_VER3; | 958 | mnt->flags &= ~NFS_MOUNT_VER3; |
959 | mnt->version = 2; | ||
1050 | break; | 960 | break; |
1051 | case Opt_v3: | 961 | case Opt_v3: |
1052 | mnt->flags |= NFS_MOUNT_VER3; | 962 | mnt->flags |= NFS_MOUNT_VER3; |
963 | mnt->version = 3; | ||
964 | break; | ||
965 | #ifdef CONFIG_NFS_V4 | ||
966 | case Opt_v4: | ||
967 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
968 | mnt->version = 4; | ||
1053 | break; | 969 | break; |
970 | #endif | ||
1054 | case Opt_udp: | 971 | case Opt_udp: |
1055 | mnt->flags &= ~NFS_MOUNT_TCP; | 972 | mnt->flags &= ~NFS_MOUNT_TCP; |
1056 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 973 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
@@ -1264,20 +1181,33 @@ static int nfs_parse_mount_options(char *raw, | |||
1264 | switch (option) { | 1181 | switch (option) { |
1265 | case NFS2_VERSION: | 1182 | case NFS2_VERSION: |
1266 | mnt->flags &= ~NFS_MOUNT_VER3; | 1183 | mnt->flags &= ~NFS_MOUNT_VER3; |
1184 | mnt->version = 2; | ||
1267 | break; | 1185 | break; |
1268 | case NFS3_VERSION: | 1186 | case NFS3_VERSION: |
1269 | mnt->flags |= NFS_MOUNT_VER3; | 1187 | mnt->flags |= NFS_MOUNT_VER3; |
1188 | mnt->version = 3; | ||
1189 | break; | ||
1190 | #ifdef CONFIG_NFS_V4 | ||
1191 | case NFS4_VERSION: | ||
1192 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
1193 | mnt->version = 4; | ||
1270 | break; | 1194 | break; |
1195 | #endif | ||
1271 | default: | 1196 | default: |
1272 | goto out_invalid_value; | 1197 | goto out_invalid_value; |
1273 | } | 1198 | } |
1274 | break; | 1199 | break; |
1275 | case Opt_minorversion: | 1200 | case Opt_minorversion: |
1276 | if (match_int(args, &int_option)) | 1201 | string = match_strdup(args); |
1277 | return 0; | 1202 | if (string == NULL) |
1278 | if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION) | 1203 | goto out_nomem; |
1279 | return 0; | 1204 | rc = strict_strtoul(string, 10, &option); |
1280 | mnt->minorversion = int_option; | 1205 | kfree(string); |
1206 | if (rc != 0) | ||
1207 | goto out_invalid_value; | ||
1208 | if (option > NFS4_MAX_MINOR_VERSION) | ||
1209 | goto out_invalid_value; | ||
1210 | mnt->minorversion = option; | ||
1281 | break; | 1211 | break; |
1282 | 1212 | ||
1283 | /* | 1213 | /* |
@@ -1352,11 +1282,14 @@ static int nfs_parse_mount_options(char *raw, | |||
1352 | string = match_strdup(args); | 1282 | string = match_strdup(args); |
1353 | if (string == NULL) | 1283 | if (string == NULL) |
1354 | goto out_nomem; | 1284 | goto out_nomem; |
1355 | nfs_parse_ip_address(string, strlen(string), | 1285 | mnt->nfs_server.addrlen = |
1356 | (struct sockaddr *) | 1286 | rpc_pton(string, strlen(string), |
1357 | &mnt->nfs_server.address, | 1287 | (struct sockaddr *) |
1358 | &mnt->nfs_server.addrlen); | 1288 | &mnt->nfs_server.address, |
1289 | sizeof(mnt->nfs_server.address)); | ||
1359 | kfree(string); | 1290 | kfree(string); |
1291 | if (mnt->nfs_server.addrlen == 0) | ||
1292 | goto out_invalid_address; | ||
1360 | break; | 1293 | break; |
1361 | case Opt_clientaddr: | 1294 | case Opt_clientaddr: |
1362 | string = match_strdup(args); | 1295 | string = match_strdup(args); |
@@ -1376,11 +1309,14 @@ static int nfs_parse_mount_options(char *raw, | |||
1376 | string = match_strdup(args); | 1309 | string = match_strdup(args); |
1377 | if (string == NULL) | 1310 | if (string == NULL) |
1378 | goto out_nomem; | 1311 | goto out_nomem; |
1379 | nfs_parse_ip_address(string, strlen(string), | 1312 | mnt->mount_server.addrlen = |
1380 | (struct sockaddr *) | 1313 | rpc_pton(string, strlen(string), |
1381 | &mnt->mount_server.address, | 1314 | (struct sockaddr *) |
1382 | &mnt->mount_server.addrlen); | 1315 | &mnt->mount_server.address, |
1316 | sizeof(mnt->mount_server.address)); | ||
1383 | kfree(string); | 1317 | kfree(string); |
1318 | if (mnt->mount_server.addrlen == 0) | ||
1319 | goto out_invalid_address; | ||
1384 | break; | 1320 | break; |
1385 | case Opt_lookupcache: | 1321 | case Opt_lookupcache: |
1386 | string = match_strdup(args); | 1322 | string = match_strdup(args); |
@@ -1432,8 +1368,11 @@ static int nfs_parse_mount_options(char *raw, | |||
1432 | 1368 | ||
1433 | return 1; | 1369 | return 1; |
1434 | 1370 | ||
1371 | out_invalid_address: | ||
1372 | printk(KERN_INFO "NFS: bad IP address specified: %s\n", p); | ||
1373 | return 0; | ||
1435 | out_invalid_value: | 1374 | out_invalid_value: |
1436 | printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p); | 1375 | printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p); |
1437 | return 0; | 1376 | return 0; |
1438 | out_nomem: | 1377 | out_nomem: |
1439 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); | 1378 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); |
@@ -1445,13 +1384,60 @@ out_security_failure: | |||
1445 | } | 1384 | } |
1446 | 1385 | ||
1447 | /* | 1386 | /* |
1387 | * Match the requested auth flavors with the list returned by | ||
1388 | * the server. Returns zero and sets the mount's authentication | ||
1389 | * flavor on success; returns -EACCES if server does not support | ||
1390 | * the requested flavor. | ||
1391 | */ | ||
1392 | static int nfs_walk_authlist(struct nfs_parsed_mount_data *args, | ||
1393 | struct nfs_mount_request *request) | ||
1394 | { | ||
1395 | unsigned int i, j, server_authlist_len = *(request->auth_flav_len); | ||
1396 | |||
1397 | /* | ||
1398 | * Certain releases of Linux's mountd return an empty | ||
1399 | * flavor list. To prevent behavioral regression with | ||
1400 | * these servers (ie. rejecting mounts that used to | ||
1401 | * succeed), revert to pre-2.6.32 behavior (no checking) | ||
1402 | * if the returned flavor list is empty. | ||
1403 | */ | ||
1404 | if (server_authlist_len == 0) | ||
1405 | return 0; | ||
1406 | |||
1407 | /* | ||
1408 | * We avoid sophisticated negotiating here, as there are | ||
1409 | * plenty of cases where we can get it wrong, providing | ||
1410 | * either too little or too much security. | ||
1411 | * | ||
1412 | * RFC 2623, section 2.7 suggests we SHOULD prefer the | ||
1413 | * flavor listed first. However, some servers list | ||
1414 | * AUTH_NULL first. Our caller plants AUTH_SYS, the | ||
1415 | * preferred default, in args->auth_flavors[0] if user | ||
1416 | * didn't specify sec= mount option. | ||
1417 | */ | ||
1418 | for (i = 0; i < args->auth_flavor_len; i++) | ||
1419 | for (j = 0; j < server_authlist_len; j++) | ||
1420 | if (args->auth_flavors[i] == request->auth_flavs[j]) { | ||
1421 | dfprintk(MOUNT, "NFS: using auth flavor %d\n", | ||
1422 | request->auth_flavs[j]); | ||
1423 | args->auth_flavors[0] = request->auth_flavs[j]; | ||
1424 | return 0; | ||
1425 | } | ||
1426 | |||
1427 | dfprintk(MOUNT, "NFS: server does not support requested auth flavor\n"); | ||
1428 | nfs_umount(request); | ||
1429 | return -EACCES; | ||
1430 | } | ||
1431 | |||
1432 | /* | ||
1448 | * Use the remote server's MOUNT service to request the NFS file handle | 1433 | * Use the remote server's MOUNT service to request the NFS file handle |
1449 | * corresponding to the provided path. | 1434 | * corresponding to the provided path. |
1450 | */ | 1435 | */ |
1451 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, | 1436 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
1452 | struct nfs_fh *root_fh) | 1437 | struct nfs_fh *root_fh) |
1453 | { | 1438 | { |
1454 | unsigned int auth_flavor_len = 0; | 1439 | rpc_authflavor_t server_authlist[NFS_MAX_SECFLAVORS]; |
1440 | unsigned int server_authlist_len = ARRAY_SIZE(server_authlist); | ||
1455 | struct nfs_mount_request request = { | 1441 | struct nfs_mount_request request = { |
1456 | .sap = (struct sockaddr *) | 1442 | .sap = (struct sockaddr *) |
1457 | &args->mount_server.address, | 1443 | &args->mount_server.address, |
@@ -1459,15 +1445,19 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1459 | .protocol = args->mount_server.protocol, | 1445 | .protocol = args->mount_server.protocol, |
1460 | .fh = root_fh, | 1446 | .fh = root_fh, |
1461 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, | 1447 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, |
1462 | .auth_flav_len = &auth_flavor_len, | 1448 | .auth_flav_len = &server_authlist_len, |
1449 | .auth_flavs = server_authlist, | ||
1463 | }; | 1450 | }; |
1464 | int status; | 1451 | int status; |
1465 | 1452 | ||
1466 | if (args->mount_server.version == 0) { | 1453 | if (args->mount_server.version == 0) { |
1467 | if (args->flags & NFS_MOUNT_VER3) | 1454 | switch (args->version) { |
1468 | args->mount_server.version = NFS_MNT3_VERSION; | 1455 | default: |
1469 | else | 1456 | args->mount_server.version = NFS_MNT3_VERSION; |
1470 | args->mount_server.version = NFS_MNT_VERSION; | 1457 | break; |
1458 | case 2: | ||
1459 | args->mount_server.version = NFS_MNT_VERSION; | ||
1460 | } | ||
1471 | } | 1461 | } |
1472 | request.version = args->mount_server.version; | 1462 | request.version = args->mount_server.version; |
1473 | 1463 | ||
@@ -1485,23 +1475,25 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1485 | args->mount_server.addrlen = args->nfs_server.addrlen; | 1475 | args->mount_server.addrlen = args->nfs_server.addrlen; |
1486 | } | 1476 | } |
1487 | request.salen = args->mount_server.addrlen; | 1477 | request.salen = args->mount_server.addrlen; |
1488 | 1478 | nfs_set_default_port(request.sap, args->mount_server.port, 0); | |
1489 | /* | ||
1490 | * autobind will be used if mount_server.port == 0 | ||
1491 | */ | ||
1492 | nfs_set_port(request.sap, args->mount_server.port); | ||
1493 | 1479 | ||
1494 | /* | 1480 | /* |
1495 | * Now ask the mount server to map our export path | 1481 | * Now ask the mount server to map our export path |
1496 | * to a file handle. | 1482 | * to a file handle. |
1497 | */ | 1483 | */ |
1498 | status = nfs_mount(&request); | 1484 | status = nfs_mount(&request); |
1499 | if (status == 0) | 1485 | if (status != 0) { |
1500 | return 0; | 1486 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", |
1487 | request.hostname, status); | ||
1488 | return status; | ||
1489 | } | ||
1501 | 1490 | ||
1502 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", | 1491 | /* |
1503 | request.hostname, status); | 1492 | * MNTv1 (NFSv2) does not support auth flavor negotiation. |
1504 | return status; | 1493 | */ |
1494 | if (args->mount_server.version != NFS_MNT3_VERSION) | ||
1495 | return 0; | ||
1496 | return nfs_walk_authlist(args, &request); | ||
1505 | } | 1497 | } |
1506 | 1498 | ||
1507 | static int nfs_parse_simple_hostname(const char *dev_name, | 1499 | static int nfs_parse_simple_hostname(const char *dev_name, |
@@ -1661,22 +1653,11 @@ static int nfs_validate_mount_data(void *options, | |||
1661 | const char *dev_name) | 1653 | const char *dev_name) |
1662 | { | 1654 | { |
1663 | struct nfs_mount_data *data = (struct nfs_mount_data *)options; | 1655 | struct nfs_mount_data *data = (struct nfs_mount_data *)options; |
1656 | struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; | ||
1664 | 1657 | ||
1665 | if (data == NULL) | 1658 | if (data == NULL) |
1666 | goto out_no_data; | 1659 | goto out_no_data; |
1667 | 1660 | ||
1668 | args->flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP); | ||
1669 | args->rsize = NFS_MAX_FILE_IO_SIZE; | ||
1670 | args->wsize = NFS_MAX_FILE_IO_SIZE; | ||
1671 | args->acregmin = NFS_DEF_ACREGMIN; | ||
1672 | args->acregmax = NFS_DEF_ACREGMAX; | ||
1673 | args->acdirmin = NFS_DEF_ACDIRMIN; | ||
1674 | args->acdirmax = NFS_DEF_ACDIRMAX; | ||
1675 | args->mount_server.port = 0; /* autobind unless user sets port */ | ||
1676 | args->nfs_server.port = 0; /* autobind unless user sets port */ | ||
1677 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | ||
1678 | args->auth_flavors[0] = RPC_AUTH_UNIX; | ||
1679 | |||
1680 | switch (data->version) { | 1661 | switch (data->version) { |
1681 | case 1: | 1662 | case 1: |
1682 | data->namlen = 0; | 1663 | data->namlen = 0; |
@@ -1697,8 +1678,11 @@ static int nfs_validate_mount_data(void *options, | |||
1697 | if (data->root.size > NFS3_FHSIZE || data->root.size == 0) | 1678 | if (data->root.size > NFS3_FHSIZE || data->root.size == 0) |
1698 | goto out_invalid_fh; | 1679 | goto out_invalid_fh; |
1699 | mntfh->size = data->root.size; | 1680 | mntfh->size = data->root.size; |
1700 | } else | 1681 | args->version = 3; |
1682 | } else { | ||
1701 | mntfh->size = NFS2_FHSIZE; | 1683 | mntfh->size = NFS2_FHSIZE; |
1684 | args->version = 2; | ||
1685 | } | ||
1702 | 1686 | ||
1703 | 1687 | ||
1704 | memcpy(mntfh->data, data->root.data, mntfh->size); | 1688 | memcpy(mntfh->data, data->root.data, mntfh->size); |
@@ -1720,15 +1704,15 @@ static int nfs_validate_mount_data(void *options, | |||
1720 | args->acdirmin = data->acdirmin; | 1704 | args->acdirmin = data->acdirmin; |
1721 | args->acdirmax = data->acdirmax; | 1705 | args->acdirmax = data->acdirmax; |
1722 | 1706 | ||
1723 | memcpy(&args->nfs_server.address, &data->addr, | 1707 | memcpy(sap, &data->addr, sizeof(data->addr)); |
1724 | sizeof(data->addr)); | ||
1725 | args->nfs_server.addrlen = sizeof(data->addr); | 1708 | args->nfs_server.addrlen = sizeof(data->addr); |
1726 | if (!nfs_verify_server_address((struct sockaddr *) | 1709 | if (!nfs_verify_server_address(sap)) |
1727 | &args->nfs_server.address)) | ||
1728 | goto out_no_address; | 1710 | goto out_no_address; |
1729 | 1711 | ||
1730 | if (!(data->flags & NFS_MOUNT_TCP)) | 1712 | if (!(data->flags & NFS_MOUNT_TCP)) |
1731 | args->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1713 | args->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
1714 | else | ||
1715 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | ||
1732 | /* N.B. caller will free nfs_server.hostname in all cases */ | 1716 | /* N.B. caller will free nfs_server.hostname in all cases */ |
1733 | args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); | 1717 | args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); |
1734 | args->namlen = data->namlen; | 1718 | args->namlen = data->namlen; |
@@ -1772,12 +1756,18 @@ static int nfs_validate_mount_data(void *options, | |||
1772 | if (nfs_parse_mount_options((char *)options, args) == 0) | 1756 | if (nfs_parse_mount_options((char *)options, args) == 0) |
1773 | return -EINVAL; | 1757 | return -EINVAL; |
1774 | 1758 | ||
1775 | if (!nfs_verify_server_address((struct sockaddr *) | 1759 | if (!nfs_verify_server_address(sap)) |
1776 | &args->nfs_server.address)) | ||
1777 | goto out_no_address; | 1760 | goto out_no_address; |
1778 | 1761 | ||
1779 | nfs_set_port((struct sockaddr *)&args->nfs_server.address, | 1762 | if (args->version == 4) |
1780 | args->nfs_server.port); | 1763 | #ifdef CONFIG_NFS_V4 |
1764 | return nfs4_validate_text_mount_data(options, | ||
1765 | args, dev_name); | ||
1766 | #else | ||
1767 | goto out_v4_not_compiled; | ||
1768 | #endif | ||
1769 | |||
1770 | nfs_set_default_port(sap, args->nfs_server.port, 0); | ||
1781 | 1771 | ||
1782 | nfs_set_mount_transport_protocol(args); | 1772 | nfs_set_mount_transport_protocol(args); |
1783 | 1773 | ||
@@ -1800,7 +1790,7 @@ static int nfs_validate_mount_data(void *options, | |||
1800 | } | 1790 | } |
1801 | 1791 | ||
1802 | #ifndef CONFIG_NFS_V3 | 1792 | #ifndef CONFIG_NFS_V3 |
1803 | if (args->flags & NFS_MOUNT_VER3) | 1793 | if (args->version == 3) |
1804 | goto out_v3_not_compiled; | 1794 | goto out_v3_not_compiled; |
1805 | #endif /* !CONFIG_NFS_V3 */ | 1795 | #endif /* !CONFIG_NFS_V3 */ |
1806 | 1796 | ||
@@ -1825,6 +1815,12 @@ out_v3_not_compiled: | |||
1825 | return -EPROTONOSUPPORT; | 1815 | return -EPROTONOSUPPORT; |
1826 | #endif /* !CONFIG_NFS_V3 */ | 1816 | #endif /* !CONFIG_NFS_V3 */ |
1827 | 1817 | ||
1818 | #ifndef CONFIG_NFS_V4 | ||
1819 | out_v4_not_compiled: | ||
1820 | dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n"); | ||
1821 | return -EPROTONOSUPPORT; | ||
1822 | #endif /* !CONFIG_NFS_V4 */ | ||
1823 | |||
1828 | out_nomem: | 1824 | out_nomem: |
1829 | dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n"); | 1825 | dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n"); |
1830 | return -ENOMEM; | 1826 | return -ENOMEM; |
@@ -1934,6 +1930,8 @@ static inline void nfs_initialise_sb(struct super_block *sb) | |||
1934 | if (server->flags & NFS_MOUNT_NOAC) | 1930 | if (server->flags & NFS_MOUNT_NOAC) |
1935 | sb->s_flags |= MS_SYNCHRONOUS; | 1931 | sb->s_flags |= MS_SYNCHRONOUS; |
1936 | 1932 | ||
1933 | sb->s_bdi = &server->backing_dev_info; | ||
1934 | |||
1937 | nfs_super_set_maxbytes(sb, server->maxfilesize); | 1935 | nfs_super_set_maxbytes(sb, server->maxfilesize); |
1938 | } | 1936 | } |
1939 | 1937 | ||
@@ -1950,7 +1948,7 @@ static void nfs_fill_super(struct super_block *sb, | |||
1950 | if (data->bsize) | 1948 | if (data->bsize) |
1951 | sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits); | 1949 | sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits); |
1952 | 1950 | ||
1953 | if (server->flags & NFS_MOUNT_VER3) { | 1951 | if (server->nfs_client->rpc_ops->version == 3) { |
1954 | /* The VFS shouldn't apply the umask to mode bits. We will do | 1952 | /* The VFS shouldn't apply the umask to mode bits. We will do |
1955 | * so ourselves when necessary. | 1953 | * so ourselves when necessary. |
1956 | */ | 1954 | */ |
@@ -1974,7 +1972,7 @@ static void nfs_clone_super(struct super_block *sb, | |||
1974 | sb->s_blocksize = old_sb->s_blocksize; | 1972 | sb->s_blocksize = old_sb->s_blocksize; |
1975 | sb->s_maxbytes = old_sb->s_maxbytes; | 1973 | sb->s_maxbytes = old_sb->s_maxbytes; |
1976 | 1974 | ||
1977 | if (server->flags & NFS_MOUNT_VER3) { | 1975 | if (server->nfs_client->rpc_ops->version == 3) { |
1978 | /* The VFS shouldn't apply the umask to mode bits. We will do | 1976 | /* The VFS shouldn't apply the umask to mode bits. We will do |
1979 | * so ourselves when necessary. | 1977 | * so ourselves when necessary. |
1980 | */ | 1978 | */ |
@@ -2108,7 +2106,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2108 | }; | 2106 | }; |
2109 | int error = -ENOMEM; | 2107 | int error = -ENOMEM; |
2110 | 2108 | ||
2111 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 2109 | data = nfs_alloc_parsed_mount_data(NFS_MOUNT_VER3 | NFS_MOUNT_TCP); |
2112 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); | 2110 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); |
2113 | if (data == NULL || mntfh == NULL) | 2111 | if (data == NULL || mntfh == NULL) |
2114 | goto out_free_fh; | 2112 | goto out_free_fh; |
@@ -2120,6 +2118,14 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2120 | if (error < 0) | 2118 | if (error < 0) |
2121 | goto out; | 2119 | goto out; |
2122 | 2120 | ||
2121 | #ifdef CONFIG_NFS_V4 | ||
2122 | if (data->version == 4) { | ||
2123 | error = nfs4_try_mount(flags, dev_name, data, mnt); | ||
2124 | kfree(data->client_address); | ||
2125 | goto out; | ||
2126 | } | ||
2127 | #endif /* CONFIG_NFS_V4 */ | ||
2128 | |||
2123 | /* Get a volume representation */ | 2129 | /* Get a volume representation */ |
2124 | server = nfs_create_server(data, mntfh); | 2130 | server = nfs_create_server(data, mntfh); |
2125 | if (IS_ERR(server)) { | 2131 | if (IS_ERR(server)) { |
@@ -2150,7 +2156,8 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2150 | if (!s->s_root) { | 2156 | if (!s->s_root) { |
2151 | /* initial superblock/root creation */ | 2157 | /* initial superblock/root creation */ |
2152 | nfs_fill_super(s, data); | 2158 | nfs_fill_super(s, data); |
2153 | nfs_fscache_get_super_cookie(s, data); | 2159 | nfs_fscache_get_super_cookie( |
2160 | s, data ? data->fscache_uniq : NULL, NULL); | ||
2154 | } | 2161 | } |
2155 | 2162 | ||
2156 | mntroot = nfs_get_root(s, mntfh); | 2163 | mntroot = nfs_get_root(s, mntfh); |
@@ -2196,8 +2203,8 @@ static void nfs_kill_super(struct super_block *s) | |||
2196 | { | 2203 | { |
2197 | struct nfs_server *server = NFS_SB(s); | 2204 | struct nfs_server *server = NFS_SB(s); |
2198 | 2205 | ||
2199 | bdi_unregister(&server->backing_dev_info); | ||
2200 | kill_anon_super(s); | 2206 | kill_anon_super(s); |
2207 | bdi_unregister(&server->backing_dev_info); | ||
2201 | nfs_fscache_release_super_cookie(s); | 2208 | nfs_fscache_release_super_cookie(s); |
2202 | nfs_free_server(server); | 2209 | nfs_free_server(server); |
2203 | } | 2210 | } |
@@ -2251,6 +2258,7 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, | |||
2251 | if (!s->s_root) { | 2258 | if (!s->s_root) { |
2252 | /* initial superblock/root creation */ | 2259 | /* initial superblock/root creation */ |
2253 | nfs_clone_super(s, data->sb); | 2260 | nfs_clone_super(s, data->sb); |
2261 | nfs_fscache_get_super_cookie(s, NULL, data); | ||
2254 | } | 2262 | } |
2255 | 2263 | ||
2256 | mntroot = nfs_get_root(s, data->fh); | 2264 | mntroot = nfs_get_root(s, data->fh); |
@@ -2317,6 +2325,43 @@ static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) | |||
2317 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3); | 2325 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3); |
2318 | } | 2326 | } |
2319 | 2327 | ||
2328 | static int nfs4_validate_text_mount_data(void *options, | ||
2329 | struct nfs_parsed_mount_data *args, | ||
2330 | const char *dev_name) | ||
2331 | { | ||
2332 | struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; | ||
2333 | |||
2334 | nfs_set_default_port(sap, args->nfs_server.port, NFS_PORT); | ||
2335 | |||
2336 | nfs_validate_transport_protocol(args); | ||
2337 | |||
2338 | nfs4_validate_mount_flags(args); | ||
2339 | |||
2340 | if (args->version != 4) { | ||
2341 | dfprintk(MOUNT, | ||
2342 | "NFS4: Illegal mount version\n"); | ||
2343 | return -EINVAL; | ||
2344 | } | ||
2345 | |||
2346 | if (args->auth_flavor_len > 1) { | ||
2347 | dfprintk(MOUNT, | ||
2348 | "NFS4: Too many RPC auth flavours specified\n"); | ||
2349 | return -EINVAL; | ||
2350 | } | ||
2351 | |||
2352 | if (args->client_address == NULL) { | ||
2353 | dfprintk(MOUNT, | ||
2354 | "NFS4: mount program didn't pass callback address\n"); | ||
2355 | return -EINVAL; | ||
2356 | } | ||
2357 | |||
2358 | return nfs_parse_devname(dev_name, | ||
2359 | &args->nfs_server.hostname, | ||
2360 | NFS4_MAXNAMLEN, | ||
2361 | &args->nfs_server.export_path, | ||
2362 | NFS4_MAXPATHLEN); | ||
2363 | } | ||
2364 | |||
2320 | /* | 2365 | /* |
2321 | * Validate NFSv4 mount options | 2366 | * Validate NFSv4 mount options |
2322 | */ | 2367 | */ |
@@ -2324,36 +2369,24 @@ static int nfs4_validate_mount_data(void *options, | |||
2324 | struct nfs_parsed_mount_data *args, | 2369 | struct nfs_parsed_mount_data *args, |
2325 | const char *dev_name) | 2370 | const char *dev_name) |
2326 | { | 2371 | { |
2327 | struct sockaddr_in *ap; | 2372 | struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; |
2328 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; | 2373 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; |
2329 | char *c; | 2374 | char *c; |
2330 | 2375 | ||
2331 | if (data == NULL) | 2376 | if (data == NULL) |
2332 | goto out_no_data; | 2377 | goto out_no_data; |
2333 | 2378 | ||
2334 | args->rsize = NFS_MAX_FILE_IO_SIZE; | 2379 | args->version = 4; |
2335 | args->wsize = NFS_MAX_FILE_IO_SIZE; | ||
2336 | args->acregmin = NFS_DEF_ACREGMIN; | ||
2337 | args->acregmax = NFS_DEF_ACREGMAX; | ||
2338 | args->acdirmin = NFS_DEF_ACDIRMIN; | ||
2339 | args->acdirmax = NFS_DEF_ACDIRMAX; | ||
2340 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | ||
2341 | args->auth_flavors[0] = RPC_AUTH_UNIX; | ||
2342 | args->auth_flavor_len = 0; | ||
2343 | args->minorversion = 0; | ||
2344 | |||
2345 | switch (data->version) { | 2380 | switch (data->version) { |
2346 | case 1: | 2381 | case 1: |
2347 | ap = (struct sockaddr_in *)&args->nfs_server.address; | ||
2348 | if (data->host_addrlen > sizeof(args->nfs_server.address)) | 2382 | if (data->host_addrlen > sizeof(args->nfs_server.address)) |
2349 | goto out_no_address; | 2383 | goto out_no_address; |
2350 | if (data->host_addrlen == 0) | 2384 | if (data->host_addrlen == 0) |
2351 | goto out_no_address; | 2385 | goto out_no_address; |
2352 | args->nfs_server.addrlen = data->host_addrlen; | 2386 | args->nfs_server.addrlen = data->host_addrlen; |
2353 | if (copy_from_user(ap, data->host_addr, data->host_addrlen)) | 2387 | if (copy_from_user(sap, data->host_addr, data->host_addrlen)) |
2354 | return -EFAULT; | 2388 | return -EFAULT; |
2355 | if (!nfs_verify_server_address((struct sockaddr *) | 2389 | if (!nfs_verify_server_address(sap)) |
2356 | &args->nfs_server.address)) | ||
2357 | goto out_no_address; | 2390 | goto out_no_address; |
2358 | 2391 | ||
2359 | if (data->auth_flavourlen) { | 2392 | if (data->auth_flavourlen) { |
@@ -2399,39 +2432,14 @@ static int nfs4_validate_mount_data(void *options, | |||
2399 | nfs_validate_transport_protocol(args); | 2432 | nfs_validate_transport_protocol(args); |
2400 | 2433 | ||
2401 | break; | 2434 | break; |
2402 | default: { | 2435 | default: |
2403 | int status; | ||
2404 | |||
2405 | if (nfs_parse_mount_options((char *)options, args) == 0) | 2436 | if (nfs_parse_mount_options((char *)options, args) == 0) |
2406 | return -EINVAL; | 2437 | return -EINVAL; |
2407 | 2438 | ||
2408 | if (!nfs_verify_server_address((struct sockaddr *) | 2439 | if (!nfs_verify_server_address(sap)) |
2409 | &args->nfs_server.address)) | ||
2410 | return -EINVAL; | 2440 | return -EINVAL; |
2411 | 2441 | ||
2412 | nfs_set_port((struct sockaddr *)&args->nfs_server.address, | 2442 | return nfs4_validate_text_mount_data(options, args, dev_name); |
2413 | args->nfs_server.port); | ||
2414 | |||
2415 | nfs_validate_transport_protocol(args); | ||
2416 | |||
2417 | nfs4_validate_mount_flags(args); | ||
2418 | |||
2419 | if (args->auth_flavor_len > 1) | ||
2420 | goto out_inval_auth; | ||
2421 | |||
2422 | if (args->client_address == NULL) | ||
2423 | goto out_no_client_address; | ||
2424 | |||
2425 | status = nfs_parse_devname(dev_name, | ||
2426 | &args->nfs_server.hostname, | ||
2427 | NFS4_MAXNAMLEN, | ||
2428 | &args->nfs_server.export_path, | ||
2429 | NFS4_MAXPATHLEN); | ||
2430 | if (status < 0) | ||
2431 | return status; | ||
2432 | |||
2433 | break; | ||
2434 | } | ||
2435 | } | 2443 | } |
2436 | 2444 | ||
2437 | return 0; | 2445 | return 0; |
@@ -2448,10 +2456,6 @@ out_inval_auth: | |||
2448 | out_no_address: | 2456 | out_no_address: |
2449 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); | 2457 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); |
2450 | return -EINVAL; | 2458 | return -EINVAL; |
2451 | |||
2452 | out_no_client_address: | ||
2453 | dfprintk(MOUNT, "NFS4: mount program didn't pass callback address\n"); | ||
2454 | return -EINVAL; | ||
2455 | } | 2459 | } |
2456 | 2460 | ||
2457 | /* | 2461 | /* |
@@ -2507,7 +2511,8 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type, | |||
2507 | if (!s->s_root) { | 2511 | if (!s->s_root) { |
2508 | /* initial superblock/root creation */ | 2512 | /* initial superblock/root creation */ |
2509 | nfs4_fill_super(s); | 2513 | nfs4_fill_super(s); |
2510 | nfs_fscache_get_super_cookie(s, data); | 2514 | nfs_fscache_get_super_cookie( |
2515 | s, data ? data->fscache_uniq : NULL, NULL); | ||
2511 | } | 2516 | } |
2512 | 2517 | ||
2513 | mntroot = nfs4_get_root(s, mntfh); | 2518 | mntroot = nfs4_get_root(s, mntfh); |
@@ -2618,6 +2623,34 @@ out_err: | |||
2618 | return ret; | 2623 | return ret; |
2619 | } | 2624 | } |
2620 | 2625 | ||
2626 | static int nfs4_try_mount(int flags, const char *dev_name, | ||
2627 | struct nfs_parsed_mount_data *data, | ||
2628 | struct vfsmount *mnt) | ||
2629 | { | ||
2630 | char *export_path; | ||
2631 | struct vfsmount *root_mnt; | ||
2632 | int error; | ||
2633 | |||
2634 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); | ||
2635 | |||
2636 | export_path = data->nfs_server.export_path; | ||
2637 | data->nfs_server.export_path = "/"; | ||
2638 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data, | ||
2639 | data->nfs_server.hostname); | ||
2640 | data->nfs_server.export_path = export_path; | ||
2641 | |||
2642 | error = PTR_ERR(root_mnt); | ||
2643 | if (IS_ERR(root_mnt)) | ||
2644 | goto out; | ||
2645 | |||
2646 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | ||
2647 | |||
2648 | out: | ||
2649 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n", error, | ||
2650 | error != 0 ? " [error]" : ""); | ||
2651 | return error; | ||
2652 | } | ||
2653 | |||
2621 | /* | 2654 | /* |
2622 | * Get the superblock for an NFS4 mountpoint | 2655 | * Get the superblock for an NFS4 mountpoint |
2623 | */ | 2656 | */ |
@@ -2625,11 +2658,9 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2625 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 2658 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) |
2626 | { | 2659 | { |
2627 | struct nfs_parsed_mount_data *data; | 2660 | struct nfs_parsed_mount_data *data; |
2628 | char *export_path; | ||
2629 | struct vfsmount *root_mnt; | ||
2630 | int error = -ENOMEM; | 2661 | int error = -ENOMEM; |
2631 | 2662 | ||
2632 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 2663 | data = nfs_alloc_parsed_mount_data(0); |
2633 | if (data == NULL) | 2664 | if (data == NULL) |
2634 | goto out_free_data; | 2665 | goto out_free_data; |
2635 | 2666 | ||
@@ -2638,17 +2669,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2638 | if (error < 0) | 2669 | if (error < 0) |
2639 | goto out; | 2670 | goto out; |
2640 | 2671 | ||
2641 | export_path = data->nfs_server.export_path; | 2672 | error = nfs4_try_mount(flags, dev_name, data, mnt); |
2642 | data->nfs_server.export_path = "/"; | ||
2643 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data, | ||
2644 | data->nfs_server.hostname); | ||
2645 | data->nfs_server.export_path = export_path; | ||
2646 | |||
2647 | error = PTR_ERR(root_mnt); | ||
2648 | if (IS_ERR(root_mnt)) | ||
2649 | goto out; | ||
2650 | |||
2651 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | ||
2652 | 2673 | ||
2653 | out: | 2674 | out: |
2654 | kfree(data->client_address); | 2675 | kfree(data->client_address); |
@@ -2724,6 +2745,7 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, | |||
2724 | if (!s->s_root) { | 2745 | if (!s->s_root) { |
2725 | /* initial superblock/root creation */ | 2746 | /* initial superblock/root creation */ |
2726 | nfs4_clone_super(s, data->sb); | 2747 | nfs4_clone_super(s, data->sb); |
2748 | nfs_fscache_get_super_cookie(s, NULL, data); | ||
2727 | } | 2749 | } |
2728 | 2750 | ||
2729 | mntroot = nfs4_get_root(s, data->fh); | 2751 | mntroot = nfs4_get_root(s, data->fh); |
@@ -2805,6 +2827,7 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
2805 | if (!s->s_root) { | 2827 | if (!s->s_root) { |
2806 | /* initial superblock/root creation */ | 2828 | /* initial superblock/root creation */ |
2807 | nfs4_fill_super(s); | 2829 | nfs4_fill_super(s); |
2830 | nfs_fscache_get_super_cookie(s, NULL, data); | ||
2808 | } | 2831 | } |
2809 | 2832 | ||
2810 | mntroot = nfs4_get_root(s, &mntfh); | 2833 | mntroot = nfs4_get_root(s, &mntfh); |