summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2010-09-01 23:51:07 +0000
committerrmacklem <rmacklem@FreeBSD.org>2010-09-01 23:51:07 +0000
commit30b194f17b94c8deebc3f66b9d22a28e3a6f6b1a (patch)
tree68fc9d05a48263a37c5d9976d25058b8a6559bc7 /sys
parentbb06251a3b690fcc700e857bf3f756c4d0e07330 (diff)
downloadFreeBSD-src-30b194f17b94c8deebc3f66b9d22a28e3a6f6b1a.zip
FreeBSD-src-30b194f17b94c8deebc3f66b9d22a28e3a6f6b1a.tar.gz
Modify nfs_diskless.c to recognize the environment variable
boot.nfsroot.nfshandlelen and set the diskless root fs to use NFSv3 and this file handle length when it is set. If this environment variable is not set, the diskless root fs will use NFSv2 and the same defaults as before. This fixes the problem where the diskless nfs root fs had to be on a FreeBSD server for NFSv3 to work, because it did not know the correct file handle length and assumed the size used by FreeBSD. Until pxeboot and loader are replaced by ones built from commits coming soon, boot.nfsroot.nfshandlelen will not be set by them and the diskless root fs will use NFSv2 unless the /etc/fstab entry has the "nfsv3" option specified. Tested by: danny at cs.huji.ac.il MFC after: 2 weeks
Diffstat (limited to 'sys')
-rw-r--r--sys/nfsclient/nfs_diskless.c165
1 files changed, 120 insertions, 45 deletions
diff --git a/sys/nfsclient/nfs_diskless.c b/sys/nfsclient/nfs_diskless.c
index 2f91b9d..aacecff 100644
--- a/sys/nfsclient/nfs_diskless.c
+++ b/sys/nfsclient/nfs_diskless.c
@@ -58,7 +58,7 @@ __FBSDID("$FreeBSD$");
static int inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa);
static int hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa);
-static int decode_nfshandle(char *ev, u_char *fh);
+static int decode_nfshandle(char *ev, u_char *fh, int maxfh);
/*
* Validate/sanity check a rsize/wsize parameter.
@@ -143,20 +143,37 @@ nfs_parse_options(const char *envopts, struct nfs_args *nd)
* boot.nfsroot.server IP address of root filesystem server
* boot.nfsroot.path path of the root filesystem on server
* boot.nfsroot.nfshandle NFS handle for root filesystem on server
+ * boot.nfsroot.nfshandlelen and length of this handle (for NFSv3 only)
* boot.nfsroot.options NFS options for the root filesystem
*/
void
nfs_setup_diskless(void)
{
struct nfs_diskless *nd = &nfs_diskless;
+ struct nfsv3_diskless *nd3 = &nfsv3_diskless;
struct ifnet *ifp;
struct ifaddr *ifa;
struct sockaddr_dl *sdl, ourdl;
struct sockaddr_in myaddr, netmask;
char *cp;
+ int cnt, fhlen, is_nfsv3;
+ uint32_t len;
- if (nfs_diskless_valid)
+ if (nfs_diskless_valid != 0)
return;
+
+ /* get handle size. If this succeeds, it's an NFSv3 setup. */
+ if ((cp = getenv("boot.nfsroot.nfshandlelen")) != NULL) {
+ cnt = sscanf(cp, "%d", &len);
+ freeenv(cp);
+ if (cnt != 1 || len == 0 || len > NFSX_V3FHMAX) {
+ printf("nfs_diskless: bad NFS handle len\n");
+ return;
+ }
+ nd3->root_fhsize = len;
+ is_nfsv3 = 1;
+ } else
+ is_nfsv3 = 0;
/* set up interface */
if (inaddr_to_sockaddr("boot.netif.ip", &myaddr))
return;
@@ -164,11 +181,21 @@ nfs_setup_diskless(void)
printf("nfs_diskless: no netmask\n");
return;
}
- bcopy(&myaddr, &nd->myif.ifra_addr, sizeof(myaddr));
- bcopy(&myaddr, &nd->myif.ifra_broadaddr, sizeof(myaddr));
- ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
- myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
- bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask));
+ if (is_nfsv3 != 0) {
+ bcopy(&myaddr, &nd3->myif.ifra_addr, sizeof(myaddr));
+ bcopy(&myaddr, &nd3->myif.ifra_broadaddr, sizeof(myaddr));
+ ((struct sockaddr_in *)
+ &nd3->myif.ifra_broadaddr)->sin_addr.s_addr =
+ myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
+ bcopy(&netmask, &nd3->myif.ifra_mask, sizeof(netmask));
+ } else {
+ bcopy(&myaddr, &nd->myif.ifra_addr, sizeof(myaddr));
+ bcopy(&myaddr, &nd->myif.ifra_broadaddr, sizeof(myaddr));
+ ((struct sockaddr_in *)
+ &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
+ myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
+ bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask));
+ }
if (hwaddr_to_sockaddr("boot.netif.hwaddr", &ourdl)) {
printf("nfs_diskless: no hardware address\n");
@@ -196,46 +223,94 @@ nfs_setup_diskless(void)
return; /* no matching interface */
match_done:
setenv("boot.netif.name", ifp->if_xname);
- strlcpy(nd->myif.ifra_name, ifp->if_xname, sizeof(nd->myif.ifra_name));
+ if (is_nfsv3 != 0) {
+ strlcpy(nd3->myif.ifra_name, ifp->if_xname,
+ sizeof(nd3->myif.ifra_name));
- /* set up gateway */
- inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway);
+ /* set up gateway */
+ inaddr_to_sockaddr("boot.netif.gateway", &nd3->mygateway);
- /* set up root mount */
- nd->root_args.rsize = 8192; /* XXX tunable? */
- nd->root_args.wsize = 8192;
- nd->root_args.sotype = SOCK_STREAM;
- nd->root_args.flags = (NFSMNT_NFSV3 | NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT);
- if (inaddr_to_sockaddr("boot.nfsroot.server", &nd->root_saddr)) {
- printf("nfs_diskless: no server\n");
- return;
- }
- nd->root_saddr.sin_port = htons(NFS_PORT);
- if (decode_nfshandle("boot.nfsroot.nfshandle", &nd->root_fh[0]) == 0) {
- printf("nfs_diskless: no NFS handle\n");
- return;
- }
- if ((cp = getenv("boot.nfsroot.path")) != NULL) {
- strncpy(nd->root_hostnam, cp, MNAMELEN - 1);
- freeenv(cp);
- }
- if ((cp = getenv("boot.nfsroot.options")) != NULL) {
- struct nfs_args args;
+ /* set up root mount */
+ nd3->root_args.rsize = 32768; /* XXX tunable? */
+ nd3->root_args.wsize = 32768;
+ nd3->root_args.sotype = SOCK_STREAM;
+ nd3->root_args.flags = (NFSMNT_NFSV3 | NFSMNT_WSIZE |
+ NFSMNT_RSIZE | NFSMNT_RESVPORT);
+ if (inaddr_to_sockaddr("boot.nfsroot.server",
+ &nd3->root_saddr)) {
+ printf("nfs_diskless: no server\n");
+ return;
+ }
+ nd3->root_saddr.sin_port = htons(NFS_PORT);
+ fhlen = decode_nfshandle("boot.nfsroot.nfshandle",
+ &nd3->root_fh[0], NFSX_V3FHMAX);
+ if (fhlen == 0) {
+ printf("nfs_diskless: no NFS handle\n");
+ return;
+ }
+ if (fhlen != nd3->root_fhsize) {
+ printf("nfs_diskless: bad NFS handle len=%d\n", fhlen);
+ return;
+ }
+ if ((cp = getenv("boot.nfsroot.path")) != NULL) {
+ strncpy(nd3->root_hostnam, cp, MNAMELEN - 1);
+ freeenv(cp);
+ }
+ if ((cp = getenv("boot.nfsroot.options")) != NULL) {
+ nfs_parse_options(cp, &nd3->root_args);
+ freeenv(cp);
+ }
+
+ nfs_diskless_valid = 3;
+ } else {
+ strlcpy(nd->myif.ifra_name, ifp->if_xname,
+ sizeof(nd->myif.ifra_name));
+
+ /* set up gateway */
+ inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway);
- /* XXX yech, convert between old and current arg format */
- args.flags = nd->root_args.flags;
- args.sotype = nd->root_args.sotype;
- args.rsize = nd->root_args.rsize;
- args.wsize = nd->root_args.wsize;
- nfs_parse_options(cp, &args);
- nd->root_args.flags = args.flags;
- nd->root_args.sotype = args.sotype;
- nd->root_args.rsize = args.rsize;
- nd->root_args.wsize = args.wsize;
- freeenv(cp);
+ /* set up root mount */
+ nd->root_args.rsize = 8192; /* XXX tunable? */
+ nd->root_args.wsize = 8192;
+ nd->root_args.sotype = SOCK_STREAM;
+ nd->root_args.flags = (NFSMNT_WSIZE |
+ NFSMNT_RSIZE | NFSMNT_RESVPORT);
+ if (inaddr_to_sockaddr("boot.nfsroot.server",
+ &nd->root_saddr)) {
+ printf("nfs_diskless: no server\n");
+ return;
+ }
+ nd->root_saddr.sin_port = htons(NFS_PORT);
+ if (decode_nfshandle("boot.nfsroot.nfshandle",
+ &nd->root_fh[0], NFSX_V2FH) == 0) {
+ printf("nfs_diskless: no NFS handle\n");
+ return;
+ }
+ if ((cp = getenv("boot.nfsroot.path")) != NULL) {
+ strncpy(nd->root_hostnam, cp, MNAMELEN - 1);
+ freeenv(cp);
+ }
+ if ((cp = getenv("boot.nfsroot.options")) != NULL) {
+ struct nfs_args args;
+
+ /*
+ * XXX yech, convert between old and current
+ * arg format
+ */
+ args.flags = nd->root_args.flags;
+ args.sotype = nd->root_args.sotype;
+ args.rsize = nd->root_args.rsize;
+ args.wsize = nd->root_args.wsize;
+ nfs_parse_options(cp, &args);
+ nd->root_args.flags = args.flags;
+ nd->root_args.sotype = args.sotype;
+ nd->root_args.rsize = args.rsize;
+ nd->root_args.wsize = args.wsize;
+ freeenv(cp);
+ }
+
+ nfs_diskless_valid = 1;
}
-
- nfs_diskless_valid = 1;
}
static int
@@ -289,7 +364,7 @@ hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa)
}
static int
-decode_nfshandle(char *ev, u_char *fh)
+decode_nfshandle(char *ev, u_char *fh, int maxfh)
{
u_char *cp, *ep;
int len, val;
@@ -315,7 +390,7 @@ decode_nfshandle(char *ev, u_char *fh)
*(fh++) = val;
len++;
cp += 2;
- if (len > NFSX_V2FH) {
+ if (len > maxfh) {
freeenv(ep);
return (0);
}
OpenPOWER on IntegriCloud