diff options
author | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2013-09-20 23:51:45 +0000 |
---|---|---|
committer | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2013-09-20 23:51:45 +0000 |
commit | 73c84df03670a6c61322c047b414c24cd154957b (patch) | |
tree | 581b8cf14dedc884df705055b8c8c99b171bf14a /sys/nfs | |
parent | 34b536d0e8c8fe020c04ed923f62b0ff6c1f69c0 (diff) |
Add support for root on nfs using v3. Code adapted from NetBSD.
Tested on sparc by miod, octeon by aalm and armv7 by me.
miod ok.
Diffstat (limited to 'sys/nfs')
-rw-r--r-- | sys/nfs/nfs_boot.c | 102 | ||||
-rw-r--r-- | sys/nfs/nfs_vfsops.c | 33 | ||||
-rw-r--r-- | sys/nfs/nfsdiskless.h | 5 |
3 files changed, 88 insertions, 52 deletions
diff --git a/sys/nfs/nfs_boot.c b/sys/nfs/nfs_boot.c index 8f89fad49ec..3b1d26d9600 100644 --- a/sys/nfs/nfs_boot.c +++ b/sys/nfs/nfs_boot.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_boot.c,v 1.28 2013/09/12 13:12:33 deraadt Exp $ */ +/* $OpenBSD: nfs_boot.c,v 1.29 2013/09/20 23:51:44 fgsch Exp $ */ /* $NetBSD: nfs_boot.c,v 1.26 1996/05/07 02:51:25 thorpej Exp $ */ /* @@ -104,7 +104,7 @@ static int bp_getfile(struct sockaddr_in *bpsin, char *key, /* mountd RPC */ static int md_mount(struct sockaddr_in *mdsin, char *path, - u_char *fh); + struct nfs_args *argp); char *nfsbootdevname; @@ -268,11 +268,36 @@ int nfs_boot_getfh(struct sockaddr_in *bpsin, char *key, struct nfs_dlmount *ndmntp, int retries) { + struct nfs_args *args; char pathname[MAXPATHLEN]; char *sp, *dp, *endp; struct sockaddr_in *sin; int error; + args = &ndmntp->ndm_args; + + /* Initialize mount args. */ + bzero((caddr_t) args, sizeof(*args)); + args->addr = (struct sockaddr *)&ndmntp->ndm_saddr; + args->addrlen = args->addr->sa_len; + args->sotype = SOCK_DGRAM; + args->fh = ndmntp->ndm_fh; + args->hostname = ndmntp->ndm_host; + args->flags = NFSMNT_NFSV3; +#ifdef NFS_BOOT_OPTIONS + args->flags |= NFS_BOOT_OPTIONS; +#endif +#ifdef NFS_BOOT_RWSIZE + /* + * Reduce rsize,wsize for interfaces that consistently + * drop fragments of long UDP messages. (i.e. wd8003). + * You can always change these later via remount. + */ + args->flags |= NFSMNT_WSIZE | NFSMNT_RSIZE; + args->wsize = NFS_BOOT_RWSIZE; + args->rsize = NFS_BOOT_RWSIZE; +#endif + sin = &ndmntp->ndm_saddr; /* @@ -290,7 +315,7 @@ nfs_boot_getfh(struct sockaddr_in *bpsin, char *key, * Get file handle for "key" (root or swap) * using RPC to mountd/mount */ - error = md_mount(sin, pathname, ndmntp->ndm_fh); + error = md_mount(sin, pathname, args); if (error) { printf("nfs_boot: mountd %s, error=%d\n", key, error); return (error); @@ -298,9 +323,11 @@ nfs_boot_getfh(struct sockaddr_in *bpsin, char *key, /* Set port number for NFS use. */ /* XXX: NFS port is always 2049, right? */ - error = krpc_portmap(sin, NFS_PROG, NFS_VER2, &sin->sin_port); + error = krpc_portmap(sin, NFS_PROG, + (args->flags & NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2, + &sin->sin_port); if (error) { - printf("nfs_boot: portmap NFS/v2, error=%d\n", error); + printf("nfs_boot: portmap NFS, error=%d\n", error); return (error); } @@ -515,31 +542,49 @@ out: * mdsin: mountd server address */ static int -md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp) +md_mount(struct sockaddr_in *mdsin, char *path, struct nfs_args *argp) { /* The RPC structures */ struct rdata { u_int32_t errno; - u_int8_t fh[NFSX_V2FH]; + union { + u_int8_t v2fh[NFSX_V2FH]; + struct { + u_int32_t fhlen; + u_int8_t fh[1]; + } v3fh; + } fh; } *rdata; struct mbuf *m; - int error; + u_int8_t *fh; + int minlen, error; + int mntver; + + mntver = (argp->flags & NFSMNT_NFSV3) ? 3 : 2; + do { + error = krpc_portmap(mdsin, RPCPROG_MNT, mntver, + &mdsin->sin_port); + if (error) + continue; - /* Get port number for MOUNTD. */ - error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, - &mdsin->sin_port); - if (error) return error; + m = xdr_string_encode(path, strlen(path)); + if (m == NULL) + return ENOMEM; - m = xdr_string_encode(path, strlen(path)); - if (m == NULL) - return ENOMEM; + /* Do RPC to mountd. */ + error = krpc_call(mdsin, RPCPROG_MNT, mntver, + RPCMNT_MOUNT, &m, NULL, -1); - /* Do RPC to mountd. */ - error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, - RPCMNT_MOUNT, &m, NULL, -1); + if (error != EPROGMISMATCH) + break; + /* Try lower version of mountd. */ + } while (--mntver >= 1); if (error) return error; /* message already freed */ + if (mntver != 3) + argp->flags &= ~NFSMNT_NFSV3; + /* The reply might have only the errno. */ if (m->m_len < 4) goto bad; @@ -550,13 +595,26 @@ md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp) goto out; /* Have errno==0, so the fh must be there. */ - if (m->m_len < sizeof(*rdata)) { - m = m_pullup(m, sizeof(*rdata)); - if (m == NULL) + if (mntver == 3) { + argp->fhsize = fxdr_unsigned(u_int32_t, rdata->fh.v3fh.fhlen); + if (argp->fhsize > NFSX_V3FHMAX) goto bad; + minlen = 2 * sizeof(u_int32_t) + argp->fhsize; + } else { + argp->fhsize = NFSX_V2FH; + minlen = sizeof(u_int32_t) + argp->fhsize; + } + + if (m->m_len < minlen) { + m = m_pullup(m, minlen); + if (m == NULL) + return (EBADRPC); rdata = mtod(m, struct rdata *); } - bcopy(rdata->fh, fhp, NFSX_V2FH); + + fh = (mntver == 3) ? rdata->fh.v3fh.fh : rdata->fh.v2fh; + bcopy(fh, argp->fh, argp->fhsize); + goto out; bad: diff --git a/sys/nfs/nfs_vfsops.c b/sys/nfs/nfs_vfsops.c index d6a7cbb830b..fcf86b1569e 100644 --- a/sys/nfs/nfs_vfsops.c +++ b/sys/nfs/nfs_vfsops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_vfsops.c,v 1.97 2013/04/17 16:22:24 florian Exp $ */ +/* $OpenBSD: nfs_vfsops.c,v 1.98 2013/09/20 23:51:44 fgsch Exp $ */ /* $NetBSD: nfs_vfsops.c,v 1.46.4.1 1996/05/25 22:40:35 fvdl Exp $ */ /* @@ -365,7 +365,6 @@ nfs_mountroot(void) struct mount * nfs_mount_diskless(struct nfs_dlmount *ndmntp, char *mntname, int mntflag) { - struct nfs_args args; struct mount *mp; struct mbuf *m; int error; @@ -374,35 +373,13 @@ nfs_mount_diskless(struct nfs_dlmount *ndmntp, char *mntname, int mntflag) panic("nfs_mount_diskless: vfs_rootmountalloc failed"); mp->mnt_flag |= mntflag; - /* Initialize mount args. */ - bzero((caddr_t) &args, sizeof(args)); - args.addr = (struct sockaddr *)&ndmntp->ndm_saddr; - args.addrlen = args.addr->sa_len; - args.sotype = SOCK_DGRAM; - args.fh = ndmntp->ndm_fh; - args.fhsize = NFSX_V2FH; - args.hostname = ndmntp->ndm_host; - -#ifdef NFS_BOOT_OPTIONS - args.flags |= NFS_BOOT_OPTIONS; -#endif -#ifdef NFS_BOOT_RWSIZE - /* - * Reduce rsize,wsize for interfaces that consistently - * drop fragments of long UDP messages. (i.e. wd8003). - * You can always change these later via remount. - */ - args.flags |= NFSMNT_WSIZE | NFSMNT_RSIZE; - args.wsize = NFS_BOOT_RWSIZE; - args.rsize = NFS_BOOT_RWSIZE; -#endif - /* Get mbuf for server sockaddr. */ m = m_get(M_WAIT, MT_SONAME); - bcopy((caddr_t)args.addr, mtod(m, caddr_t), - (m->m_len = args.addr->sa_len)); + bcopy((caddr_t)ndmntp->ndm_args.addr, mtod(m, caddr_t), + (m->m_len = ndmntp->ndm_args.addr->sa_len)); - error = mountnfs(&args, mp, m, mntname, args.hostname); + error = mountnfs(&ndmntp->ndm_args, mp, m, mntname, + ndmntp->ndm_args.hostname); if (error) panic("nfs_mountroot: mount %s failed: %d", mntname, error); diff --git a/sys/nfs/nfsdiskless.h b/sys/nfs/nfsdiskless.h index 762ec2c6717..f379f26aa6e 100644 --- a/sys/nfs/nfsdiskless.h +++ b/sys/nfs/nfsdiskless.h @@ -1,4 +1,4 @@ -/* $OpenBSD: nfsdiskless.h,v 1.9 2013/04/17 16:22:24 florian Exp $ */ +/* $OpenBSD: nfsdiskless.h,v 1.10 2013/09/20 23:51:44 fgsch Exp $ */ /* $NetBSD: nfsdiskless.h,v 1.9 1996/02/18 11:54:00 fvdl Exp $ */ /* @@ -50,9 +50,10 @@ * client/server byte ordering differences. */ struct nfs_dlmount { + struct nfs_args ndm_args; struct sockaddr_in ndm_saddr; /* Address of file server */ char ndm_host[MNAMELEN]; /* Host name for mount pt */ - u_char ndm_fh[NFSX_V2FH]; /* The file's file handle */ + u_char ndm_fh[NFSX_V3FHMAX]; /* The file's file handle */ }; struct nfs_diskless { struct sockaddr_in nd_boot; /* Address of boot server */ |