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