Annotation of sys/nfs/nfs_vfsops.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: nfs_vfsops.c,v 1.66 2007/06/20 15:00:43 thib Exp $ */
! 2: /* $NetBSD: nfs_vfsops.c,v 1.46.4.1 1996/05/25 22:40:35 fvdl Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1989, 1993, 1995
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to Berkeley by
! 9: * Rick Macklem at The University of Guelph.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. Neither the name of the University nor the names of its contributors
! 20: * may be used to endorse or promote products derived from this software
! 21: * without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 33: * SUCH DAMAGE.
! 34: *
! 35: * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95
! 36: */
! 37:
! 38: #include <sys/param.h>
! 39: #include <sys/conf.h>
! 40: #include <sys/ioctl.h>
! 41: #include <sys/signal.h>
! 42: #include <sys/proc.h>
! 43: #include <sys/namei.h>
! 44: #include <sys/vnode.h>
! 45: #include <sys/kernel.h>
! 46: #include <sys/mount.h>
! 47: #include <sys/buf.h>
! 48: #include <sys/mbuf.h>
! 49: #include <sys/socket.h>
! 50: #include <sys/socketvar.h>
! 51: #include <sys/systm.h>
! 52: #include <sys/sysctl.h>
! 53:
! 54: #include <net/if.h>
! 55: #include <net/route.h>
! 56: #include <netinet/in.h>
! 57:
! 58: #include <nfs/rpcv2.h>
! 59: #include <nfs/nfsproto.h>
! 60: #include <nfs/nfsnode.h>
! 61: #include <nfs/nfs.h>
! 62: #include <nfs/nfsmount.h>
! 63: #include <nfs/xdr_subs.h>
! 64: #include <nfs/nfsm_subs.h>
! 65: #include <nfs/nfsdiskless.h>
! 66: #include <nfs/nfs_var.h>
! 67:
! 68: #define NQ_DEADTHRESH NQ_NEVERDEAD /* Default nm_deadthresh */
! 69: #define NQ_NEVERDEAD 9 /* Greater than max. nm_timeouts */
! 70:
! 71: extern struct nfsstats nfsstats;
! 72: extern int nfs_ticks;
! 73: extern u_int32_t nfs_procids[NFS_NPROCS];
! 74:
! 75: int nfs_sysctl(int *, u_int, void *, size_t *, void *, size_t, struct proc *);
! 76: int nfs_checkexp(struct mount *, struct mbuf *, int *, struct ucred **);
! 77: struct mount *nfs_mount_diskless(struct nfs_dlmount *, char *, int);
! 78:
! 79: /*
! 80: * nfs vfs operations.
! 81: */
! 82: const struct vfsops nfs_vfsops = {
! 83: nfs_mount,
! 84: nfs_start,
! 85: nfs_unmount,
! 86: nfs_root,
! 87: nfs_quotactl,
! 88: nfs_statfs,
! 89: nfs_sync,
! 90: nfs_vget,
! 91: nfs_fhtovp,
! 92: nfs_vptofh,
! 93: nfs_vfs_init,
! 94: nfs_sysctl,
! 95: nfs_checkexp
! 96: };
! 97:
! 98: #define TRUE 1
! 99: #define FALSE 0
! 100:
! 101: /*
! 102: * nfs statfs call
! 103: */
! 104: int
! 105: nfs_statfs(mp, sbp, p)
! 106: struct mount *mp;
! 107: struct statfs *sbp;
! 108: struct proc *p;
! 109: {
! 110: struct vnode *vp;
! 111: struct nfs_statfs *sfp = NULL;
! 112: caddr_t cp;
! 113: u_int32_t *tl;
! 114: int32_t t1, t2;
! 115: caddr_t bpos, dpos, cp2;
! 116: struct nfsmount *nmp = VFSTONFS(mp);
! 117: int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;
! 118: struct mbuf *mreq, *mrep = NULL, *md, *mb, *mb2;
! 119: struct ucred *cred;
! 120: struct nfsnode *np;
! 121: u_quad_t tquad;
! 122:
! 123: error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
! 124: if (error)
! 125: return (error);
! 126: vp = NFSTOV(np);
! 127: cred = crget();
! 128: cred->cr_ngroups = 0;
! 129: if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0)
! 130: (void)nfs_fsinfo(nmp, vp, cred, p);
! 131: nfsstats.rpccnt[NFSPROC_FSSTAT]++;
! 132: nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));
! 133: nfsm_fhtom(vp, v3);
! 134: nfsm_request(vp, NFSPROC_FSSTAT, p, cred);
! 135: if (v3)
! 136: nfsm_postop_attr(vp, retattr);
! 137: if (error) {
! 138: if (mrep != NULL)
! 139: m_free(mrep);
! 140: goto nfsmout;
! 141: }
! 142: nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
! 143: sbp->f_flags = nmp->nm_flag;
! 144: sbp->f_iosize = min(nmp->nm_rsize, nmp->nm_wsize);
! 145: if (v3) {
! 146: sbp->f_bsize = NFS_FABLKSIZE;
! 147: tquad = fxdr_hyper(&sfp->sf_tbytes);
! 148: sbp->f_blocks = (u_int32_t)(tquad / (u_quad_t)NFS_FABLKSIZE);
! 149: tquad = fxdr_hyper(&sfp->sf_fbytes);
! 150: sbp->f_bfree = (u_int32_t)(tquad / (u_quad_t)NFS_FABLKSIZE);
! 151: tquad = fxdr_hyper(&sfp->sf_abytes);
! 152: sbp->f_bavail = (int32_t)((quad_t)tquad / (quad_t)NFS_FABLKSIZE);
! 153: sbp->f_files = (fxdr_unsigned(int32_t,
! 154: sfp->sf_tfiles.nfsuquad[1]) & 0x7fffffff);
! 155: sbp->f_ffree = (fxdr_unsigned(int32_t,
! 156: sfp->sf_ffiles.nfsuquad[1]) & 0x7fffffff);
! 157: } else {
! 158: sbp->f_bsize = fxdr_unsigned(int32_t, sfp->sf_bsize);
! 159: sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks);
! 160: sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree);
! 161: sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail);
! 162: sbp->f_files = 0;
! 163: sbp->f_ffree = 0;
! 164: }
! 165: if (sbp != &mp->mnt_stat) {
! 166: bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
! 167: bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
! 168: bcopy(&mp->mnt_stat.mount_info.nfs_args,
! 169: &sbp->mount_info.nfs_args, sizeof(struct nfs_args));
! 170: }
! 171: strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);
! 172: nfsm_reqdone;
! 173: vrele(vp);
! 174: crfree(cred);
! 175: return (error);
! 176: }
! 177:
! 178: /*
! 179: * nfs version 3 fsinfo rpc call
! 180: */
! 181: int
! 182: nfs_fsinfo(nmp, vp, cred, p)
! 183: struct nfsmount *nmp;
! 184: struct vnode *vp;
! 185: struct ucred *cred;
! 186: struct proc *p;
! 187: {
! 188: struct nfsv3_fsinfo *fsp;
! 189: caddr_t cp;
! 190: int32_t t1, t2;
! 191: u_int32_t *tl, pref, max;
! 192: caddr_t bpos, dpos, cp2;
! 193: int error = 0, retattr;
! 194: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 195:
! 196: nfsstats.rpccnt[NFSPROC_FSINFO]++;
! 197: nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
! 198: nfsm_fhtom(vp, 1);
! 199: nfsm_request(vp, NFSPROC_FSINFO, p, cred);
! 200: nfsm_postop_attr(vp, retattr);
! 201: if (!error) {
! 202: nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
! 203: pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref);
! 204: if (pref < nmp->nm_wsize)
! 205: nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
! 206: ~(NFS_FABLKSIZE - 1);
! 207: max = fxdr_unsigned(u_int32_t, fsp->fs_wtmax);
! 208: if (max < nmp->nm_wsize) {
! 209: nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
! 210: if (nmp->nm_wsize == 0)
! 211: nmp->nm_wsize = max;
! 212: }
! 213: pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref);
! 214: if (pref < nmp->nm_rsize)
! 215: nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
! 216: ~(NFS_FABLKSIZE - 1);
! 217: max = fxdr_unsigned(u_int32_t, fsp->fs_rtmax);
! 218: if (max < nmp->nm_rsize) {
! 219: nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
! 220: if (nmp->nm_rsize == 0)
! 221: nmp->nm_rsize = max;
! 222: }
! 223: pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref);
! 224: if (pref < nmp->nm_readdirsize)
! 225: nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) &
! 226: ~(NFS_DIRBLKSIZ - 1);
! 227: if (max < nmp->nm_readdirsize) {
! 228: nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1);
! 229: if (nmp->nm_readdirsize == 0)
! 230: nmp->nm_readdirsize = max;
! 231: }
! 232: nmp->nm_flag |= NFSMNT_GOTFSINFO;
! 233: }
! 234: nfsm_reqdone;
! 235: return (error);
! 236: }
! 237:
! 238: /*
! 239: * Mount a remote root fs via. NFS. It goes like this:
! 240: * - Call nfs_boot_init() to fill in the nfs_diskless struct
! 241: * (using RARP, bootparam RPC, mountd RPC)
! 242: * - hand craft the swap nfs vnode hanging off a fake mount point
! 243: * if swdevt[0].sw_dev == NODEV
! 244: * - build the rootfs mount point and call mountnfs() to do the rest.
! 245: */
! 246: int
! 247: nfs_mountroot()
! 248: {
! 249: struct nfs_diskless nd;
! 250: struct vattr attr;
! 251: struct mount *mp;
! 252: struct vnode *vp;
! 253: struct proc *procp;
! 254: long n;
! 255: int error;
! 256:
! 257: procp = curproc; /* XXX */
! 258:
! 259: /*
! 260: * Call nfs_boot_init() to fill in the nfs_diskless struct.
! 261: * Side effect: Finds and configures a network interface.
! 262: */
! 263: bzero((caddr_t) &nd, sizeof(nd));
! 264: nfs_boot_init(&nd, procp);
! 265:
! 266: /*
! 267: * Create the root mount point.
! 268: */
! 269: if (nfs_boot_getfh(&nd.nd_boot, "root", &nd.nd_root, -1))
! 270: panic("nfs_mountroot: root");
! 271: mp = nfs_mount_diskless(&nd.nd_root, "/", 0);
! 272: nfs_root(mp, &rootvp);
! 273: printf("root on %s\n", nd.nd_root.ndm_host);
! 274:
! 275: /*
! 276: * Link it into the mount list.
! 277: */
! 278: CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
! 279: vfs_unbusy(mp);
! 280:
! 281: /* Get root attributes (for the time). */
! 282: error = VOP_GETATTR(rootvp, &attr, procp->p_ucred, procp);
! 283: if (error) panic("nfs_mountroot: getattr for root");
! 284: n = attr.va_atime.tv_sec;
! 285: #ifdef DEBUG
! 286: printf("root time: 0x%lx\n", n);
! 287: #endif
! 288: inittodr(n);
! 289:
! 290: #ifdef notyet
! 291: /* Set up swap credentials. */
! 292: proc0.p_ucred->cr_uid = ntohl(nd.swap_ucred.cr_uid);
! 293: proc0.p_ucred->cr_gid = ntohl(nd.swap_ucred.cr_gid);
! 294: if ((proc0.p_ucred->cr_ngroups = ntohs(nd.swap_ucred.cr_ngroups)) >
! 295: NGROUPS)
! 296: proc0.p_ucred->cr_ngroups = NGROUPS;
! 297: for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
! 298: proc0.p_ucred->cr_groups[i] = ntohl(nd.swap_ucred.cr_groups[i]);
! 299: #endif
! 300:
! 301: /*
! 302: * "Mount" the swap device.
! 303: *
! 304: * On a "dataless" configuration (swap on disk) we will have:
! 305: * (swdevt[0].sw_dev != NODEV) identifying the swap device.
! 306: */
! 307: if (bdevvp(swapdev, &swapdev_vp))
! 308: panic("nfs_mountroot: can't setup swap vp");
! 309: if (swdevt[0].sw_dev != NODEV) {
! 310: printf("swap on device 0x%x\n", swdevt[0].sw_dev);
! 311: return (0);
! 312: }
! 313:
! 314: /*
! 315: * If swapping to an nfs node: (swdevt[0].sw_dev == NODEV)
! 316: * Create a fake mount point just for the swap vnode so that the
! 317: * swap file can be on a different server from the rootfs.
! 318: *
! 319: * Wait 5 retries, finally no swap is cool. -mickey
! 320: */
! 321: error = nfs_boot_getfh(&nd.nd_boot, "swap", &nd.nd_swap, 5);
! 322: if (!error) {
! 323: mp = nfs_mount_diskless(&nd.nd_swap, "/swap", 0);
! 324: nfs_root(mp, &vp);
! 325: vfs_unbusy(mp);
! 326:
! 327: /*
! 328: * Since the swap file is not the root dir of a file system,
! 329: * hack it to a regular file.
! 330: */
! 331: vp->v_type = VREG;
! 332: vp->v_flag = 0;
! 333:
! 334: /*
! 335: * Next line is a hack to make swapmount() work on NFS swap files.
! 336: * XXX-smurph
! 337: */
! 338: swdevt[0].sw_dev = NETDEV;
! 339: /* end hack */
! 340: swdevt[0].sw_vp = vp;
! 341:
! 342: /*
! 343: * Find out how large the swap file is.
! 344: */
! 345: error = VOP_GETATTR(vp, &attr, procp->p_ucred, procp);
! 346: if (error)
! 347: printf("nfs_mountroot: getattr for swap\n");
! 348: n = (long) (attr.va_size >> DEV_BSHIFT);
! 349:
! 350: printf("swap on %s\n", nd.nd_swap.ndm_host);
! 351: #ifdef DEBUG
! 352: printf("swap size: 0x%lx (blocks)\n", n);
! 353: #endif
! 354: return (0);
! 355: }
! 356:
! 357: printf("WARNING: no swap\n");
! 358: swdevt[0].sw_dev = NODEV;
! 359: swdevt[0].sw_vp = NULL;
! 360:
! 361: return (0);
! 362: }
! 363:
! 364: /*
! 365: * Internal version of mount system call for diskless setup.
! 366: */
! 367: struct mount *
! 368: nfs_mount_diskless(ndmntp, mntname, mntflag)
! 369: struct nfs_dlmount *ndmntp;
! 370: char *mntname;
! 371: int mntflag;
! 372: {
! 373: struct nfs_args args;
! 374: struct mount *mp;
! 375: struct mbuf *m;
! 376: int error;
! 377:
! 378: if (vfs_rootmountalloc("nfs", mntname, &mp))
! 379: panic("nfs_mount_diskless: vfs_rootmountalloc failed");
! 380: mp->mnt_flag |= mntflag;
! 381:
! 382: /* Initialize mount args. */
! 383: bzero((caddr_t) &args, sizeof(args));
! 384: args.addr = (struct sockaddr *)&ndmntp->ndm_saddr;
! 385: args.addrlen = args.addr->sa_len;
! 386: args.sotype = SOCK_DGRAM;
! 387: args.fh = ndmntp->ndm_fh;
! 388: args.fhsize = NFSX_V2FH;
! 389: args.hostname = ndmntp->ndm_host;
! 390:
! 391: #ifdef NFS_BOOT_OPTIONS
! 392: args.flags |= NFS_BOOT_OPTIONS;
! 393: #endif
! 394: #ifdef NFS_BOOT_RWSIZE
! 395: /*
! 396: * Reduce rsize,wsize for interfaces that consistently
! 397: * drop fragments of long UDP messages. (i.e. wd8003).
! 398: * You can always change these later via remount.
! 399: */
! 400: args.flags |= NFSMNT_WSIZE | NFSMNT_RSIZE;
! 401: args.wsize = NFS_BOOT_RWSIZE;
! 402: args.rsize = NFS_BOOT_RWSIZE;
! 403: #endif
! 404:
! 405: /* Get mbuf for server sockaddr. */
! 406: m = m_get(M_WAIT, MT_SONAME);
! 407: bcopy((caddr_t)args.addr, mtod(m, caddr_t),
! 408: (m->m_len = args.addr->sa_len));
! 409:
! 410: error = mountnfs(&args, mp, m, mntname, args.hostname);
! 411: if (error)
! 412: panic("nfs_mountroot: mount %s failed: %d", mntname, error);
! 413:
! 414: return (mp);
! 415: }
! 416:
! 417: void
! 418: nfs_decode_args(nmp, argp, nargp)
! 419: struct nfsmount *nmp;
! 420: struct nfs_args *argp;
! 421: struct nfs_args *nargp;
! 422: {
! 423: int s;
! 424: int adjsock = 0;
! 425: int maxio;
! 426:
! 427: s = splsoftnet();
! 428:
! 429: #if 0
! 430: /* Re-bind if rsrvd port requested and wasn't on one */
! 431: adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
! 432: && (argp->flags & NFSMNT_RESVPORT);
! 433: #endif
! 434: /* Also re-bind if we're switching to/from a connected UDP socket */
! 435: adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
! 436: (argp->flags & NFSMNT_NOCONN));
! 437:
! 438: /* Update flags atomically. Don't change the lock bits. */
! 439: nmp->nm_flag =
! 440: (argp->flags & ~NFSMNT_INTERNAL) | (nmp->nm_flag & NFSMNT_INTERNAL);
! 441: splx(s);
! 442:
! 443: if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
! 444: nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
! 445: if (nmp->nm_timeo < NFS_MINTIMEO)
! 446: nmp->nm_timeo = NFS_MINTIMEO;
! 447: else if (nmp->nm_timeo > NFS_MAXTIMEO)
! 448: nmp->nm_timeo = NFS_MAXTIMEO;
! 449: }
! 450:
! 451: if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
! 452: nmp->nm_retry = argp->retrans;
! 453: if (nmp->nm_retry > NFS_MAXREXMIT)
! 454: nmp->nm_retry = NFS_MAXREXMIT;
! 455: }
! 456:
! 457: if (argp->flags & NFSMNT_NFSV3) {
! 458: if (argp->sotype == SOCK_DGRAM)
! 459: maxio = NFS_MAXDGRAMDATA;
! 460: else
! 461: maxio = NFS_MAXDATA;
! 462: } else
! 463: maxio = NFS_V2MAXDATA;
! 464:
! 465: if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
! 466: int osize = nmp->nm_wsize;
! 467: nmp->nm_wsize = argp->wsize;
! 468: /* Round down to multiple of blocksize */
! 469: nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
! 470: if (nmp->nm_wsize <= 0)
! 471: nmp->nm_wsize = NFS_FABLKSIZE;
! 472: adjsock |= (nmp->nm_wsize != osize);
! 473: }
! 474: if (nmp->nm_wsize > maxio)
! 475: nmp->nm_wsize = maxio;
! 476: if (nmp->nm_wsize > MAXBSIZE)
! 477: nmp->nm_wsize = MAXBSIZE;
! 478:
! 479: if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
! 480: int osize = nmp->nm_rsize;
! 481: nmp->nm_rsize = argp->rsize;
! 482: /* Round down to multiple of blocksize */
! 483: nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
! 484: if (nmp->nm_rsize <= 0)
! 485: nmp->nm_rsize = NFS_FABLKSIZE;
! 486: adjsock |= (nmp->nm_rsize != osize);
! 487: }
! 488: if (nmp->nm_rsize > maxio)
! 489: nmp->nm_rsize = maxio;
! 490: if (nmp->nm_rsize > MAXBSIZE)
! 491: nmp->nm_rsize = MAXBSIZE;
! 492:
! 493: if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
! 494: nmp->nm_readdirsize = argp->readdirsize;
! 495: /* Round down to multiple of blocksize */
! 496: nmp->nm_readdirsize &= ~(NFS_DIRBLKSIZ - 1);
! 497: if (nmp->nm_readdirsize < NFS_DIRBLKSIZ)
! 498: nmp->nm_readdirsize = NFS_DIRBLKSIZ;
! 499: } else if (argp->flags & NFSMNT_RSIZE)
! 500: nmp->nm_readdirsize = nmp->nm_rsize;
! 501:
! 502: if (nmp->nm_readdirsize > maxio)
! 503: nmp->nm_readdirsize = maxio;
! 504:
! 505: if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
! 506: argp->maxgrouplist <= NFS_MAXGRPS)
! 507: nmp->nm_numgrps = argp->maxgrouplist;
! 508: if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
! 509: argp->readahead <= NFS_MAXRAHEAD)
! 510: nmp->nm_readahead = argp->readahead;
! 511: if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
! 512: argp->deadthresh <= NQ_NEVERDEAD)
! 513: nmp->nm_deadthresh = argp->deadthresh;
! 514: if (argp->flags & NFSMNT_ACREGMIN && argp->acregmin >= 0) {
! 515: if (argp->acregmin > 0xffff)
! 516: nmp->nm_acregmin = 0xffff;
! 517: else
! 518: nmp->nm_acregmin = argp->acregmin;
! 519: }
! 520: if (argp->flags & NFSMNT_ACREGMAX && argp->acregmax >= 0) {
! 521: if (argp->acregmax > 0xffff)
! 522: nmp->nm_acregmax = 0xffff;
! 523: else
! 524: nmp->nm_acregmax = argp->acregmax;
! 525: }
! 526: if (nmp->nm_acregmin > nmp->nm_acregmax)
! 527: nmp->nm_acregmin = nmp->nm_acregmax;
! 528:
! 529: if (argp->flags & NFSMNT_ACDIRMIN && argp->acdirmin >= 0) {
! 530: if (argp->acdirmin > 0xffff)
! 531: nmp->nm_acdirmin = 0xffff;
! 532: else
! 533: nmp->nm_acdirmin = argp->acdirmin;
! 534: }
! 535: if (argp->flags & NFSMNT_ACDIRMAX && argp->acdirmax >= 0) {
! 536: if (argp->acdirmax > 0xffff)
! 537: nmp->nm_acdirmax = 0xffff;
! 538: else
! 539: nmp->nm_acdirmax = argp->acdirmax;
! 540: }
! 541: if (nmp->nm_acdirmin > nmp->nm_acdirmax)
! 542: nmp->nm_acdirmin = nmp->nm_acdirmax;
! 543:
! 544: if (nmp->nm_so && adjsock) {
! 545: nfs_disconnect(nmp);
! 546: if (nmp->nm_sotype == SOCK_DGRAM)
! 547: while (nfs_connect(nmp, (struct nfsreq *)0)) {
! 548: printf("nfs_args: retrying connect\n");
! 549: (void) tsleep((caddr_t)&lbolt,
! 550: PSOCK, "nfscon", 0);
! 551: }
! 552: }
! 553:
! 554: /* Update nargp based on nmp */
! 555: nargp->wsize = nmp->nm_wsize;
! 556: nargp->rsize = nmp->nm_rsize;
! 557: nargp->readdirsize = nmp->nm_readdirsize;
! 558: nargp->timeo = nmp->nm_timeo;
! 559: nargp->retrans = nmp->nm_retry;
! 560: nargp->maxgrouplist = nmp->nm_numgrps;
! 561: nargp->readahead = nmp->nm_readahead;
! 562: nargp->deadthresh = nmp->nm_deadthresh;
! 563: nargp->acregmin = nmp->nm_acregmin;
! 564: nargp->acregmax = nmp->nm_acregmax;
! 565: nargp->acdirmin = nmp->nm_acdirmin;
! 566: nargp->acdirmax = nmp->nm_acdirmax;
! 567: }
! 568:
! 569: /*
! 570: * VFS Operations.
! 571: *
! 572: * mount system call
! 573: * It seems a bit dumb to copyinstr() the host and path here and then
! 574: * bcopy() them in mountnfs(), but I wanted to detect errors before
! 575: * doing the sockargs() call because sockargs() allocates an mbuf and
! 576: * an error after that means that I have to release the mbuf.
! 577: */
! 578: /* ARGSUSED */
! 579: int
! 580: nfs_mount(mp, path, data, ndp, p)
! 581: struct mount *mp;
! 582: const char *path;
! 583: void *data;
! 584: struct nameidata *ndp;
! 585: struct proc *p;
! 586: {
! 587: int error;
! 588: struct nfs_args args;
! 589: struct mbuf *nam;
! 590: char pth[MNAMELEN], hst[MNAMELEN];
! 591: size_t len;
! 592: u_char nfh[NFSX_V3FHMAX];
! 593:
! 594: error = copyin (data, &args, sizeof (args.version));
! 595: if (error)
! 596: return (error);
! 597: if (args.version == 3) {
! 598: error = copyin (data, (caddr_t)&args,
! 599: sizeof (struct nfs_args3));
! 600: args.flags &= ~(NFSMNT_INTERNAL|NFSMNT_NOAC);
! 601: }
! 602: else if (args.version == NFS_ARGSVERSION) {
! 603: error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args));
! 604: args.flags &= ~NFSMNT_NOAC; /* XXX - compatibility */
! 605: }
! 606: else
! 607: return (EPROGMISMATCH);
! 608: if (error)
! 609: return (error);
! 610:
! 611: if ((args.flags & (NFSMNT_NFSV3|NFSMNT_RDIRPLUS)) == NFSMNT_RDIRPLUS)
! 612: return (EINVAL);
! 613:
! 614: if (nfs_niothreads < 0) {
! 615: nfs_niothreads = 4;
! 616: nfs_getset_niothreads(TRUE);
! 617: }
! 618:
! 619: if (mp->mnt_flag & MNT_UPDATE) {
! 620: struct nfsmount *nmp = VFSTONFS(mp);
! 621:
! 622: if (nmp == NULL)
! 623: return (EIO);
! 624: /*
! 625: * When doing an update, we can't change from or to
! 626: * v3.
! 627: */
! 628: args.flags = (args.flags & ~(NFSMNT_NFSV3)) |
! 629: (nmp->nm_flag & (NFSMNT_NFSV3));
! 630: nfs_decode_args(nmp, &args, &mp->mnt_stat.mount_info.nfs_args);
! 631: return (0);
! 632: }
! 633: if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX)
! 634: return (EINVAL);
! 635: error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize);
! 636: if (error)
! 637: return (error);
! 638: error = copyinstr(path, pth, MNAMELEN-1, &len);
! 639: if (error)
! 640: return (error);
! 641: bzero(&pth[len], MNAMELEN - len);
! 642: error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
! 643: if (error)
! 644: return (error);
! 645: bzero(&hst[len], MNAMELEN - len);
! 646: /* sockargs() call must be after above copyin() calls */
! 647: error = sockargs(&nam, args.addr, args.addrlen, MT_SONAME);
! 648: if (error)
! 649: return (error);
! 650: args.fh = nfh;
! 651: error = mountnfs(&args, mp, nam, pth, hst);
! 652: return (error);
! 653: }
! 654:
! 655: /*
! 656: * Common code for mount and mountroot
! 657: */
! 658: int
! 659: mountnfs(argp, mp, nam, pth, hst)
! 660: struct nfs_args *argp;
! 661: struct mount *mp;
! 662: struct mbuf *nam;
! 663: char *pth, *hst;
! 664: {
! 665: struct nfsmount *nmp;
! 666: int error;
! 667:
! 668: if (mp->mnt_flag & MNT_UPDATE) {
! 669: nmp = VFSTONFS(mp);
! 670: /* update paths, file handles, etc, here XXX */
! 671: m_freem(nam);
! 672: return (0);
! 673: } else {
! 674: MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
! 675: M_NFSMNT, M_WAITOK);
! 676: bzero((caddr_t)nmp, sizeof (struct nfsmount));
! 677: mp->mnt_data = (qaddr_t)nmp;
! 678: TAILQ_INIT(&nmp->nm_uidlruhead);
! 679: }
! 680:
! 681: vfs_getnewfsid(mp);
! 682: nmp->nm_mountp = mp;
! 683: nmp->nm_timeo = NFS_TIMEO;
! 684: nmp->nm_retry = NFS_RETRANS;
! 685: nmp->nm_wsize = NFS_WSIZE;
! 686: nmp->nm_rsize = NFS_RSIZE;
! 687: nmp->nm_readdirsize = NFS_READDIRSIZE;
! 688: nmp->nm_numgrps = NFS_MAXGRPS;
! 689: nmp->nm_readahead = NFS_DEFRAHEAD;
! 690: nmp->nm_deadthresh = NQ_DEADTHRESH;
! 691: nmp->nm_fhsize = argp->fhsize;
! 692: nmp->nm_acregmin = NFS_MINATTRTIMO;
! 693: nmp->nm_acregmax = NFS_MAXATTRTIMO;
! 694: nmp->nm_acdirmin = NFS_MINATTRTIMO;
! 695: nmp->nm_acdirmax = NFS_MAXATTRTIMO;
! 696: bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
! 697: strncpy(&mp->mnt_stat.f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);
! 698: bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
! 699: bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
! 700: bcopy(argp, &mp->mnt_stat.mount_info.nfs_args, sizeof(*argp));
! 701: nmp->nm_nam = nam;
! 702: nfs_decode_args(nmp, argp, &mp->mnt_stat.mount_info.nfs_args);
! 703:
! 704: /* Set up the sockets and per-host congestion */
! 705: nmp->nm_sotype = argp->sotype;
! 706: nmp->nm_soproto = argp->proto;
! 707:
! 708: /*
! 709: * For Connection based sockets (TCP,...) defer the connect until
! 710: * the first request, in case the server is not responding.
! 711: */
! 712: if (nmp->nm_sotype == SOCK_DGRAM &&
! 713: (error = nfs_connect(nmp, (struct nfsreq *)0)))
! 714: goto bad;
! 715:
! 716: /*
! 717: * This is silly, but it has to be set so that vinifod() works.
! 718: * We do not want to do an nfs_statfs() here since we can get
! 719: * stuck on a dead server and we are holding a lock on the mount
! 720: * point.
! 721: */
! 722: mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
! 723:
! 724: return (0);
! 725: bad:
! 726: nfs_disconnect(nmp);
! 727: free((caddr_t)nmp, M_NFSMNT);
! 728: m_freem(nam);
! 729: return (error);
! 730: }
! 731:
! 732: /* unmount system call */
! 733: int
! 734: nfs_unmount(struct mount *mp, int mntflags, struct proc *p)
! 735: {
! 736: struct nfsmount *nmp;
! 737: int error, flags;
! 738:
! 739: nmp = VFSTONFS(mp);
! 740: flags = 0;
! 741:
! 742: if (mntflags & MNT_FORCE)
! 743: flags |= FORCECLOSE;
! 744:
! 745: error = vflush(mp, NULL, flags);
! 746: if (error)
! 747: return (error);
! 748:
! 749: nfs_disconnect(nmp);
! 750: m_freem(nmp->nm_nam);
! 751: free(nmp, M_NFSMNT);
! 752: return (0);
! 753: }
! 754:
! 755: /*
! 756: * Return root of a filesystem
! 757: */
! 758: int
! 759: nfs_root(mp, vpp)
! 760: struct mount *mp;
! 761: struct vnode **vpp;
! 762: {
! 763: struct nfsmount *nmp;
! 764: struct nfsnode *np;
! 765: int error;
! 766:
! 767: nmp = VFSTONFS(mp);
! 768: error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
! 769: if (error)
! 770: return (error);
! 771: *vpp = NFSTOV(np);
! 772: return (0);
! 773: }
! 774:
! 775: /*
! 776: * Flush out the buffer cache
! 777: */
! 778: /* ARGSUSED */
! 779: int
! 780: nfs_sync(mp, waitfor, cred, p)
! 781: struct mount *mp;
! 782: int waitfor;
! 783: struct ucred *cred;
! 784: struct proc *p;
! 785: {
! 786: struct vnode *vp;
! 787: int error, allerror = 0;
! 788:
! 789: /*
! 790: * Don't traverse the vnode list if we want to skip all of them.
! 791: */
! 792: if (waitfor == MNT_LAZY)
! 793: return (allerror);
! 794:
! 795: /*
! 796: * Force stale buffer cache information to be flushed.
! 797: */
! 798: loop:
! 799: for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp != NULL;
! 800: vp = LIST_NEXT(vp, v_mntvnodes)) {
! 801: /*
! 802: * If the vnode that we are about to sync is no longer
! 803: * associated with this mount point, start over.
! 804: */
! 805: if (vp->v_mount != mp)
! 806: goto loop;
! 807: if (VOP_ISLOCKED(vp) || LIST_FIRST(&vp->v_dirtyblkhd) == NULL)
! 808: continue;
! 809: if (vget(vp, LK_EXCLUSIVE, p))
! 810: goto loop;
! 811: error = VOP_FSYNC(vp, cred, waitfor, p);
! 812: if (error)
! 813: allerror = error;
! 814: vput(vp);
! 815: }
! 816:
! 817: return (allerror);
! 818: }
! 819:
! 820: /*
! 821: * NFS flat namespace lookup.
! 822: * Currently unsupported.
! 823: */
! 824: /* ARGSUSED */
! 825: int
! 826: nfs_vget(mp, ino, vpp)
! 827: struct mount *mp;
! 828: ino_t ino;
! 829: struct vnode **vpp;
! 830: {
! 831:
! 832: return (EOPNOTSUPP);
! 833: }
! 834:
! 835: /*
! 836: * Do that sysctl thang...
! 837: */
! 838: int
! 839: nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
! 840: size_t newlen, struct proc *p)
! 841: {
! 842: int rv;
! 843:
! 844: /*
! 845: * All names at this level are terminal.
! 846: */
! 847: if(namelen > 1)
! 848: return ENOTDIR; /* overloaded */
! 849:
! 850: switch(name[0]) {
! 851: case NFS_NFSSTATS:
! 852: if(!oldp) {
! 853: *oldlenp = sizeof nfsstats;
! 854: return 0;
! 855: }
! 856:
! 857: if(*oldlenp < sizeof nfsstats) {
! 858: *oldlenp = sizeof nfsstats;
! 859: return ENOMEM;
! 860: }
! 861:
! 862: rv = copyout(&nfsstats, oldp, sizeof nfsstats);
! 863: if(rv) return rv;
! 864:
! 865: if(newp && newlen != sizeof nfsstats)
! 866: return EINVAL;
! 867:
! 868: if(newp) {
! 869: return copyin(newp, &nfsstats, sizeof nfsstats);
! 870: }
! 871: return 0;
! 872:
! 873: case NFS_NIOTHREADS:
! 874: nfs_getset_niothreads(0);
! 875:
! 876: rv = sysctl_int(oldp, oldlenp, newp, newlen, &nfs_niothreads);
! 877: if (newp)
! 878: nfs_getset_niothreads(1);
! 879:
! 880: return rv;
! 881:
! 882: default:
! 883: return EOPNOTSUPP;
! 884: }
! 885: }
! 886:
! 887:
! 888: /*
! 889: * At this point, this should never happen
! 890: */
! 891: /* ARGSUSED */
! 892: int
! 893: nfs_fhtovp(mp, fhp, vpp)
! 894: struct mount *mp;
! 895: struct fid *fhp;
! 896: struct vnode **vpp;
! 897: {
! 898:
! 899: return (EINVAL);
! 900: }
! 901:
! 902: /*
! 903: * Vnode pointer to File handle, should never happen either
! 904: */
! 905: /* ARGSUSED */
! 906: int
! 907: nfs_vptofh(vp, fhp)
! 908: struct vnode *vp;
! 909: struct fid *fhp;
! 910: {
! 911:
! 912: return (EINVAL);
! 913: }
! 914:
! 915: /*
! 916: * Vfs start routine, a no-op.
! 917: */
! 918: /* ARGSUSED */
! 919: int
! 920: nfs_start(mp, flags, p)
! 921: struct mount *mp;
! 922: int flags;
! 923: struct proc *p;
! 924: {
! 925:
! 926: return (0);
! 927: }
! 928:
! 929: /*
! 930: * Do operations associated with quotas, not supported
! 931: */
! 932: /* ARGSUSED */
! 933: int
! 934: nfs_quotactl(mp, cmd, uid, arg, p)
! 935: struct mount *mp;
! 936: int cmd;
! 937: uid_t uid;
! 938: caddr_t arg;
! 939: struct proc *p;
! 940: {
! 941:
! 942: return (EOPNOTSUPP);
! 943: }
! 944:
! 945: /*
! 946: * check export permission, not supported
! 947: */
! 948: /* ARGUSED */
! 949: int
! 950: nfs_checkexp(mp, nam, exflagsp, credanonp)
! 951: struct mount *mp;
! 952: struct mbuf *nam;
! 953: int *exflagsp;
! 954: struct ucred **credanonp;
! 955: {
! 956: return (EOPNOTSUPP);
! 957: }
! 958:
CVSweb