diff options
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; |
