aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/super.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r--fs/nfs/super.c297
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
202static int nfs_xdev_get_sb(struct file_system_type *fs_type, 202static 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);
204static void nfs_kill_super(struct super_block *); 204static void nfs_kill_super(struct super_block *);
205static void nfs_put_super(struct super_block *);
205 206
206static struct file_system_type nfs_fs_type = { 207static 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
330void nfs_sb_active(struct nfs_server *server)
331{
332 atomic_inc(&server->active);
333}
334
335void nfs_sb_deactive(struct nfs_server *server)
336{
337 if (atomic_dec_and_test(&server->active))
338 wake_up(&server->active_wq);
339}
340
341static 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 */
605static 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 */
580static int nfs_verify_server_address(struct sockaddr *addr) 627static 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 */
651static 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
962out_nomem: 1042out_nomem:
@@ -987,7 +1067,8 @@ out_unknown:
987static int nfs_try_mount(struct nfs_parsed_mount_data *args, 1067static 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 */
1050static int nfs_validate_mount_data(void *options, 1135static 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
1412static 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
1325static int nfs_compare_super(struct super_block *sb, void *data) 1449static 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
1401out: 1523out:
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
1405out_err_nosb: 1528out_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 */
1657static 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 */
1533static int nfs4_validate_mount_data(void *options, 1678static 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;