From 0e8ff41ac29f4cf41084018e133c4758a1f73f73 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sun, 4 Sep 2005 01:29:00 +0000 Subject: [PATCH] Give the kernel a native NFS mount rpc capability for mounting NFS roots by splitting off the mount rpc code from the BOOTP code. The loader is no longer required to pass the nfs root mount file handle to the kernel. Pure tftp-based loaders with no knowledge of NFS can now pass a NFS root mount path to the kernel without having to pass a resolved NFS file handle. This change allows kernels booted from tftp loaders to have an NFS root without having to specify BOOTP (which sometimes doesn't work properly when done from both the loader and from the kernel). --- sys/conf/files | 5 +- sys/i386/i386/autoconf.c | 10 +- sys/platform/pc32/i386/autoconf.c | 10 +- sys/vfs/nfs/bootp_subr.c | 368 +------------------------ sys/vfs/nfs/nfs_mountrpc.c | 433 ++++++++++++++++++++++++++++++ sys/vfs/nfs/nfs_vfsops.c | 47 +++- sys/vfs/nfs/nfsmountrpc.h | 50 ++++ 7 files changed, 546 insertions(+), 377 deletions(-) create mode 100644 sys/vfs/nfs/nfs_mountrpc.c create mode 100644 sys/vfs/nfs/nfsmountrpc.h diff --git a/sys/conf/files b/sys/conf/files index 24eb4c2be0..78abb8ba19 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,5 +1,5 @@ # $FreeBSD: src/sys/conf/files,v 1.340.2.137 2003/06/04 17:10:30 sam Exp $ -# $DragonFly: src/sys/conf/files,v 1.104 2005/08/28 15:27:05 hsu Exp $ +# $DragonFly: src/sys/conf/files,v 1.105 2005/09/04 01:28:57 dillon Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -975,7 +975,8 @@ vfs/nfs/nfs_syscalls.c optional nfs vfs/nfs/nfs_vfsops.c optional nfs vfs/nfs/nfs_vnops.c optional nfs vfs/nfs/bootp_subr.c optional bootp -vfs/nfs/krpc_subr.c optional bootp +vfs/nfs/nfs_mountrpc.c optional nfs +vfs/nfs/krpc_subr.c optional nfs vfs/nwfs/nwfs_io.c optional nwfs vfs/nwfs/nwfs_ioctl.c optional nwfs vfs/nwfs/nwfs_node.c optional nwfs diff --git a/sys/i386/i386/autoconf.c b/sys/i386/i386/autoconf.c index 0879988b5c..394b7a4d27 100644 --- a/sys/i386/i386/autoconf.c +++ b/sys/i386/i386/autoconf.c @@ -35,7 +35,7 @@ * * from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91 * $FreeBSD: src/sys/i386/i386/autoconf.c,v 1.146.2.2 2001/06/07 06:05:58 dd Exp $ - * $DragonFly: src/sys/i386/i386/Attic/autoconf.c,v 1.17 2005/06/16 21:12:44 dillon Exp $ + * $DragonFly: src/sys/i386/i386/Attic/autoconf.c,v 1.18 2005/09/04 01:28:59 dillon Exp $ */ /* @@ -520,9 +520,13 @@ match_done: return; } nd->root_saddr.sin_port = htons(NFS_PORT); + + /* + * A tftp-only loader may pass NFS path information without a + * root handle. Generate a warning but continue configuring. + */ if (decode_nfshandle("boot.nfsroot.nfshandle", &nd->root_fh[0]) == 0) { - printf("PXE: no NFS handle\n"); - return; + printf("PXE: Warning, no NFS handle passed from loader\n"); } if ((cp = getenv("boot.nfsroot.path")) != NULL) strncpy(nd->root_hostnam, cp, MNAMELEN - 1); diff --git a/sys/platform/pc32/i386/autoconf.c b/sys/platform/pc32/i386/autoconf.c index 18fd706011..985aed639f 100644 --- a/sys/platform/pc32/i386/autoconf.c +++ b/sys/platform/pc32/i386/autoconf.c @@ -35,7 +35,7 @@ * * from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91 * $FreeBSD: src/sys/i386/i386/autoconf.c,v 1.146.2.2 2001/06/07 06:05:58 dd Exp $ - * $DragonFly: src/sys/platform/pc32/i386/autoconf.c,v 1.17 2005/06/16 21:12:44 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/i386/autoconf.c,v 1.18 2005/09/04 01:28:59 dillon Exp $ */ /* @@ -520,9 +520,13 @@ match_done: return; } nd->root_saddr.sin_port = htons(NFS_PORT); + + /* + * A tftp-only loader may pass NFS path information without a + * root handle. Generate a warning but continue configuring. + */ if (decode_nfshandle("boot.nfsroot.nfshandle", &nd->root_fh[0]) == 0) { - printf("PXE: no NFS handle\n"); - return; + printf("PXE: Warning, no NFS handle passed from loader\n"); } if ((cp = getenv("boot.nfsroot.path")) != NULL) strncpy(nd->root_hostnam, cp, MNAMELEN - 1); diff --git a/sys/vfs/nfs/bootp_subr.c b/sys/vfs/nfs/bootp_subr.c index fea8d3ea82..f190a73343 100644 --- a/sys/vfs/nfs/bootp_subr.c +++ b/sys/vfs/nfs/bootp_subr.c @@ -1,6 +1,3 @@ -/* $FreeBSD: src/sys/nfs/bootp_subr.c,v 1.20.2.9 2003/04/24 16:51:08 ambrisko Exp $ */ -/* $DragonFly: src/sys/vfs/nfs/bootp_subr.c,v 1.10 2004/06/21 05:58:01 dillon Exp $ */ - /* * Copyright (c) 1995 Gordon Ross, Adam Glass * Copyright (c) 1992 Regents of the University of California. @@ -38,9 +35,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * based on: - * nfs/krpc_subr.c - * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $ + * nfs/krpc_subr.c + * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $ + * $FreeBSD: src/sys/nfs/bootp_subr.c,v 1.20.2.9 2003/04/24 16:51:08 ambrisko Exp $ + * $DragonFly: src/sys/vfs/nfs/bootp_subr.c,v 1.11 2005/09/04 01:29:00 dillon Exp $ */ #include "opt_bootp.h" @@ -71,7 +69,7 @@ #include "nfsdiskless.h" #include "krpc.h" #include "xdr_subs.h" - +#include "nfsmountrpc.h" #define BOOTP_MIN_LEN 300 /* Minimum size of bootp udp packet */ @@ -220,19 +218,7 @@ SYSCTL_STRING(_kern, OID_AUTO, bootp_cookie, CTLFLAG_RD, bootp_cookie, 0, "Cookie (T134) supplied by bootp server"); /* mountd RPC */ -static int md_mount(struct sockaddr_in *mdsin, char *path, - u_char *fhp, int *fhsizep, - struct nfs_args *args,struct thread *td); -static int md_lookup_swap(struct sockaddr_in *mdsin,char *path, - u_char *fhp, int *fhsizep, - struct nfs_args *args, - struct thread *td); -static int setfs(struct sockaddr_in *addr, char *path, char *p); static int getdec(char **ptr); -static char *substr(char *a,char *b); -static void mountopts(struct nfs_args *args, char *p); -static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len); -static int xdr_int_decode(struct mbuf **ptr, int *iptr); static void print_in_addr(struct in_addr addr); static void print_sin_addr(struct sockaddr_in *addr); static void clear_sinaddr(struct sockaddr_in *sin); @@ -1167,150 +1153,6 @@ bootpc_adjust_interface(struct bootpc_ifcontext *ifctx, return 0; } - -static int -setfs(struct sockaddr_in *addr, char *path, char *p) -{ - unsigned int ip; - int val; - - ip = 0; - if (((val = getdec(&p)) < 0) || (val > 255)) - return 0; - ip = val << 24; - if (*p != '.') - return 0; - p++; - if (((val = getdec(&p)) < 0) || (val > 255)) - return 0; - ip |= (val << 16); - if (*p != '.') - return 0; - p++; - if (((val = getdec(&p)) < 0) || (val > 255)) - return 0; - ip |= (val << 8); - if (*p != '.') - return 0; - p++; - if (((val = getdec(&p)) < 0) || (val > 255)) - return 0; - ip |= val; - if (*p != ':') - return 0; - p++; - - addr->sin_addr.s_addr = htonl(ip); - addr->sin_len = sizeof(struct sockaddr_in); - addr->sin_family = AF_INET; - - strncpy(path, p, MNAMELEN - 1); - return 1; -} - - -static int -getdec(char **ptr) -{ - char *p; - int ret; - - p = *ptr; - ret = 0; - if ((*p < '0') || (*p > '9')) - return -1; - while ((*p >= '0') && (*p <= '9')) { - ret = ret * 10 + (*p - '0'); - p++; - } - *ptr = p; - return ret; -} - - -static char * -substr(char *a, char *b) -{ - char *loc1; - char *loc2; - - while (*a != '\0') { - loc1 = a; - loc2 = b; - while (*loc1 == *loc2++) { - if (*loc1 == '\0') - return 0; - loc1++; - if (*loc2 == '\0') - return loc1; - } - a++; - } - return 0; -} - - -static void -mountopts(struct nfs_args *args, char *p) -{ - char *tmp; - - args->version = NFS_ARGSVERSION; - args->rsize = 8192; - args->wsize = 8192; - args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT; - args->sotype = SOCK_DGRAM; - if (p == NULL) - return; - if ((tmp = (char *)substr(p, "rsize="))) - args->rsize = getdec(&tmp); - if ((tmp = (char *)substr(p, "wsize="))) - args->wsize = getdec(&tmp); - if ((tmp = (char *)substr(p, "intr"))) - args->flags |= NFSMNT_INT; - if ((tmp = (char *)substr(p, "soft"))) - args->flags |= NFSMNT_SOFT; - if ((tmp = (char *)substr(p, "noconn"))) - args->flags |= NFSMNT_NOCONN; - if ((tmp = (char *)substr(p, "tcp"))) - args->sotype = SOCK_STREAM; -} - - -static int -xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len) -{ - struct mbuf *m; - int alignedlen; - - m = *mptr; - alignedlen = ( len + 3 ) & ~3; - - if (m->m_len < alignedlen) { - m = m_pullup(m, alignedlen); - if (m == NULL) { - *mptr = NULL; - return EBADRPC; - } - } - bcopy(mtod(m, u_char *), buf, len); - m_adj(m, alignedlen); - *mptr = m; - return 0; -} - - -static int -xdr_int_decode(struct mbuf **mptr, int *iptr) -{ - u_int32_t i; - if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0) - return EBADRPC; - *iptr = fxdr_unsigned(u_int32_t, i); - return 0; -} - - static void print_sin_addr(struct sockaddr_in *sin) { @@ -1851,203 +1693,3 @@ out: free(gctx, M_TEMP); } - -/* - * RPC: mountd/mount - * Given a server pathname, get an NFS file handle. - * Also, sets sin->sin_port to the NFS service port. - */ -static int -md_mount(struct sockaddr_in *mdsin, /* mountd server address */ - char *path, - u_char *fhp, - int *fhsizep, - struct nfs_args *args, - struct thread *td) -{ - struct mbuf *m; - int error; - int authunixok; - int authcount; - int authver; - -#ifdef BOOTP_NFSV3 - /* First try NFS v3 */ - /* Get port number for MOUNTD. */ - error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3, - &mdsin->sin_port, td); - if (error == 0) { - m = xdr_string_encode(path, strlen(path)); - - /* Do RPC to mountd. */ - error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3, - RPCMNT_MOUNT, &m, NULL, td); - } - if (error == 0) { - args->flags |= NFSMNT_NFSV3; - } else { -#endif - /* Fallback to NFS v2 */ - - /* Get port number for MOUNTD. */ - error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, - &mdsin->sin_port, td); - if (error != 0) - return error; - - m = xdr_string_encode(path, strlen(path)); - - /* Do RPC to mountd. */ - error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, - RPCMNT_MOUNT, &m, NULL, td); - if (error != 0) - return error; /* message already freed */ - -#ifdef BOOTP_NFSV3 - } -#endif - - if (xdr_int_decode(&m, &error) != 0 || error != 0) - goto bad; - - if ((args->flags & NFSMNT_NFSV3) != 0) { - if (xdr_int_decode(&m, fhsizep) != 0 || - *fhsizep > NFSX_V3FHMAX || - *fhsizep <= 0) - goto bad; - } else - *fhsizep = NFSX_V2FH; - - if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0) - goto bad; - - if (args->flags & NFSMNT_NFSV3) { - if (xdr_int_decode(&m, &authcount) != 0) - goto bad; - authunixok = 0; - if (authcount < 0 || authcount > 100) - goto bad; - while (authcount > 0) { - if (xdr_int_decode(&m, &authver) != 0) - goto bad; - if (authver == RPCAUTH_UNIX) - authunixok = 1; - authcount--; - } - if (authunixok == 0) - goto bad; - } - - /* Set port number for NFS use. */ - error = krpc_portmap(mdsin, NFS_PROG, - (args->flags & - NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2, - &mdsin->sin_port, td); - - goto out; - -bad: - error = EBADRPC; - -out: - m_freem(m); - return error; -} - - -static int -md_lookup_swap(struct sockaddr_in *mdsin, /* mountd server address */ - char *path, - u_char *fhp, - int *fhsizep, - struct nfs_args *args, - struct thread *td) -{ - struct mbuf *m; - int error; - int size = -1; - int attribs_present; - int status; - union { - u_int32_t v2[17]; - u_int32_t v3[21]; - } fattribs; - - m = m_get(MB_WAIT,MT_DATA); - if (m == NULL) - return ENOBUFS; - - if ((args->flags & NFSMNT_NFSV3) != 0) { - *mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep); - bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep); - m->m_len = *fhsizep + sizeof(u_int32_t); - } else { - bcopy(fhp, mtod(m, u_char *), NFSX_V2FH); - m->m_len = NFSX_V2FH; - } - - m->m_next = xdr_string_encode(path, strlen(path)); - if (m->m_next == NULL) { - error = ENOBUFS; - goto out; - } - - /* Do RPC to nfsd. */ - if ((args->flags & NFSMNT_NFSV3) != 0) - error = krpc_call(mdsin, NFS_PROG, NFS_VER3, - NFSPROC_LOOKUP, &m, NULL, td); - else - error = krpc_call(mdsin, NFS_PROG, NFS_VER2, - NFSV2PROC_LOOKUP, &m, NULL, td); - if (error != 0) - return error; /* message already freed */ - - if (xdr_int_decode(&m, &status) != 0) - goto bad; - if (status != 0) { - error = ENOENT; - goto out; - } - - if ((args->flags & NFSMNT_NFSV3) != 0) { - if (xdr_int_decode(&m, fhsizep) != 0 || - *fhsizep > NFSX_V3FHMAX || - *fhsizep <= 0) - goto bad; - } else - *fhsizep = NFSX_V2FH; - - if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0) - goto bad; - - if ((args->flags & NFSMNT_NFSV3) != 0) { - if (xdr_int_decode(&m, &attribs_present) != 0) - goto bad; - if (attribs_present != 0) { - if (xdr_opaque_decode(&m, (u_char *) &fattribs.v3, - sizeof(u_int32_t) * 21) != 0) - goto bad; - size = fxdr_unsigned(u_int32_t, fattribs.v3[6]); - } - } else { - if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2, - sizeof(u_int32_t) * 17) != 0) - goto bad; - size = fxdr_unsigned(u_int32_t, fattribs.v2[5]); - } - - if (nfsv3_diskless.swap_nblks == 0 && size != -1) { - nfsv3_diskless.swap_nblks = size / 1024; - printf("md_lookup_swap: Swap size is %d KB\n", - nfsv3_diskless.swap_nblks); - } - - goto out; - -bad: - error = EBADRPC; - -out: - m_freem(m); - return error; -} diff --git a/sys/vfs/nfs/nfs_mountrpc.c b/sys/vfs/nfs/nfs_mountrpc.c new file mode 100644 index 0000000000..1445fa5a50 --- /dev/null +++ b/sys/vfs/nfs/nfs_mountrpc.c @@ -0,0 +1,433 @@ +/* + * Copyright (c) 1995 Gordon Ross, Adam Glass + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * nfs/krpc_subr.c + * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $ + * $FreeBSD: src/sys/nfs/bootp_subr.c,v 1.20.2.9 2003/04/24 16:51:08 ambrisko Exp $ + * $DragonFly: src/sys/vfs/nfs/nfs_mountrpc.c,v 1.1 2005/09/04 01:29:00 dillon Exp $ + */ +/* + * Procedures used by NFS_ROOT and BOOTP to do an NFS mount rpc to obtain + * the nfs root file handle for a NFS-based root mount point. This module + * is not used by normal operating code because the 'mount' command has a + * far more sophisticated implementation. + */ +#include "opt_bootp.h" +#include "opt_nfsroot.h" + +#if defined(BOOTP) || defined(NFS_ROOT) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "rpcv2.h" +#include "nfsproto.h" +#include "nfs.h" +#include "nfsdiskless.h" +#include "krpc.h" +#include "xdr_subs.h" +#include "nfsmountrpc.h" + +/* + * What is the longest we will wait before re-sending a request? + * Note this is also the frequency of "RPC timeout" messages. + * The re-send loop count sup linearly to this maximum, so the + * first complaint will happen after (1+2+3+4+5)=15 seconds. + */ + +extern struct nfsv3_diskless nfsv3_diskless; + +static int getdec(char **ptr); +static char *substr(char *a,char *b); +static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len); +static int xdr_int_decode(struct mbuf **ptr, int *iptr); + +void +mountopts(struct nfs_args *args, char *p) +{ + char *tmp; + + args->version = NFS_ARGSVERSION; + args->rsize = 8192; + args->wsize = 8192; + args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT; + args->sotype = SOCK_DGRAM; + if (p == NULL) + return; + if ((tmp = (char *)substr(p, "rsize="))) + args->rsize = getdec(&tmp); + if ((tmp = (char *)substr(p, "wsize="))) + args->wsize = getdec(&tmp); + if ((tmp = (char *)substr(p, "intr"))) + args->flags |= NFSMNT_INT; + if ((tmp = (char *)substr(p, "soft"))) + args->flags |= NFSMNT_SOFT; + if ((tmp = (char *)substr(p, "noconn"))) + args->flags |= NFSMNT_NOCONN; + if ((tmp = (char *)substr(p, "tcp"))) + args->sotype = SOCK_STREAM; +} + +/* + * RPC: mountd/mount + * Given a server pathname, get an NFS file handle. + * Also, sets sin->sin_port to the NFS service port. + */ +int +md_mount(struct sockaddr_in *mdsin, /* mountd server address */ + char *path, + u_char *fhp, + int *fhsizep, + struct nfs_args *args, + struct thread *td) +{ + struct mbuf *m; + int error; + int authunixok; + int authcount; + int authver; + +#ifdef BOOTP_NFSV3 + /* First try NFS v3 */ + /* Get port number for MOUNTD. */ + error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3, + &mdsin->sin_port, td); + if (error == 0) { + m = xdr_string_encode(path, strlen(path)); + + /* Do RPC to mountd. */ + error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3, + RPCMNT_MOUNT, &m, NULL, td); + } + if (error == 0) { + args->flags |= NFSMNT_NFSV3; + } else { +#endif + /* Fallback to NFS v2 */ + + /* Get port number for MOUNTD. */ + error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, + &mdsin->sin_port, td); + if (error != 0) + return error; + + m = xdr_string_encode(path, strlen(path)); + + /* Do RPC to mountd. */ + error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, + RPCMNT_MOUNT, &m, NULL, td); + if (error != 0) + return error; /* message already freed */ + +#ifdef BOOTP_NFSV3 + } +#endif + + if (xdr_int_decode(&m, &error) != 0 || error != 0) + goto bad; + + if ((args->flags & NFSMNT_NFSV3) != 0) { + if (xdr_int_decode(&m, fhsizep) != 0 || + *fhsizep > NFSX_V3FHMAX || + *fhsizep <= 0) + goto bad; + } else + *fhsizep = NFSX_V2FH; + + if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0) + goto bad; + + if (args->flags & NFSMNT_NFSV3) { + if (xdr_int_decode(&m, &authcount) != 0) + goto bad; + authunixok = 0; + if (authcount < 0 || authcount > 100) + goto bad; + while (authcount > 0) { + if (xdr_int_decode(&m, &authver) != 0) + goto bad; + if (authver == RPCAUTH_UNIX) + authunixok = 1; + authcount--; + } + if (authunixok == 0) + goto bad; + } + + /* Set port number for NFS use. */ + error = krpc_portmap(mdsin, NFS_PROG, + (args->flags & + NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2, + &mdsin->sin_port, td); + + goto out; + +bad: + error = EBADRPC; + +out: + m_freem(m); + return error; +} + +int +md_lookup_swap(struct sockaddr_in *mdsin, /* mountd server address */ + char *path, + u_char *fhp, + int *fhsizep, + struct nfs_args *args, + struct thread *td) +{ + struct mbuf *m; + int error; + int size = -1; + int attribs_present; + int status; + union { + u_int32_t v2[17]; + u_int32_t v3[21]; + } fattribs; + + m = m_get(MB_WAIT,MT_DATA); + if (m == NULL) + return ENOBUFS; + + if ((args->flags & NFSMNT_NFSV3) != 0) { + *mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep); + bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep); + m->m_len = *fhsizep + sizeof(u_int32_t); + } else { + bcopy(fhp, mtod(m, u_char *), NFSX_V2FH); + m->m_len = NFSX_V2FH; + } + + m->m_next = xdr_string_encode(path, strlen(path)); + if (m->m_next == NULL) { + error = ENOBUFS; + goto out; + } + + /* Do RPC to nfsd. */ + if ((args->flags & NFSMNT_NFSV3) != 0) + error = krpc_call(mdsin, NFS_PROG, NFS_VER3, + NFSPROC_LOOKUP, &m, NULL, td); + else + error = krpc_call(mdsin, NFS_PROG, NFS_VER2, + NFSV2PROC_LOOKUP, &m, NULL, td); + if (error != 0) + return error; /* message already freed */ + + if (xdr_int_decode(&m, &status) != 0) + goto bad; + if (status != 0) { + error = ENOENT; + goto out; + } + + if ((args->flags & NFSMNT_NFSV3) != 0) { + if (xdr_int_decode(&m, fhsizep) != 0 || + *fhsizep > NFSX_V3FHMAX || + *fhsizep <= 0) + goto bad; + } else + *fhsizep = NFSX_V2FH; + + if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0) + goto bad; + + if ((args->flags & NFSMNT_NFSV3) != 0) { + if (xdr_int_decode(&m, &attribs_present) != 0) + goto bad; + if (attribs_present != 0) { + if (xdr_opaque_decode(&m, (u_char *) &fattribs.v3, + sizeof(u_int32_t) * 21) != 0) + goto bad; + size = fxdr_unsigned(u_int32_t, fattribs.v3[6]); + } + } else { + if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2, + sizeof(u_int32_t) * 17) != 0) + goto bad; + size = fxdr_unsigned(u_int32_t, fattribs.v2[5]); + } + + if (nfsv3_diskless.swap_nblks == 0 && size != -1) { + nfsv3_diskless.swap_nblks = size / 1024; + printf("md_lookup_swap: Swap size is %d KB\n", + nfsv3_diskless.swap_nblks); + } + + goto out; + +bad: + error = EBADRPC; + +out: + m_freem(m); + return error; +} + +int +setfs(struct sockaddr_in *addr, char *path, char *p) +{ + unsigned int ip; + int val; + + ip = 0; + if (((val = getdec(&p)) < 0) || (val > 255)) + return 0; + ip = val << 24; + if (*p != '.') + return 0; + p++; + if (((val = getdec(&p)) < 0) || (val > 255)) + return 0; + ip |= (val << 16); + if (*p != '.') + return 0; + p++; + if (((val = getdec(&p)) < 0) || (val > 255)) + return 0; + ip |= (val << 8); + if (*p != '.') + return 0; + p++; + if (((val = getdec(&p)) < 0) || (val > 255)) + return 0; + ip |= val; + if (*p != ':') + return 0; + p++; + + addr->sin_addr.s_addr = htonl(ip); + addr->sin_len = sizeof(struct sockaddr_in); + addr->sin_family = AF_INET; + + strncpy(path, p, MNAMELEN - 1); + return 1; +} + +static int +getdec(char **ptr) +{ + char *p; + int ret; + + p = *ptr; + ret = 0; + if ((*p < '0') || (*p > '9')) + return -1; + while ((*p >= '0') && (*p <= '9')) { + ret = ret * 10 + (*p - '0'); + p++; + } + *ptr = p; + return ret; +} + +static char * +substr(char *a, char *b) +{ + char *loc1; + char *loc2; + + while (*a != '\0') { + loc1 = a; + loc2 = b; + while (*loc1 == *loc2++) { + if (*loc1 == '\0') + return 0; + loc1++; + if (*loc2 == '\0') + return loc1; + } + a++; + } + return 0; +} + +static int +xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len) +{ + struct mbuf *m; + int alignedlen; + + m = *mptr; + alignedlen = ( len + 3 ) & ~3; + + if (m->m_len < alignedlen) { + m = m_pullup(m, alignedlen); + if (m == NULL) { + *mptr = NULL; + return EBADRPC; + } + } + bcopy(mtod(m, u_char *), buf, len); + m_adj(m, alignedlen); + *mptr = m; + return 0; +} + +static int +xdr_int_decode(struct mbuf **mptr, int *iptr) +{ + u_int32_t i; + if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0) + return EBADRPC; + *iptr = fxdr_unsigned(u_int32_t, i); + return 0; +} + +#endif /* BOOTP && NFS_ROOT */ + diff --git a/sys/vfs/nfs/nfs_vfsops.c b/sys/vfs/nfs/nfs_vfsops.c index 0c16b43d93..94b4b8f7fd 100644 --- a/sys/vfs/nfs/nfs_vfsops.c +++ b/sys/vfs/nfs/nfs_vfsops.c @@ -35,10 +35,11 @@ * * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95 * $FreeBSD: src/sys/nfs/nfs_vfsops.c,v 1.91.2.7 2003/01/27 20:04:08 dillon Exp $ - * $DragonFly: src/sys/vfs/nfs/nfs_vfsops.c,v 1.30 2005/09/03 23:43:59 dillon Exp $ + * $DragonFly: src/sys/vfs/nfs/nfs_vfsops.c,v 1.31 2005/09/04 01:29:00 dillon Exp $ */ #include "opt_bootp.h" +#include "opt_nfsroot.h" #include #include @@ -72,6 +73,7 @@ #include "nfsm_subs.h" #include "nfsdiskless.h" #include "nqnfs.h" +#include "nfsmountrpc.h" extern int nfs_mountroot(struct mount *mp); extern void bootpc_init(void); @@ -248,13 +250,23 @@ nfs_convert_oargs(args, oargs) static void nfs_convert_diskless() { + int i; + bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif, sizeof(struct ifaliasreq)); bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway, sizeof(struct sockaddr_in)); nfs_convert_oargs(&nfsv3_diskless.swap_args,&nfs_diskless.swap_args); - nfsv3_diskless.swap_fhsize = NFSX_V2FH; + bcopy(nfs_diskless.swap_fh,nfsv3_diskless.swap_fh,NFSX_V2FH); + nfsv3_diskless.swap_fhsize = NFSX_V2FH; + for (i = NFSX_V2FH - 1; i >= 0; --i) { + if (nfs_diskless.swap_fh[i]) + break; + } + if (i < 0) + nfsv3_diskless.swap_fhsize = 0; + bcopy(&nfs_diskless.swap_saddr,&nfsv3_diskless.swap_saddr, sizeof(struct sockaddr_in)); bcopy(nfs_diskless.swap_hostnam,nfsv3_diskless.swap_hostnam, MNAMELEN); @@ -262,8 +274,16 @@ nfs_convert_diskless() bcopy(&nfs_diskless.swap_ucred, &nfsv3_diskless.swap_ucred, sizeof(struct ucred)); nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args); - nfsv3_diskless.root_fhsize = NFSX_V2FH; + bcopy(nfs_diskless.root_fh,nfsv3_diskless.root_fh,NFSX_V2FH); + nfsv3_diskless.root_fhsize = NFSX_V2FH; + for (i = NFSX_V2FH - 1; i >= 0; --i) { + if (nfs_diskless.root_fh[i]) + break; + } + if (i < 0) + nfsv3_diskless.root_fhsize = 0; + bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr, sizeof(struct sockaddr_in)); bcopy(nfs_diskless.root_hostnam,nfsv3_diskless.root_hostnam, MNAMELEN); @@ -592,8 +612,8 @@ nfs_mountdiskless(char *path, char *which, int mountflag, { struct mount *mp; struct sockaddr *nam; - int error; int didalloc = 0; + int error; mp = *mpp; @@ -604,11 +624,25 @@ nfs_mountdiskless(char *path, char *which, int mountflag, } didalloc = 1; } - mp->mnt_kern_flag = 0; mp->mnt_flag = mountflag; nam = dup_sockaddr((struct sockaddr *)sin); + +#if defined(BOOTP) || defined(NFS_ROOT) + if (args->fhsize == 0) { + printf("NFS_ROOT: No FH passed from loader, attempting mount rpc..."); + args->fhsize = 0; + error = md_mount(sin, which, args->fh, &args->fhsize, args, td); + if (error) { + printf("failed.\n"); + goto haderror; + } + printf("success!\n"); + } +#endif + if ((error = mountnfs(args, mp, nam, which, path, vpp)) != 0) { +haderror: printf("nfs_mountroot: mount %s on %s: %d", path, which, error); mp->mnt_vfc->vfc_refcount--; vfs_unbusy(mp, td); @@ -880,7 +914,7 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, } vfs_getnewfsid(mp); nmp->nm_mountp = mp; - if (argp->flags & NFSMNT_NQNFS) + if (argp->flags & NFSMNT_NQNFS) { /* * We have to set mnt_maxsymlink to a non-zero value so * that COMPAT_43 routines will know that we are setting @@ -888,6 +922,7 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, * unsuspecting binaries). */ mp->mnt_maxsymlinklen = 1; + } /* * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too diff --git a/sys/vfs/nfs/nfsmountrpc.h b/sys/vfs/nfs/nfsmountrpc.h new file mode 100644 index 0000000000..cc64cc5dfa --- /dev/null +++ b/sys/vfs/nfs/nfsmountrpc.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1995 Gordon Ross, Adam Glass + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly: src/sys/vfs/nfs/nfsmountrpc.h,v 1.1 2005/09/04 01:29:00 dillon Exp $ + */ + +int md_mount(struct sockaddr_in *mdsin, char *path, + u_char *fhp, int *fhsizep, + struct nfs_args *args,struct thread *td); +int md_lookup_swap(struct sockaddr_in *mdsin,char *path, + u_char *fhp, int *fhsizep, + struct nfs_args *args, + struct thread *td); +void mountopts(struct nfs_args *args, char *p); +int setfs(struct sockaddr_in *addr, char *path, char *p); + -- 2.41.0