diff options
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r-- | fs/nfs/super.c | 297 |
1 files changed, 222 insertions, 75 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 0b0c72a072ff..22c49c02897d 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -45,6 +45,8 @@ | |||
45 | #include <linux/nfs_idmap.h> | 45 | #include <linux/nfs_idmap.h> |
46 | #include <linux/vfs.h> | 46 | #include <linux/vfs.h> |
47 | #include <linux/inet.h> | 47 | #include <linux/inet.h> |
48 | #include <linux/in6.h> | ||
49 | #include <net/ipv6.h> | ||
48 | #include <linux/nfs_xdr.h> | 50 | #include <linux/nfs_xdr.h> |
49 | #include <linux/magic.h> | 51 | #include <linux/magic.h> |
50 | #include <linux/parser.h> | 52 | #include <linux/parser.h> |
@@ -83,11 +85,11 @@ enum { | |||
83 | Opt_actimeo, | 85 | Opt_actimeo, |
84 | Opt_namelen, | 86 | Opt_namelen, |
85 | Opt_mountport, | 87 | Opt_mountport, |
86 | Opt_mountprog, Opt_mountvers, | 88 | Opt_mountvers, |
87 | Opt_nfsprog, Opt_nfsvers, | 89 | Opt_nfsvers, |
88 | 90 | ||
89 | /* Mount options that take string arguments */ | 91 | /* Mount options that take string arguments */ |
90 | Opt_sec, Opt_proto, Opt_mountproto, | 92 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, |
91 | Opt_addr, Opt_mountaddr, Opt_clientaddr, | 93 | Opt_addr, Opt_mountaddr, Opt_clientaddr, |
92 | 94 | ||
93 | /* Mount options that are ignored */ | 95 | /* Mount options that are ignored */ |
@@ -137,9 +139,7 @@ static match_table_t nfs_mount_option_tokens = { | |||
137 | { Opt_userspace, "retry=%u" }, | 139 | { Opt_userspace, "retry=%u" }, |
138 | { Opt_namelen, "namlen=%u" }, | 140 | { Opt_namelen, "namlen=%u" }, |
139 | { Opt_mountport, "mountport=%u" }, | 141 | { Opt_mountport, "mountport=%u" }, |
140 | { Opt_mountprog, "mountprog=%u" }, | ||
141 | { Opt_mountvers, "mountvers=%u" }, | 142 | { Opt_mountvers, "mountvers=%u" }, |
142 | { Opt_nfsprog, "nfsprog=%u" }, | ||
143 | { Opt_nfsvers, "nfsvers=%u" }, | 143 | { Opt_nfsvers, "nfsvers=%u" }, |
144 | { Opt_nfsvers, "vers=%u" }, | 144 | { Opt_nfsvers, "vers=%u" }, |
145 | 145 | ||
@@ -148,7 +148,7 @@ static match_table_t nfs_mount_option_tokens = { | |||
148 | { Opt_mountproto, "mountproto=%s" }, | 148 | { Opt_mountproto, "mountproto=%s" }, |
149 | { Opt_addr, "addr=%s" }, | 149 | { Opt_addr, "addr=%s" }, |
150 | { Opt_clientaddr, "clientaddr=%s" }, | 150 | { Opt_clientaddr, "clientaddr=%s" }, |
151 | { Opt_userspace, "mounthost=%s" }, | 151 | { Opt_mounthost, "mounthost=%s" }, |
152 | { Opt_mountaddr, "mountaddr=%s" }, | 152 | { Opt_mountaddr, "mountaddr=%s" }, |
153 | 153 | ||
154 | { Opt_err, NULL } | 154 | { Opt_err, NULL } |
@@ -202,6 +202,7 @@ static int nfs_get_sb(struct file_system_type *, int, const char *, void *, stru | |||
202 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, | 202 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, |
203 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 203 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
204 | static void nfs_kill_super(struct super_block *); | 204 | static void nfs_kill_super(struct super_block *); |
205 | static void nfs_put_super(struct super_block *); | ||
205 | 206 | ||
206 | static struct file_system_type nfs_fs_type = { | 207 | static struct file_system_type nfs_fs_type = { |
207 | .owner = THIS_MODULE, | 208 | .owner = THIS_MODULE, |
@@ -223,6 +224,7 @@ static const struct super_operations nfs_sops = { | |||
223 | .alloc_inode = nfs_alloc_inode, | 224 | .alloc_inode = nfs_alloc_inode, |
224 | .destroy_inode = nfs_destroy_inode, | 225 | .destroy_inode = nfs_destroy_inode, |
225 | .write_inode = nfs_write_inode, | 226 | .write_inode = nfs_write_inode, |
227 | .put_super = nfs_put_super, | ||
226 | .statfs = nfs_statfs, | 228 | .statfs = nfs_statfs, |
227 | .clear_inode = nfs_clear_inode, | 229 | .clear_inode = nfs_clear_inode, |
228 | .umount_begin = nfs_umount_begin, | 230 | .umount_begin = nfs_umount_begin, |
@@ -325,6 +327,28 @@ void __exit unregister_nfs_fs(void) | |||
325 | unregister_filesystem(&nfs_fs_type); | 327 | unregister_filesystem(&nfs_fs_type); |
326 | } | 328 | } |
327 | 329 | ||
330 | void nfs_sb_active(struct nfs_server *server) | ||
331 | { | ||
332 | atomic_inc(&server->active); | ||
333 | } | ||
334 | |||
335 | void nfs_sb_deactive(struct nfs_server *server) | ||
336 | { | ||
337 | if (atomic_dec_and_test(&server->active)) | ||
338 | wake_up(&server->active_wq); | ||
339 | } | ||
340 | |||
341 | static void nfs_put_super(struct super_block *sb) | ||
342 | { | ||
343 | struct nfs_server *server = NFS_SB(sb); | ||
344 | /* | ||
345 | * Make sure there are no outstanding ops to this server. | ||
346 | * If so, wait for them to finish before allowing the | ||
347 | * unmount to continue. | ||
348 | */ | ||
349 | wait_event(server->active_wq, atomic_read(&server->active) == 0); | ||
350 | } | ||
351 | |||
328 | /* | 352 | /* |
329 | * Deliver file system statistics to userspace | 353 | * Deliver file system statistics to userspace |
330 | */ | 354 | */ |
@@ -455,8 +479,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
455 | } | 479 | } |
456 | seq_printf(m, ",proto=%s", | 480 | seq_printf(m, ",proto=%s", |
457 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); | 481 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); |
458 | seq_printf(m, ",timeo=%lu", 10U * clp->retrans_timeo / HZ); | 482 | seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ); |
459 | seq_printf(m, ",retrans=%u", clp->retrans_count); | 483 | seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries); |
460 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); | 484 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); |
461 | } | 485 | } |
462 | 486 | ||
@@ -469,8 +493,9 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
469 | 493 | ||
470 | nfs_show_mount_options(m, nfss, 0); | 494 | nfs_show_mount_options(m, nfss, 0); |
471 | 495 | ||
472 | seq_printf(m, ",addr="NIPQUAD_FMT, | 496 | seq_printf(m, ",addr=%s", |
473 | NIPQUAD(nfss->nfs_client->cl_addr.sin_addr)); | 497 | rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient, |
498 | RPC_DISPLAY_ADDR)); | ||
474 | 499 | ||
475 | return 0; | 500 | return 0; |
476 | } | 501 | } |
@@ -507,7 +532,7 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
507 | seq_printf(m, ",namelen=%d", nfss->namelen); | 532 | seq_printf(m, ",namelen=%d", nfss->namelen); |
508 | 533 | ||
509 | #ifdef CONFIG_NFS_V4 | 534 | #ifdef CONFIG_NFS_V4 |
510 | if (nfss->nfs_client->cl_nfsversion == 4) { | 535 | if (nfss->nfs_client->rpc_ops->version == 4) { |
511 | seq_printf(m, "\n\tnfsv4:\t"); | 536 | seq_printf(m, "\n\tnfsv4:\t"); |
512 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); | 537 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); |
513 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); | 538 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); |
@@ -575,16 +600,40 @@ static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) | |||
575 | } | 600 | } |
576 | 601 | ||
577 | /* | 602 | /* |
578 | * Sanity-check a server address provided by the mount command | 603 | * Set the port number in an address. Be agnostic about the address family. |
604 | */ | ||
605 | static void nfs_set_port(struct sockaddr *sap, unsigned short port) | ||
606 | { | ||
607 | switch (sap->sa_family) { | ||
608 | case AF_INET: { | ||
609 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
610 | ap->sin_port = htons(port); | ||
611 | break; | ||
612 | } | ||
613 | case AF_INET6: { | ||
614 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
615 | ap->sin6_port = htons(port); | ||
616 | break; | ||
617 | } | ||
618 | } | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | * Sanity-check a server address provided by the mount command. | ||
623 | * | ||
624 | * Address family must be initialized, and address must not be | ||
625 | * the ANY address for that family. | ||
579 | */ | 626 | */ |
580 | static int nfs_verify_server_address(struct sockaddr *addr) | 627 | static int nfs_verify_server_address(struct sockaddr *addr) |
581 | { | 628 | { |
582 | switch (addr->sa_family) { | 629 | switch (addr->sa_family) { |
583 | case AF_INET: { | 630 | case AF_INET: { |
584 | struct sockaddr_in *sa = (struct sockaddr_in *) addr; | 631 | struct sockaddr_in *sa = (struct sockaddr_in *)addr; |
585 | if (sa->sin_addr.s_addr != INADDR_ANY) | 632 | return sa->sin_addr.s_addr != INADDR_ANY; |
586 | return 1; | 633 | } |
587 | break; | 634 | case AF_INET6: { |
635 | struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr; | ||
636 | return !ipv6_addr_any(sa); | ||
588 | } | 637 | } |
589 | } | 638 | } |
590 | 639 | ||
@@ -592,6 +641,40 @@ static int nfs_verify_server_address(struct sockaddr *addr) | |||
592 | } | 641 | } |
593 | 642 | ||
594 | /* | 643 | /* |
644 | * Parse string addresses passed in via a mount option, | ||
645 | * and construct a sockaddr based on the result. | ||
646 | * | ||
647 | * If address parsing fails, set the sockaddr's address | ||
648 | * family to AF_UNSPEC to force nfs_verify_server_address() | ||
649 | * to punt the mount. | ||
650 | */ | ||
651 | static void nfs_parse_server_address(char *value, | ||
652 | struct sockaddr *sap, | ||
653 | size_t *len) | ||
654 | { | ||
655 | if (strchr(value, ':')) { | ||
656 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
657 | u8 *addr = (u8 *)&ap->sin6_addr.in6_u; | ||
658 | |||
659 | ap->sin6_family = AF_INET6; | ||
660 | *len = sizeof(*ap); | ||
661 | if (in6_pton(value, -1, addr, '\0', NULL)) | ||
662 | return; | ||
663 | } else { | ||
664 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
665 | u8 *addr = (u8 *)&ap->sin_addr.s_addr; | ||
666 | |||
667 | ap->sin_family = AF_INET; | ||
668 | *len = sizeof(*ap); | ||
669 | if (in4_pton(value, -1, addr, '\0', NULL)) | ||
670 | return; | ||
671 | } | ||
672 | |||
673 | sap->sa_family = AF_UNSPEC; | ||
674 | *len = 0; | ||
675 | } | ||
676 | |||
677 | /* | ||
595 | * Error-check and convert a string of mount options from user space into | 678 | * Error-check and convert a string of mount options from user space into |
596 | * a data structure | 679 | * a data structure |
597 | */ | 680 | */ |
@@ -599,6 +682,7 @@ static int nfs_parse_mount_options(char *raw, | |||
599 | struct nfs_parsed_mount_data *mnt) | 682 | struct nfs_parsed_mount_data *mnt) |
600 | { | 683 | { |
601 | char *p, *string; | 684 | char *p, *string; |
685 | unsigned short port = 0; | ||
602 | 686 | ||
603 | if (!raw) { | 687 | if (!raw) { |
604 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); | 688 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); |
@@ -701,7 +785,7 @@ static int nfs_parse_mount_options(char *raw, | |||
701 | return 0; | 785 | return 0; |
702 | if (option < 0 || option > 65535) | 786 | if (option < 0 || option > 65535) |
703 | return 0; | 787 | return 0; |
704 | mnt->nfs_server.address.sin_port = htons(option); | 788 | port = option; |
705 | break; | 789 | break; |
706 | case Opt_rsize: | 790 | case Opt_rsize: |
707 | if (match_int(args, &mnt->rsize)) | 791 | if (match_int(args, &mnt->rsize)) |
@@ -763,13 +847,6 @@ static int nfs_parse_mount_options(char *raw, | |||
763 | return 0; | 847 | return 0; |
764 | mnt->mount_server.port = option; | 848 | mnt->mount_server.port = option; |
765 | break; | 849 | break; |
766 | case Opt_mountprog: | ||
767 | if (match_int(args, &option)) | ||
768 | return 0; | ||
769 | if (option < 0) | ||
770 | return 0; | ||
771 | mnt->mount_server.program = option; | ||
772 | break; | ||
773 | case Opt_mountvers: | 850 | case Opt_mountvers: |
774 | if (match_int(args, &option)) | 851 | if (match_int(args, &option)) |
775 | return 0; | 852 | return 0; |
@@ -777,13 +854,6 @@ static int nfs_parse_mount_options(char *raw, | |||
777 | return 0; | 854 | return 0; |
778 | mnt->mount_server.version = option; | 855 | mnt->mount_server.version = option; |
779 | break; | 856 | break; |
780 | case Opt_nfsprog: | ||
781 | if (match_int(args, &option)) | ||
782 | return 0; | ||
783 | if (option < 0) | ||
784 | return 0; | ||
785 | mnt->nfs_server.program = option; | ||
786 | break; | ||
787 | case Opt_nfsvers: | 857 | case Opt_nfsvers: |
788 | if (match_int(args, &option)) | 858 | if (match_int(args, &option)) |
789 | return 0; | 859 | return 0; |
@@ -927,24 +997,32 @@ static int nfs_parse_mount_options(char *raw, | |||
927 | string = match_strdup(args); | 997 | string = match_strdup(args); |
928 | if (string == NULL) | 998 | if (string == NULL) |
929 | goto out_nomem; | 999 | goto out_nomem; |
930 | mnt->nfs_server.address.sin_family = AF_INET; | 1000 | nfs_parse_server_address(string, (struct sockaddr *) |
931 | mnt->nfs_server.address.sin_addr.s_addr = | 1001 | &mnt->nfs_server.address, |
932 | in_aton(string); | 1002 | &mnt->nfs_server.addrlen); |
933 | kfree(string); | 1003 | kfree(string); |
934 | break; | 1004 | break; |
935 | case Opt_clientaddr: | 1005 | case Opt_clientaddr: |
936 | string = match_strdup(args); | 1006 | string = match_strdup(args); |
937 | if (string == NULL) | 1007 | if (string == NULL) |
938 | goto out_nomem; | 1008 | goto out_nomem; |
1009 | kfree(mnt->client_address); | ||
939 | mnt->client_address = string; | 1010 | mnt->client_address = string; |
940 | break; | 1011 | break; |
1012 | case Opt_mounthost: | ||
1013 | string = match_strdup(args); | ||
1014 | if (string == NULL) | ||
1015 | goto out_nomem; | ||
1016 | kfree(mnt->mount_server.hostname); | ||
1017 | mnt->mount_server.hostname = string; | ||
1018 | break; | ||
941 | case Opt_mountaddr: | 1019 | case Opt_mountaddr: |
942 | string = match_strdup(args); | 1020 | string = match_strdup(args); |
943 | if (string == NULL) | 1021 | if (string == NULL) |
944 | goto out_nomem; | 1022 | goto out_nomem; |
945 | mnt->mount_server.address.sin_family = AF_INET; | 1023 | nfs_parse_server_address(string, (struct sockaddr *) |
946 | mnt->mount_server.address.sin_addr.s_addr = | 1024 | &mnt->mount_server.address, |
947 | in_aton(string); | 1025 | &mnt->mount_server.addrlen); |
948 | kfree(string); | 1026 | kfree(string); |
949 | break; | 1027 | break; |
950 | 1028 | ||
@@ -957,6 +1035,8 @@ static int nfs_parse_mount_options(char *raw, | |||
957 | } | 1035 | } |
958 | } | 1036 | } |
959 | 1037 | ||
1038 | nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, port); | ||
1039 | |||
960 | return 1; | 1040 | return 1; |
961 | 1041 | ||
962 | out_nomem: | 1042 | out_nomem: |
@@ -987,7 +1067,8 @@ out_unknown: | |||
987 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, | 1067 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
988 | struct nfs_fh *root_fh) | 1068 | struct nfs_fh *root_fh) |
989 | { | 1069 | { |
990 | struct sockaddr_in sin; | 1070 | struct sockaddr *sap = (struct sockaddr *)&args->mount_server.address; |
1071 | char *hostname; | ||
991 | int status; | 1072 | int status; |
992 | 1073 | ||
993 | if (args->mount_server.version == 0) { | 1074 | if (args->mount_server.version == 0) { |
@@ -997,25 +1078,32 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
997 | args->mount_server.version = NFS_MNT_VERSION; | 1078 | args->mount_server.version = NFS_MNT_VERSION; |
998 | } | 1079 | } |
999 | 1080 | ||
1081 | if (args->mount_server.hostname) | ||
1082 | hostname = args->mount_server.hostname; | ||
1083 | else | ||
1084 | hostname = args->nfs_server.hostname; | ||
1085 | |||
1000 | /* | 1086 | /* |
1001 | * Construct the mount server's address. | 1087 | * Construct the mount server's address. |
1002 | */ | 1088 | */ |
1003 | if (args->mount_server.address.sin_addr.s_addr != INADDR_ANY) | 1089 | if (args->mount_server.address.ss_family == AF_UNSPEC) { |
1004 | sin = args->mount_server.address; | 1090 | memcpy(sap, &args->nfs_server.address, |
1005 | else | 1091 | args->nfs_server.addrlen); |
1006 | sin = args->nfs_server.address; | 1092 | args->mount_server.addrlen = args->nfs_server.addrlen; |
1093 | } | ||
1094 | |||
1007 | /* | 1095 | /* |
1008 | * autobind will be used if mount_server.port == 0 | 1096 | * autobind will be used if mount_server.port == 0 |
1009 | */ | 1097 | */ |
1010 | sin.sin_port = htons(args->mount_server.port); | 1098 | nfs_set_port(sap, args->mount_server.port); |
1011 | 1099 | ||
1012 | /* | 1100 | /* |
1013 | * Now ask the mount server to map our export path | 1101 | * Now ask the mount server to map our export path |
1014 | * to a file handle. | 1102 | * to a file handle. |
1015 | */ | 1103 | */ |
1016 | status = nfs_mount((struct sockaddr *) &sin, | 1104 | status = nfs_mount(sap, |
1017 | sizeof(sin), | 1105 | args->mount_server.addrlen, |
1018 | args->nfs_server.hostname, | 1106 | hostname, |
1019 | args->nfs_server.export_path, | 1107 | args->nfs_server.export_path, |
1020 | args->mount_server.version, | 1108 | args->mount_server.version, |
1021 | args->mount_server.protocol, | 1109 | args->mount_server.protocol, |
@@ -1023,8 +1111,8 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1023 | if (status == 0) | 1111 | if (status == 0) |
1024 | return 0; | 1112 | return 0; |
1025 | 1113 | ||
1026 | dfprintk(MOUNT, "NFS: unable to mount server " NIPQUAD_FMT | 1114 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d", |
1027 | ", error %d\n", NIPQUAD(sin.sin_addr.s_addr), status); | 1115 | hostname, status); |
1028 | return status; | 1116 | return status; |
1029 | } | 1117 | } |
1030 | 1118 | ||
@@ -1043,9 +1131,6 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1043 | * | 1131 | * |
1044 | * + breaking back: trying proto=udp after proto=tcp, v2 after v3, | 1132 | * + breaking back: trying proto=udp after proto=tcp, v2 after v3, |
1045 | * mountproto=tcp after mountproto=udp, and so on | 1133 | * mountproto=tcp after mountproto=udp, and so on |
1046 | * | ||
1047 | * XXX: as far as I can tell, changing the NFS program number is not | ||
1048 | * supported in the NFS client. | ||
1049 | */ | 1134 | */ |
1050 | static int nfs_validate_mount_data(void *options, | 1135 | static int nfs_validate_mount_data(void *options, |
1051 | struct nfs_parsed_mount_data *args, | 1136 | struct nfs_parsed_mount_data *args, |
@@ -1069,9 +1154,7 @@ static int nfs_validate_mount_data(void *options, | |||
1069 | args->acdirmin = 30; | 1154 | args->acdirmin = 30; |
1070 | args->acdirmax = 60; | 1155 | args->acdirmax = 60; |
1071 | args->mount_server.protocol = XPRT_TRANSPORT_UDP; | 1156 | args->mount_server.protocol = XPRT_TRANSPORT_UDP; |
1072 | args->mount_server.program = NFS_MNT_PROGRAM; | ||
1073 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1157 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1074 | args->nfs_server.program = NFS_PROGRAM; | ||
1075 | 1158 | ||
1076 | switch (data->version) { | 1159 | switch (data->version) { |
1077 | case 1: | 1160 | case 1: |
@@ -1102,9 +1185,6 @@ static int nfs_validate_mount_data(void *options, | |||
1102 | memset(mntfh->data + mntfh->size, 0, | 1185 | memset(mntfh->data + mntfh->size, 0, |
1103 | sizeof(mntfh->data) - mntfh->size); | 1186 | sizeof(mntfh->data) - mntfh->size); |
1104 | 1187 | ||
1105 | if (!nfs_verify_server_address((struct sockaddr *) &data->addr)) | ||
1106 | goto out_no_address; | ||
1107 | |||
1108 | /* | 1188 | /* |
1109 | * Translate to nfs_parsed_mount_data, which nfs_fill_super | 1189 | * Translate to nfs_parsed_mount_data, which nfs_fill_super |
1110 | * can deal with. | 1190 | * can deal with. |
@@ -1119,7 +1199,14 @@ static int nfs_validate_mount_data(void *options, | |||
1119 | args->acregmax = data->acregmax; | 1199 | args->acregmax = data->acregmax; |
1120 | args->acdirmin = data->acdirmin; | 1200 | args->acdirmin = data->acdirmin; |
1121 | args->acdirmax = data->acdirmax; | 1201 | args->acdirmax = data->acdirmax; |
1122 | args->nfs_server.address = data->addr; | 1202 | |
1203 | memcpy(&args->nfs_server.address, &data->addr, | ||
1204 | sizeof(data->addr)); | ||
1205 | args->nfs_server.addrlen = sizeof(data->addr); | ||
1206 | if (!nfs_verify_server_address((struct sockaddr *) | ||
1207 | &args->nfs_server.address)) | ||
1208 | goto out_no_address; | ||
1209 | |||
1123 | if (!(data->flags & NFS_MOUNT_TCP)) | 1210 | if (!(data->flags & NFS_MOUNT_TCP)) |
1124 | args->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1211 | args->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
1125 | /* N.B. caller will free nfs_server.hostname in all cases */ | 1212 | /* N.B. caller will free nfs_server.hostname in all cases */ |
@@ -1322,15 +1409,50 @@ static int nfs_set_super(struct super_block *s, void *data) | |||
1322 | return ret; | 1409 | return ret; |
1323 | } | 1410 | } |
1324 | 1411 | ||
1412 | static int nfs_compare_super_address(struct nfs_server *server1, | ||
1413 | struct nfs_server *server2) | ||
1414 | { | ||
1415 | struct sockaddr *sap1, *sap2; | ||
1416 | |||
1417 | sap1 = (struct sockaddr *)&server1->nfs_client->cl_addr; | ||
1418 | sap2 = (struct sockaddr *)&server2->nfs_client->cl_addr; | ||
1419 | |||
1420 | if (sap1->sa_family != sap2->sa_family) | ||
1421 | return 0; | ||
1422 | |||
1423 | switch (sap1->sa_family) { | ||
1424 | case AF_INET: { | ||
1425 | struct sockaddr_in *sin1 = (struct sockaddr_in *)sap1; | ||
1426 | struct sockaddr_in *sin2 = (struct sockaddr_in *)sap2; | ||
1427 | if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) | ||
1428 | return 0; | ||
1429 | if (sin1->sin_port != sin2->sin_port) | ||
1430 | return 0; | ||
1431 | break; | ||
1432 | } | ||
1433 | case AF_INET6: { | ||
1434 | struct sockaddr_in6 *sin1 = (struct sockaddr_in6 *)sap1; | ||
1435 | struct sockaddr_in6 *sin2 = (struct sockaddr_in6 *)sap2; | ||
1436 | if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr)) | ||
1437 | return 0; | ||
1438 | if (sin1->sin6_port != sin2->sin6_port) | ||
1439 | return 0; | ||
1440 | break; | ||
1441 | } | ||
1442 | default: | ||
1443 | return 0; | ||
1444 | } | ||
1445 | |||
1446 | return 1; | ||
1447 | } | ||
1448 | |||
1325 | static int nfs_compare_super(struct super_block *sb, void *data) | 1449 | static int nfs_compare_super(struct super_block *sb, void *data) |
1326 | { | 1450 | { |
1327 | struct nfs_sb_mountdata *sb_mntdata = data; | 1451 | struct nfs_sb_mountdata *sb_mntdata = data; |
1328 | struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); | 1452 | struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); |
1329 | int mntflags = sb_mntdata->mntflags; | 1453 | int mntflags = sb_mntdata->mntflags; |
1330 | 1454 | ||
1331 | if (memcmp(&old->nfs_client->cl_addr, | 1455 | if (!nfs_compare_super_address(old, server)) |
1332 | &server->nfs_client->cl_addr, | ||
1333 | sizeof(old->nfs_client->cl_addr)) != 0) | ||
1334 | return 0; | 1456 | return 0; |
1335 | /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ | 1457 | /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ |
1336 | if (old->flags & NFS_MOUNT_UNSHARED) | 1458 | if (old->flags & NFS_MOUNT_UNSHARED) |
@@ -1400,6 +1522,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
1400 | 1522 | ||
1401 | out: | 1523 | out: |
1402 | kfree(data.nfs_server.hostname); | 1524 | kfree(data.nfs_server.hostname); |
1525 | kfree(data.mount_server.hostname); | ||
1403 | return error; | 1526 | return error; |
1404 | 1527 | ||
1405 | out_err_nosb: | 1528 | out_err_nosb: |
@@ -1528,12 +1651,35 @@ static void nfs4_fill_super(struct super_block *sb) | |||
1528 | } | 1651 | } |
1529 | 1652 | ||
1530 | /* | 1653 | /* |
1654 | * If the user didn't specify a port, set the port number to | ||
1655 | * the NFS version 4 default port. | ||
1656 | */ | ||
1657 | static void nfs4_default_port(struct sockaddr *sap) | ||
1658 | { | ||
1659 | switch (sap->sa_family) { | ||
1660 | case AF_INET: { | ||
1661 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
1662 | if (ap->sin_port == 0) | ||
1663 | ap->sin_port = htons(NFS_PORT); | ||
1664 | break; | ||
1665 | } | ||
1666 | case AF_INET6: { | ||
1667 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
1668 | if (ap->sin6_port == 0) | ||
1669 | ap->sin6_port = htons(NFS_PORT); | ||
1670 | break; | ||
1671 | } | ||
1672 | } | ||
1673 | } | ||
1674 | |||
1675 | /* | ||
1531 | * Validate NFSv4 mount options | 1676 | * Validate NFSv4 mount options |
1532 | */ | 1677 | */ |
1533 | static int nfs4_validate_mount_data(void *options, | 1678 | static int nfs4_validate_mount_data(void *options, |
1534 | struct nfs_parsed_mount_data *args, | 1679 | struct nfs_parsed_mount_data *args, |
1535 | const char *dev_name) | 1680 | const char *dev_name) |
1536 | { | 1681 | { |
1682 | struct sockaddr_in *ap; | ||
1537 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; | 1683 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; |
1538 | char *c; | 1684 | char *c; |
1539 | 1685 | ||
@@ -1554,18 +1700,21 @@ static int nfs4_validate_mount_data(void *options, | |||
1554 | 1700 | ||
1555 | switch (data->version) { | 1701 | switch (data->version) { |
1556 | case 1: | 1702 | case 1: |
1557 | if (data->host_addrlen != sizeof(args->nfs_server.address)) | 1703 | ap = (struct sockaddr_in *)&args->nfs_server.address; |
1704 | if (data->host_addrlen > sizeof(args->nfs_server.address)) | ||
1558 | goto out_no_address; | 1705 | goto out_no_address; |
1559 | if (copy_from_user(&args->nfs_server.address, | 1706 | if (data->host_addrlen == 0) |
1560 | data->host_addr, | 1707 | goto out_no_address; |
1561 | sizeof(args->nfs_server.address))) | 1708 | args->nfs_server.addrlen = data->host_addrlen; |
1709 | if (copy_from_user(ap, data->host_addr, data->host_addrlen)) | ||
1562 | return -EFAULT; | 1710 | return -EFAULT; |
1563 | if (args->nfs_server.address.sin_port == 0) | ||
1564 | args->nfs_server.address.sin_port = htons(NFS_PORT); | ||
1565 | if (!nfs_verify_server_address((struct sockaddr *) | 1711 | if (!nfs_verify_server_address((struct sockaddr *) |
1566 | &args->nfs_server.address)) | 1712 | &args->nfs_server.address)) |
1567 | goto out_no_address; | 1713 | goto out_no_address; |
1568 | 1714 | ||
1715 | nfs4_default_port((struct sockaddr *) | ||
1716 | &args->nfs_server.address); | ||
1717 | |||
1569 | switch (data->auth_flavourlen) { | 1718 | switch (data->auth_flavourlen) { |
1570 | case 0: | 1719 | case 0: |
1571 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1720 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
@@ -1623,6 +1772,9 @@ static int nfs4_validate_mount_data(void *options, | |||
1623 | &args->nfs_server.address)) | 1772 | &args->nfs_server.address)) |
1624 | return -EINVAL; | 1773 | return -EINVAL; |
1625 | 1774 | ||
1775 | nfs4_default_port((struct sockaddr *) | ||
1776 | &args->nfs_server.address); | ||
1777 | |||
1626 | switch (args->auth_flavor_len) { | 1778 | switch (args->auth_flavor_len) { |
1627 | case 0: | 1779 | case 0: |
1628 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1780 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
@@ -1643,21 +1795,16 @@ static int nfs4_validate_mount_data(void *options, | |||
1643 | len = c - dev_name; | 1795 | len = c - dev_name; |
1644 | if (len > NFS4_MAXNAMLEN) | 1796 | if (len > NFS4_MAXNAMLEN) |
1645 | return -ENAMETOOLONG; | 1797 | return -ENAMETOOLONG; |
1646 | args->nfs_server.hostname = kzalloc(len, GFP_KERNEL); | 1798 | /* N.B. caller will free nfs_server.hostname in all cases */ |
1647 | if (args->nfs_server.hostname == NULL) | 1799 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); |
1648 | return -ENOMEM; | ||
1649 | strncpy(args->nfs_server.hostname, dev_name, len - 1); | ||
1650 | 1800 | ||
1651 | c++; /* step over the ':' */ | 1801 | c++; /* step over the ':' */ |
1652 | len = strlen(c); | 1802 | len = strlen(c); |
1653 | if (len > NFS4_MAXPATHLEN) | 1803 | if (len > NFS4_MAXPATHLEN) |
1654 | return -ENAMETOOLONG; | 1804 | return -ENAMETOOLONG; |
1655 | args->nfs_server.export_path = kzalloc(len + 1, GFP_KERNEL); | 1805 | args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL); |
1656 | if (args->nfs_server.export_path == NULL) | ||
1657 | return -ENOMEM; | ||
1658 | strncpy(args->nfs_server.export_path, c, len); | ||
1659 | 1806 | ||
1660 | dprintk("MNTPATH: %s\n", args->nfs_server.export_path); | 1807 | dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path); |
1661 | 1808 | ||
1662 | if (args->client_address == NULL) | 1809 | if (args->client_address == NULL) |
1663 | goto out_no_client_address; | 1810 | goto out_no_client_address; |