diff options
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r-- | fs/nfs/super.c | 451 |
1 files changed, 233 insertions, 218 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 0b4cbdc60abd..867f70504531 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, |
@@ -742,127 +747,23 @@ static int nfs_verify_server_address(struct sockaddr *addr) | |||
742 | } | 747 | } |
743 | } | 748 | } |
744 | 749 | ||
750 | dfprintk(MOUNT, "NFS: Invalid IP address specified\n"); | ||
745 | return 0; | 751 | return 0; |
746 | } | 752 | } |
747 | 753 | ||
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 | /* | 754 | /* |
846 | * Construct a sockaddr based on the contents of a string that contains | 755 | * Select between a default port value and a user-specified port value. |
847 | * an IP address in presentation format. | 756 | * 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 | */ | 757 | */ |
852 | void nfs_parse_ip_address(char *string, size_t str_len, | 758 | static void nfs_set_default_port(struct sockaddr *sap, const int parsed_port, |
853 | struct sockaddr *sap, size_t *addr_len) | 759 | const unsigned short default_port) |
854 | { | 760 | { |
855 | unsigned int i, colons; | 761 | unsigned short port = default_port; |
856 | 762 | ||
857 | colons = 0; | 763 | if (parsed_port != NFS_UNSPEC_PORT) |
858 | for (i = 0; i < str_len; i++) | 764 | port = parsed_port; |
859 | if (string[i] == ':') | ||
860 | colons++; | ||
861 | 765 | ||
862 | if (colons >= 2) | 766 | 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 | } | 767 | } |
867 | 768 | ||
868 | /* | 769 | /* |
@@ -904,8 +805,6 @@ static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt) | |||
904 | 805 | ||
905 | /* | 806 | /* |
906 | * Parse the value of the 'sec=' option. | 807 | * Parse the value of the 'sec=' option. |
907 | * | ||
908 | * The flavor_len setting is for v4 mounts. | ||
909 | */ | 808 | */ |
910 | static int nfs_parse_security_flavors(char *value, | 809 | static int nfs_parse_security_flavors(char *value, |
911 | struct nfs_parsed_mount_data *mnt) | 810 | struct nfs_parsed_mount_data *mnt) |
@@ -916,53 +815,43 @@ static int nfs_parse_security_flavors(char *value, | |||
916 | 815 | ||
917 | switch (match_token(value, nfs_secflavor_tokens, args)) { | 816 | switch (match_token(value, nfs_secflavor_tokens, args)) { |
918 | case Opt_sec_none: | 817 | case Opt_sec_none: |
919 | mnt->auth_flavor_len = 0; | ||
920 | mnt->auth_flavors[0] = RPC_AUTH_NULL; | 818 | mnt->auth_flavors[0] = RPC_AUTH_NULL; |
921 | break; | 819 | break; |
922 | case Opt_sec_sys: | 820 | case Opt_sec_sys: |
923 | mnt->auth_flavor_len = 0; | ||
924 | mnt->auth_flavors[0] = RPC_AUTH_UNIX; | 821 | mnt->auth_flavors[0] = RPC_AUTH_UNIX; |
925 | break; | 822 | break; |
926 | case Opt_sec_krb5: | 823 | case Opt_sec_krb5: |
927 | mnt->auth_flavor_len = 1; | ||
928 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; | 824 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; |
929 | break; | 825 | break; |
930 | case Opt_sec_krb5i: | 826 | case Opt_sec_krb5i: |
931 | mnt->auth_flavor_len = 1; | ||
932 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; | 827 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; |
933 | break; | 828 | break; |
934 | case Opt_sec_krb5p: | 829 | case Opt_sec_krb5p: |
935 | mnt->auth_flavor_len = 1; | ||
936 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; | 830 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; |
937 | break; | 831 | break; |
938 | case Opt_sec_lkey: | 832 | case Opt_sec_lkey: |
939 | mnt->auth_flavor_len = 1; | ||
940 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; | 833 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; |
941 | break; | 834 | break; |
942 | case Opt_sec_lkeyi: | 835 | case Opt_sec_lkeyi: |
943 | mnt->auth_flavor_len = 1; | ||
944 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; | 836 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; |
945 | break; | 837 | break; |
946 | case Opt_sec_lkeyp: | 838 | case Opt_sec_lkeyp: |
947 | mnt->auth_flavor_len = 1; | ||
948 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; | 839 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; |
949 | break; | 840 | break; |
950 | case Opt_sec_spkm: | 841 | case Opt_sec_spkm: |
951 | mnt->auth_flavor_len = 1; | ||
952 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; | 842 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; |
953 | break; | 843 | break; |
954 | case Opt_sec_spkmi: | 844 | case Opt_sec_spkmi: |
955 | mnt->auth_flavor_len = 1; | ||
956 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; | 845 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; |
957 | break; | 846 | break; |
958 | case Opt_sec_spkmp: | 847 | case Opt_sec_spkmp: |
959 | mnt->auth_flavor_len = 1; | ||
960 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; | 848 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; |
961 | break; | 849 | break; |
962 | default: | 850 | default: |
963 | return 0; | 851 | return 0; |
964 | } | 852 | } |
965 | 853 | ||
854 | mnt->auth_flavor_len = 1; | ||
966 | return 1; | 855 | return 1; |
967 | } | 856 | } |
968 | 857 | ||
@@ -1001,7 +890,6 @@ static int nfs_parse_mount_options(char *raw, | |||
1001 | while ((p = strsep(&raw, ",")) != NULL) { | 890 | while ((p = strsep(&raw, ",")) != NULL) { |
1002 | substring_t args[MAX_OPT_ARGS]; | 891 | substring_t args[MAX_OPT_ARGS]; |
1003 | unsigned long option; | 892 | unsigned long option; |
1004 | int int_option; | ||
1005 | int token; | 893 | int token; |
1006 | 894 | ||
1007 | if (!*p) | 895 | if (!*p) |
@@ -1047,10 +935,18 @@ static int nfs_parse_mount_options(char *raw, | |||
1047 | break; | 935 | break; |
1048 | case Opt_v2: | 936 | case Opt_v2: |
1049 | mnt->flags &= ~NFS_MOUNT_VER3; | 937 | mnt->flags &= ~NFS_MOUNT_VER3; |
938 | mnt->version = 2; | ||
1050 | break; | 939 | break; |
1051 | case Opt_v3: | 940 | case Opt_v3: |
1052 | mnt->flags |= NFS_MOUNT_VER3; | 941 | mnt->flags |= NFS_MOUNT_VER3; |
942 | mnt->version = 3; | ||
1053 | break; | 943 | break; |
944 | #ifdef CONFIG_NFS_V4 | ||
945 | case Opt_v4: | ||
946 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
947 | mnt->version = 4; | ||
948 | break; | ||
949 | #endif | ||
1054 | case Opt_udp: | 950 | case Opt_udp: |
1055 | mnt->flags &= ~NFS_MOUNT_TCP; | 951 | mnt->flags &= ~NFS_MOUNT_TCP; |
1056 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 952 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
@@ -1264,20 +1160,33 @@ static int nfs_parse_mount_options(char *raw, | |||
1264 | switch (option) { | 1160 | switch (option) { |
1265 | case NFS2_VERSION: | 1161 | case NFS2_VERSION: |
1266 | mnt->flags &= ~NFS_MOUNT_VER3; | 1162 | mnt->flags &= ~NFS_MOUNT_VER3; |
1163 | mnt->version = 2; | ||
1267 | break; | 1164 | break; |
1268 | case NFS3_VERSION: | 1165 | case NFS3_VERSION: |
1269 | mnt->flags |= NFS_MOUNT_VER3; | 1166 | mnt->flags |= NFS_MOUNT_VER3; |
1167 | mnt->version = 3; | ||
1270 | break; | 1168 | break; |
1169 | #ifdef CONFIG_NFS_V4 | ||
1170 | case NFS4_VERSION: | ||
1171 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
1172 | mnt->version = 4; | ||
1173 | break; | ||
1174 | #endif | ||
1271 | default: | 1175 | default: |
1272 | goto out_invalid_value; | 1176 | goto out_invalid_value; |
1273 | } | 1177 | } |
1274 | break; | 1178 | break; |
1275 | case Opt_minorversion: | 1179 | case Opt_minorversion: |
1276 | if (match_int(args, &int_option)) | 1180 | string = match_strdup(args); |
1277 | return 0; | 1181 | if (string == NULL) |
1278 | if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION) | 1182 | goto out_nomem; |
1279 | return 0; | 1183 | rc = strict_strtoul(string, 10, &option); |
1280 | mnt->minorversion = int_option; | 1184 | kfree(string); |
1185 | if (rc != 0) | ||
1186 | goto out_invalid_value; | ||
1187 | if (option > NFS4_MAX_MINOR_VERSION) | ||
1188 | goto out_invalid_value; | ||
1189 | mnt->minorversion = option; | ||
1281 | break; | 1190 | break; |
1282 | 1191 | ||
1283 | /* | 1192 | /* |
@@ -1352,11 +1261,14 @@ static int nfs_parse_mount_options(char *raw, | |||
1352 | string = match_strdup(args); | 1261 | string = match_strdup(args); |
1353 | if (string == NULL) | 1262 | if (string == NULL) |
1354 | goto out_nomem; | 1263 | goto out_nomem; |
1355 | nfs_parse_ip_address(string, strlen(string), | 1264 | mnt->nfs_server.addrlen = |
1356 | (struct sockaddr *) | 1265 | rpc_pton(string, strlen(string), |
1357 | &mnt->nfs_server.address, | 1266 | (struct sockaddr *) |
1358 | &mnt->nfs_server.addrlen); | 1267 | &mnt->nfs_server.address, |
1268 | sizeof(mnt->nfs_server.address)); | ||
1359 | kfree(string); | 1269 | kfree(string); |
1270 | if (mnt->nfs_server.addrlen == 0) | ||
1271 | goto out_invalid_address; | ||
1360 | break; | 1272 | break; |
1361 | case Opt_clientaddr: | 1273 | case Opt_clientaddr: |
1362 | string = match_strdup(args); | 1274 | string = match_strdup(args); |
@@ -1376,11 +1288,14 @@ static int nfs_parse_mount_options(char *raw, | |||
1376 | string = match_strdup(args); | 1288 | string = match_strdup(args); |
1377 | if (string == NULL) | 1289 | if (string == NULL) |
1378 | goto out_nomem; | 1290 | goto out_nomem; |
1379 | nfs_parse_ip_address(string, strlen(string), | 1291 | mnt->mount_server.addrlen = |
1380 | (struct sockaddr *) | 1292 | rpc_pton(string, strlen(string), |
1381 | &mnt->mount_server.address, | 1293 | (struct sockaddr *) |
1382 | &mnt->mount_server.addrlen); | 1294 | &mnt->mount_server.address, |
1295 | sizeof(mnt->mount_server.address)); | ||
1383 | kfree(string); | 1296 | kfree(string); |
1297 | if (mnt->mount_server.addrlen == 0) | ||
1298 | goto out_invalid_address; | ||
1384 | break; | 1299 | break; |
1385 | case Opt_lookupcache: | 1300 | case Opt_lookupcache: |
1386 | string = match_strdup(args); | 1301 | string = match_strdup(args); |
@@ -1432,8 +1347,11 @@ static int nfs_parse_mount_options(char *raw, | |||
1432 | 1347 | ||
1433 | return 1; | 1348 | return 1; |
1434 | 1349 | ||
1350 | out_invalid_address: | ||
1351 | printk(KERN_INFO "NFS: bad IP address specified: %s\n", p); | ||
1352 | return 0; | ||
1435 | out_invalid_value: | 1353 | out_invalid_value: |
1436 | printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p); | 1354 | printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p); |
1437 | return 0; | 1355 | return 0; |
1438 | out_nomem: | 1356 | out_nomem: |
1439 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); | 1357 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); |
@@ -1445,13 +1363,60 @@ out_security_failure: | |||
1445 | } | 1363 | } |
1446 | 1364 | ||
1447 | /* | 1365 | /* |
1366 | * Match the requested auth flavors with the list returned by | ||
1367 | * the server. Returns zero and sets the mount's authentication | ||
1368 | * flavor on success; returns -EACCES if server does not support | ||
1369 | * the requested flavor. | ||
1370 | */ | ||
1371 | static int nfs_walk_authlist(struct nfs_parsed_mount_data *args, | ||
1372 | struct nfs_mount_request *request) | ||
1373 | { | ||
1374 | unsigned int i, j, server_authlist_len = *(request->auth_flav_len); | ||
1375 | |||
1376 | /* | ||
1377 | * Certain releases of Linux's mountd return an empty | ||
1378 | * flavor list. To prevent behavioral regression with | ||
1379 | * these servers (ie. rejecting mounts that used to | ||
1380 | * succeed), revert to pre-2.6.32 behavior (no checking) | ||
1381 | * if the returned flavor list is empty. | ||
1382 | */ | ||
1383 | if (server_authlist_len == 0) | ||
1384 | return 0; | ||
1385 | |||
1386 | /* | ||
1387 | * We avoid sophisticated negotiating here, as there are | ||
1388 | * plenty of cases where we can get it wrong, providing | ||
1389 | * either too little or too much security. | ||
1390 | * | ||
1391 | * RFC 2623, section 2.7 suggests we SHOULD prefer the | ||
1392 | * flavor listed first. However, some servers list | ||
1393 | * AUTH_NULL first. Our caller plants AUTH_SYS, the | ||
1394 | * preferred default, in args->auth_flavors[0] if user | ||
1395 | * didn't specify sec= mount option. | ||
1396 | */ | ||
1397 | for (i = 0; i < args->auth_flavor_len; i++) | ||
1398 | for (j = 0; j < server_authlist_len; j++) | ||
1399 | if (args->auth_flavors[i] == request->auth_flavs[j]) { | ||
1400 | dfprintk(MOUNT, "NFS: using auth flavor %d\n", | ||
1401 | request->auth_flavs[j]); | ||
1402 | args->auth_flavors[0] = request->auth_flavs[j]; | ||
1403 | return 0; | ||
1404 | } | ||
1405 | |||
1406 | dfprintk(MOUNT, "NFS: server does not support requested auth flavor\n"); | ||
1407 | nfs_umount(request); | ||
1408 | return -EACCES; | ||
1409 | } | ||
1410 | |||
1411 | /* | ||
1448 | * Use the remote server's MOUNT service to request the NFS file handle | 1412 | * Use the remote server's MOUNT service to request the NFS file handle |
1449 | * corresponding to the provided path. | 1413 | * corresponding to the provided path. |
1450 | */ | 1414 | */ |
1451 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, | 1415 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
1452 | struct nfs_fh *root_fh) | 1416 | struct nfs_fh *root_fh) |
1453 | { | 1417 | { |
1454 | unsigned int auth_flavor_len = 0; | 1418 | rpc_authflavor_t server_authlist[NFS_MAX_SECFLAVORS]; |
1419 | unsigned int server_authlist_len = ARRAY_SIZE(server_authlist); | ||
1455 | struct nfs_mount_request request = { | 1420 | struct nfs_mount_request request = { |
1456 | .sap = (struct sockaddr *) | 1421 | .sap = (struct sockaddr *) |
1457 | &args->mount_server.address, | 1422 | &args->mount_server.address, |
@@ -1459,7 +1424,8 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1459 | .protocol = args->mount_server.protocol, | 1424 | .protocol = args->mount_server.protocol, |
1460 | .fh = root_fh, | 1425 | .fh = root_fh, |
1461 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, | 1426 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, |
1462 | .auth_flav_len = &auth_flavor_len, | 1427 | .auth_flav_len = &server_authlist_len, |
1428 | .auth_flavs = server_authlist, | ||
1463 | }; | 1429 | }; |
1464 | int status; | 1430 | int status; |
1465 | 1431 | ||
@@ -1485,23 +1451,25 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1485 | args->mount_server.addrlen = args->nfs_server.addrlen; | 1451 | args->mount_server.addrlen = args->nfs_server.addrlen; |
1486 | } | 1452 | } |
1487 | request.salen = args->mount_server.addrlen; | 1453 | request.salen = args->mount_server.addrlen; |
1488 | 1454 | 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 | 1455 | ||
1494 | /* | 1456 | /* |
1495 | * Now ask the mount server to map our export path | 1457 | * Now ask the mount server to map our export path |
1496 | * to a file handle. | 1458 | * to a file handle. |
1497 | */ | 1459 | */ |
1498 | status = nfs_mount(&request); | 1460 | status = nfs_mount(&request); |
1499 | if (status == 0) | 1461 | if (status != 0) { |
1500 | return 0; | 1462 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", |
1463 | request.hostname, status); | ||
1464 | return status; | ||
1465 | } | ||
1501 | 1466 | ||
1502 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", | 1467 | /* |
1503 | request.hostname, status); | 1468 | * MNTv1 (NFSv2) does not support auth flavor negotiation. |
1504 | return status; | 1469 | */ |
1470 | if (args->mount_server.version != NFS_MNT3_VERSION) | ||
1471 | return 0; | ||
1472 | return nfs_walk_authlist(args, &request); | ||
1505 | } | 1473 | } |
1506 | 1474 | ||
1507 | static int nfs_parse_simple_hostname(const char *dev_name, | 1475 | static int nfs_parse_simple_hostname(const char *dev_name, |
@@ -1661,6 +1629,7 @@ static int nfs_validate_mount_data(void *options, | |||
1661 | const char *dev_name) | 1629 | const char *dev_name) |
1662 | { | 1630 | { |
1663 | struct nfs_mount_data *data = (struct nfs_mount_data *)options; | 1631 | struct nfs_mount_data *data = (struct nfs_mount_data *)options; |
1632 | struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; | ||
1664 | 1633 | ||
1665 | if (data == NULL) | 1634 | if (data == NULL) |
1666 | goto out_no_data; | 1635 | goto out_no_data; |
@@ -1672,10 +1641,12 @@ static int nfs_validate_mount_data(void *options, | |||
1672 | args->acregmax = NFS_DEF_ACREGMAX; | 1641 | args->acregmax = NFS_DEF_ACREGMAX; |
1673 | args->acdirmin = NFS_DEF_ACDIRMIN; | 1642 | args->acdirmin = NFS_DEF_ACDIRMIN; |
1674 | args->acdirmax = NFS_DEF_ACDIRMAX; | 1643 | args->acdirmax = NFS_DEF_ACDIRMAX; |
1675 | args->mount_server.port = 0; /* autobind unless user sets port */ | 1644 | args->mount_server.port = NFS_UNSPEC_PORT; |
1676 | args->nfs_server.port = 0; /* autobind unless user sets port */ | 1645 | args->nfs_server.port = NFS_UNSPEC_PORT; |
1677 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1646 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1678 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1647 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
1648 | args->auth_flavor_len = 1; | ||
1649 | args->minorversion = 0; | ||
1679 | 1650 | ||
1680 | switch (data->version) { | 1651 | switch (data->version) { |
1681 | case 1: | 1652 | case 1: |
@@ -1697,8 +1668,11 @@ static int nfs_validate_mount_data(void *options, | |||
1697 | if (data->root.size > NFS3_FHSIZE || data->root.size == 0) | 1668 | if (data->root.size > NFS3_FHSIZE || data->root.size == 0) |
1698 | goto out_invalid_fh; | 1669 | goto out_invalid_fh; |
1699 | mntfh->size = data->root.size; | 1670 | mntfh->size = data->root.size; |
1700 | } else | 1671 | args->version = 3; |
1672 | } else { | ||
1701 | mntfh->size = NFS2_FHSIZE; | 1673 | mntfh->size = NFS2_FHSIZE; |
1674 | args->version = 2; | ||
1675 | } | ||
1702 | 1676 | ||
1703 | 1677 | ||
1704 | memcpy(mntfh->data, data->root.data, mntfh->size); | 1678 | memcpy(mntfh->data, data->root.data, mntfh->size); |
@@ -1720,11 +1694,9 @@ static int nfs_validate_mount_data(void *options, | |||
1720 | args->acdirmin = data->acdirmin; | 1694 | args->acdirmin = data->acdirmin; |
1721 | args->acdirmax = data->acdirmax; | 1695 | args->acdirmax = data->acdirmax; |
1722 | 1696 | ||
1723 | memcpy(&args->nfs_server.address, &data->addr, | 1697 | memcpy(sap, &data->addr, sizeof(data->addr)); |
1724 | sizeof(data->addr)); | ||
1725 | args->nfs_server.addrlen = sizeof(data->addr); | 1698 | args->nfs_server.addrlen = sizeof(data->addr); |
1726 | if (!nfs_verify_server_address((struct sockaddr *) | 1699 | if (!nfs_verify_server_address(sap)) |
1727 | &args->nfs_server.address)) | ||
1728 | goto out_no_address; | 1700 | goto out_no_address; |
1729 | 1701 | ||
1730 | if (!(data->flags & NFS_MOUNT_TCP)) | 1702 | if (!(data->flags & NFS_MOUNT_TCP)) |
@@ -1772,12 +1744,18 @@ static int nfs_validate_mount_data(void *options, | |||
1772 | if (nfs_parse_mount_options((char *)options, args) == 0) | 1744 | if (nfs_parse_mount_options((char *)options, args) == 0) |
1773 | return -EINVAL; | 1745 | return -EINVAL; |
1774 | 1746 | ||
1775 | if (!nfs_verify_server_address((struct sockaddr *) | 1747 | if (!nfs_verify_server_address(sap)) |
1776 | &args->nfs_server.address)) | ||
1777 | goto out_no_address; | 1748 | goto out_no_address; |
1778 | 1749 | ||
1779 | nfs_set_port((struct sockaddr *)&args->nfs_server.address, | 1750 | if (args->version == 4) |
1780 | args->nfs_server.port); | 1751 | #ifdef CONFIG_NFS_V4 |
1752 | return nfs4_validate_text_mount_data(options, | ||
1753 | args, dev_name); | ||
1754 | #else | ||
1755 | goto out_v4_not_compiled; | ||
1756 | #endif | ||
1757 | |||
1758 | nfs_set_default_port(sap, args->nfs_server.port, 0); | ||
1781 | 1759 | ||
1782 | nfs_set_mount_transport_protocol(args); | 1760 | nfs_set_mount_transport_protocol(args); |
1783 | 1761 | ||
@@ -1825,6 +1803,12 @@ out_v3_not_compiled: | |||
1825 | return -EPROTONOSUPPORT; | 1803 | return -EPROTONOSUPPORT; |
1826 | #endif /* !CONFIG_NFS_V3 */ | 1804 | #endif /* !CONFIG_NFS_V3 */ |
1827 | 1805 | ||
1806 | #ifndef CONFIG_NFS_V4 | ||
1807 | out_v4_not_compiled: | ||
1808 | dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n"); | ||
1809 | return -EPROTONOSUPPORT; | ||
1810 | #endif /* !CONFIG_NFS_V4 */ | ||
1811 | |||
1828 | out_nomem: | 1812 | out_nomem: |
1829 | dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n"); | 1813 | dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n"); |
1830 | return -ENOMEM; | 1814 | return -ENOMEM; |
@@ -2120,6 +2104,14 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2120 | if (error < 0) | 2104 | if (error < 0) |
2121 | goto out; | 2105 | goto out; |
2122 | 2106 | ||
2107 | #ifdef CONFIG_NFS_V4 | ||
2108 | if (data->version == 4) { | ||
2109 | error = nfs4_try_mount(flags, dev_name, data, mnt); | ||
2110 | kfree(data->client_address); | ||
2111 | goto out; | ||
2112 | } | ||
2113 | #endif /* CONFIG_NFS_V4 */ | ||
2114 | |||
2123 | /* Get a volume representation */ | 2115 | /* Get a volume representation */ |
2124 | server = nfs_create_server(data, mntfh); | 2116 | server = nfs_create_server(data, mntfh); |
2125 | if (IS_ERR(server)) { | 2117 | if (IS_ERR(server)) { |
@@ -2317,6 +2309,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); | 2309 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3); |
2318 | } | 2310 | } |
2319 | 2311 | ||
2312 | static int nfs4_validate_text_mount_data(void *options, | ||
2313 | struct nfs_parsed_mount_data *args, | ||
2314 | const char *dev_name) | ||
2315 | { | ||
2316 | struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; | ||
2317 | |||
2318 | nfs_set_default_port(sap, args->nfs_server.port, NFS_PORT); | ||
2319 | |||
2320 | nfs_validate_transport_protocol(args); | ||
2321 | |||
2322 | nfs4_validate_mount_flags(args); | ||
2323 | |||
2324 | if (args->version != 4) { | ||
2325 | dfprintk(MOUNT, | ||
2326 | "NFS4: Illegal mount version\n"); | ||
2327 | return -EINVAL; | ||
2328 | } | ||
2329 | |||
2330 | if (args->auth_flavor_len > 1) { | ||
2331 | dfprintk(MOUNT, | ||
2332 | "NFS4: Too many RPC auth flavours specified\n"); | ||
2333 | return -EINVAL; | ||
2334 | } | ||
2335 | |||
2336 | if (args->client_address == NULL) { | ||
2337 | dfprintk(MOUNT, | ||
2338 | "NFS4: mount program didn't pass callback address\n"); | ||
2339 | return -EINVAL; | ||
2340 | } | ||
2341 | |||
2342 | return nfs_parse_devname(dev_name, | ||
2343 | &args->nfs_server.hostname, | ||
2344 | NFS4_MAXNAMLEN, | ||
2345 | &args->nfs_server.export_path, | ||
2346 | NFS4_MAXPATHLEN); | ||
2347 | } | ||
2348 | |||
2320 | /* | 2349 | /* |
2321 | * Validate NFSv4 mount options | 2350 | * Validate NFSv4 mount options |
2322 | */ | 2351 | */ |
@@ -2324,7 +2353,7 @@ static int nfs4_validate_mount_data(void *options, | |||
2324 | struct nfs_parsed_mount_data *args, | 2353 | struct nfs_parsed_mount_data *args, |
2325 | const char *dev_name) | 2354 | const char *dev_name) |
2326 | { | 2355 | { |
2327 | struct sockaddr_in *ap; | 2356 | struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; |
2328 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; | 2357 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; |
2329 | char *c; | 2358 | char *c; |
2330 | 2359 | ||
@@ -2337,23 +2366,22 @@ static int nfs4_validate_mount_data(void *options, | |||
2337 | args->acregmax = NFS_DEF_ACREGMAX; | 2366 | args->acregmax = NFS_DEF_ACREGMAX; |
2338 | args->acdirmin = NFS_DEF_ACDIRMIN; | 2367 | args->acdirmin = NFS_DEF_ACDIRMIN; |
2339 | args->acdirmax = NFS_DEF_ACDIRMAX; | 2368 | args->acdirmax = NFS_DEF_ACDIRMAX; |
2340 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | 2369 | args->nfs_server.port = NFS_UNSPEC_PORT; |
2341 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 2370 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
2342 | args->auth_flavor_len = 0; | 2371 | args->auth_flavor_len = 1; |
2372 | args->version = 4; | ||
2343 | args->minorversion = 0; | 2373 | args->minorversion = 0; |
2344 | 2374 | ||
2345 | switch (data->version) { | 2375 | switch (data->version) { |
2346 | case 1: | 2376 | case 1: |
2347 | ap = (struct sockaddr_in *)&args->nfs_server.address; | ||
2348 | if (data->host_addrlen > sizeof(args->nfs_server.address)) | 2377 | if (data->host_addrlen > sizeof(args->nfs_server.address)) |
2349 | goto out_no_address; | 2378 | goto out_no_address; |
2350 | if (data->host_addrlen == 0) | 2379 | if (data->host_addrlen == 0) |
2351 | goto out_no_address; | 2380 | goto out_no_address; |
2352 | args->nfs_server.addrlen = data->host_addrlen; | 2381 | args->nfs_server.addrlen = data->host_addrlen; |
2353 | if (copy_from_user(ap, data->host_addr, data->host_addrlen)) | 2382 | if (copy_from_user(sap, data->host_addr, data->host_addrlen)) |
2354 | return -EFAULT; | 2383 | return -EFAULT; |
2355 | if (!nfs_verify_server_address((struct sockaddr *) | 2384 | if (!nfs_verify_server_address(sap)) |
2356 | &args->nfs_server.address)) | ||
2357 | goto out_no_address; | 2385 | goto out_no_address; |
2358 | 2386 | ||
2359 | if (data->auth_flavourlen) { | 2387 | if (data->auth_flavourlen) { |
@@ -2399,39 +2427,14 @@ static int nfs4_validate_mount_data(void *options, | |||
2399 | nfs_validate_transport_protocol(args); | 2427 | nfs_validate_transport_protocol(args); |
2400 | 2428 | ||
2401 | break; | 2429 | break; |
2402 | default: { | 2430 | default: |
2403 | int status; | ||
2404 | |||
2405 | if (nfs_parse_mount_options((char *)options, args) == 0) | 2431 | if (nfs_parse_mount_options((char *)options, args) == 0) |
2406 | return -EINVAL; | 2432 | return -EINVAL; |
2407 | 2433 | ||
2408 | if (!nfs_verify_server_address((struct sockaddr *) | 2434 | if (!nfs_verify_server_address(sap)) |
2409 | &args->nfs_server.address)) | ||
2410 | return -EINVAL; | 2435 | return -EINVAL; |
2411 | 2436 | ||
2412 | nfs_set_port((struct sockaddr *)&args->nfs_server.address, | 2437 | 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 | } | 2438 | } |
2436 | 2439 | ||
2437 | return 0; | 2440 | return 0; |
@@ -2448,10 +2451,6 @@ out_inval_auth: | |||
2448 | out_no_address: | 2451 | out_no_address: |
2449 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); | 2452 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); |
2450 | return -EINVAL; | 2453 | return -EINVAL; |
2451 | |||
2452 | out_no_client_address: | ||
2453 | dfprintk(MOUNT, "NFS4: mount program didn't pass callback address\n"); | ||
2454 | return -EINVAL; | ||
2455 | } | 2454 | } |
2456 | 2455 | ||
2457 | /* | 2456 | /* |
@@ -2618,6 +2617,34 @@ out_err: | |||
2618 | return ret; | 2617 | return ret; |
2619 | } | 2618 | } |
2620 | 2619 | ||
2620 | static int nfs4_try_mount(int flags, const char *dev_name, | ||
2621 | struct nfs_parsed_mount_data *data, | ||
2622 | struct vfsmount *mnt) | ||
2623 | { | ||
2624 | char *export_path; | ||
2625 | struct vfsmount *root_mnt; | ||
2626 | int error; | ||
2627 | |||
2628 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); | ||
2629 | |||
2630 | export_path = data->nfs_server.export_path; | ||
2631 | data->nfs_server.export_path = "/"; | ||
2632 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data, | ||
2633 | data->nfs_server.hostname); | ||
2634 | data->nfs_server.export_path = export_path; | ||
2635 | |||
2636 | error = PTR_ERR(root_mnt); | ||
2637 | if (IS_ERR(root_mnt)) | ||
2638 | goto out; | ||
2639 | |||
2640 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | ||
2641 | |||
2642 | out: | ||
2643 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n", error, | ||
2644 | error != 0 ? " [error]" : ""); | ||
2645 | return error; | ||
2646 | } | ||
2647 | |||
2621 | /* | 2648 | /* |
2622 | * Get the superblock for an NFS4 mountpoint | 2649 | * Get the superblock for an NFS4 mountpoint |
2623 | */ | 2650 | */ |
@@ -2625,8 +2652,6 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2625 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 2652 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) |
2626 | { | 2653 | { |
2627 | struct nfs_parsed_mount_data *data; | 2654 | struct nfs_parsed_mount_data *data; |
2628 | char *export_path; | ||
2629 | struct vfsmount *root_mnt; | ||
2630 | int error = -ENOMEM; | 2655 | int error = -ENOMEM; |
2631 | 2656 | ||
2632 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 2657 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
@@ -2638,17 +2663,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2638 | if (error < 0) | 2663 | if (error < 0) |
2639 | goto out; | 2664 | goto out; |
2640 | 2665 | ||
2641 | export_path = data->nfs_server.export_path; | 2666 | 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 | 2667 | ||
2653 | out: | 2668 | out: |
2654 | kfree(data->client_address); | 2669 | kfree(data->client_address); |