X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/d7e50217d7adf6e52786a38bcaa4cd698cb9a79e..a3d08fcd5120d2aa8303b6349ca8b14e3f284af3:/bsd/nfs/nfs_vfsops.c diff --git a/bsd/nfs/nfs_vfsops.c b/bsd/nfs/nfs_vfsops.c index cda27c84d..b08612aa8 100644 --- a/bsd/nfs/nfs_vfsops.c +++ b/bsd/nfs/nfs_vfsops.c @@ -1,24 +1,21 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. * * @APPLE_LICENSE_HEADER_END@ */ @@ -74,7 +71,6 @@ #include #include #include -#include #include #include #include @@ -103,6 +99,8 @@ extern int nfs_mountroot __P((void)); extern int nfs_ticks; +extern int nfs_mount_type; +extern int nfs_resv_mounts; struct nfsstats nfsstats; static int nfs_sysctl(int *, u_int, void *, size_t *, void *, size_t, @@ -121,6 +119,18 @@ SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0, ""); #endif #endif +SYSCTL_DECL(_vfs_generic_nfs); +SYSCTL_NODE(_vfs_generic_nfs, OID_AUTO, client, CTLFLAG_RW, 0, + "nfs client hinge"); +/* how long NFS will wait before signalling vfs that it's down. */ +static int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY; +SYSCTL_INT(_vfs_generic_nfs_client, NFS_TPRINTF_INITIAL_DELAY, + initialdowndelay, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, ""); +/* how long between console messages "nfs server foo not responding" */ +static int nfs_tprintf_delay = NFS_TPRINTF_DELAY; +SYSCTL_INT(_vfs_generic_nfs_client, NFS_TPRINTF_DELAY, + nextdowndelay, CTLFLAG_RW, &nfs_tprintf_delay, 0, ""); + static int nfs_iosize __P((struct nfsmount *nmp)); static int mountnfs __P((struct nfs_args *,struct mount *, struct mbuf *,char *,char *,struct vnode **)); @@ -141,7 +151,7 @@ static int nfs_vptofh __P(( struct vnode *vp, struct fid *fhp)); static int nfs_fhtovp __P((struct mount *mp, struct fid *fhp, struct mbuf *nam, struct vnode **vpp, int *exflagsp, struct ucred **credanonp)); -static int nfs_vget __P((struct mount *, ino_t, struct vnode **)); +static int nfs_vget __P((struct mount *, void *, struct vnode **)); /* @@ -192,7 +202,10 @@ static int nfs_iosize(nmp) * Calculate the size used for io buffers. Use the larger * of the two sizes to minimise nfs requests but make sure * that it is at least one VM page to avoid wasting buffer - * space. + * space and to allow easy mmapping of I/O buffers. + * The read/write rpc calls handle the splitting up of + * buffers into multiple requests if the buffer size is + * larger than the I/O size. */ iosize = max(nmp->nm_rsize, nmp->nm_wsize); if (iosize < PAGE_SIZE) @@ -243,7 +256,6 @@ nfs_statfs(mp, sbp, p) int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr; struct mbuf *mreq, *mrep, *md, *mb, *mb2; struct ucred *cred; - u_quad_t tquad; extern int nfs_mount_type; u_int64_t xid; @@ -255,13 +267,13 @@ nfs_statfs(mp, sbp, p) return(error); cred = crget(); cred->cr_ngroups = 1; - if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0) + if (v3 && (nmp->nm_state & NFSSTA_GOTFSINFO) == 0) (void)nfs_fsinfo(nmp, vp, cred, p); nfsstats.rpccnt[NFSPROC_FSSTAT]++; nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3)); nfsm_fhtom(vp, v3); nfsm_request(vp, NFSPROC_FSSTAT, p, cred, &xid); - if (v3) + if (v3 && mrep) nfsm_postop_attr(vp, retattr, &xid); nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3)); @@ -274,17 +286,40 @@ nfs_statfs(mp, sbp, p) sbp->f_flags = nmp->nm_flag; sbp->f_iosize = nfs_iosize(nmp); if (v3) { - sbp->f_bsize = NFS_FABLKSIZE; + /* + * Adjust block size to get total block count to fit in a long. + * If we can't increase block size enough, clamp to max long. + */ + u_quad_t tquad, tquad2, bsize; + bsize = NFS_FABLKSIZE; + fxdr_hyper(&sfp->sf_tbytes, &tquad); - sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE)); + tquad /= bsize; + while ((tquad & ~0x7fffffff) && (bsize < 0x40000000)) { + bsize <<= 1; + tquad >>= 1; + } + sbp->f_blocks = (tquad & ~0x7fffffff) ? 0x7fffffff : (long)tquad; + fxdr_hyper(&sfp->sf_fbytes, &tquad); - sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE)); + tquad /= bsize; + sbp->f_bfree = (tquad & ~0x7fffffff) ? 0x7fffffff : (long)tquad; + fxdr_hyper(&sfp->sf_abytes, &tquad); - sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE)); - sbp->f_files = (fxdr_unsigned(long, sfp->sf_tfiles.nfsuquad[1]) - & 0x7fffffff); - sbp->f_ffree = (fxdr_unsigned(long, sfp->sf_ffiles.nfsuquad[1]) - & 0x7fffffff); + tquad /= bsize; + sbp->f_bavail = (tquad & ~0x7fffffff) ? 0x7fffffff : (long)tquad; + + sbp->f_bsize = (long)bsize; + + /* adjust file slots too... */ + fxdr_hyper(&sfp->sf_tfiles, &tquad); + fxdr_hyper(&sfp->sf_ffiles, &tquad2); + while (tquad & ~0x7fffffff) { + tquad >>= 1; + tquad2 >>= 1; + } + sbp->f_files = tquad; + sbp->f_ffree = tquad2; } else { sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize); sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); @@ -326,7 +361,9 @@ nfs_fsinfo(nmp, vp, cred, p) nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1)); nfsm_fhtom(vp, 1); nfsm_request(vp, NFSPROC_FSINFO, p, cred, &xid); - nfsm_postop_attr(vp, retattr, &xid); + if (mrep) { + nfsm_postop_attr(vp, retattr, &xid); + } if (!error) { nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO); pref = fxdr_unsigned(u_long, fsp->fs_wtpref); @@ -355,7 +392,7 @@ nfs_fsinfo(nmp, vp, cred, p) if (max < nmp->nm_readdirsize) { nmp->nm_readdirsize = max; } - nmp->nm_flag |= NFSMNT_GOTFSINFO; + nmp->nm_state |= NFSSTA_GOTFSINFO; } nfsm_reqdone; return (error); @@ -409,6 +446,15 @@ nfs_mountroot() tryagain: error = nfs_boot_getfh(&nd, procp, v3); if (error) { + if (error == EHOSTDOWN || error == EHOSTUNREACH) { + if (nd.nd_root.ndm_path) + FREE_ZONE(nd.nd_root.ndm_path, + MAXPATHLEN, M_NAMEI); + if (nd.nd_private.ndm_path) + FREE_ZONE(nd.nd_private.ndm_path, + MAXPATHLEN, M_NAMEI); + return (error); + } if (v3) { printf("nfs_boot_getfh(v3) failed with %d, trying v2...\n", error); v3 = 0; @@ -513,8 +559,12 @@ nfs_mount_diskless(ndmntp, mntname, mntflag, vpp, mpp) if ((error = mountnfs(&args, mp, m, mntname, args.hostname, vpp))) { printf("nfs_mountroot: mount %s failed: %d", mntname, error); mp->mnt_vfc->vfc_refcount--; + + if (mp->mnt_kern_flag & MNTK_IO_XINFO) + FREE(mp->mnt_xinfo_ptr, M_TEMP); vfs_unbusy(mp, procp); - _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); + + FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); return (error); } #if 0 /* Causes incorrect reporting of "mounted on" */ @@ -607,9 +657,9 @@ nfs_mount_diskless_private(ndmntp, mntname, mntflag, vpp, mpp) mp = _MALLOC_ZONE((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); bzero((char *)mp, (u_long)sizeof(struct mount)); - /* Initialize the default IO constraints */ - mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS; - mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32; + /* Initialize the default IO constraints */ + mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS; + mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32; lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); (void)vfs_busy(mp, LK_NOWAIT, 0, procp); @@ -645,8 +695,12 @@ nfs_mount_diskless_private(ndmntp, mntname, mntflag, vpp, mpp) if ((error = mountnfs(&args, mp, m, mntname, args.hostname, &vp))) { printf("nfs_mountroot: mount %s failed: %d", mntname, error); mp->mnt_vfc->vfc_refcount--; + + if (mp->mnt_kern_flag & MNTK_IO_XINFO) + FREE(mp->mnt_xinfo_ptr, M_TEMP); vfs_unbusy(mp, procp); - _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); + + FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); return (error); } @@ -679,7 +733,7 @@ nfs_mount(mp, path, data, ndp, p) struct mbuf *nam; struct vnode *vp; char pth[MNAMELEN], hst[MNAMELEN]; - u_int len; + size_t len; u_char nfh[NFSX_V3FHMAX]; error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)); @@ -701,7 +755,7 @@ nfs_mount(mp, path, data, ndp, p) return (EPROGMISMATCH); #endif /* !NO_COMPAT_PRELITE2 */ } - if (args.fhsize > NFSX_V3FHMAX) + if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) return (EINVAL); error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize); if (error) @@ -750,6 +804,13 @@ mountnfs(argp, mp, nam, pth, hst, vpp) error = NFSERR_NOTSUPP; goto bad2; } + + /* + * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes + * no sense in that context. + */ + if (argp->sotype == SOCK_STREAM) + argp->flags &= ~NFSMNT_NOCONN; if (mp->mnt_flag & MNT_UPDATE) { nmp = VFSTONFS(mp); @@ -777,26 +838,30 @@ mountnfs(argp, mp, nam, pth, hst, vpp) mp->mnt_maxsymlinklen = 1; nmp->nm_timeo = NFS_TIMEO; nmp->nm_retry = NFS_RETRANS; - nmp->nm_wsize = NFS_WSIZE; - nmp->nm_rsize = NFS_RSIZE; + if (argp->sotype == SOCK_DGRAM) { + nmp->nm_wsize = NFS_DGRAM_WSIZE; + nmp->nm_rsize = NFS_DGRAM_RSIZE; + } else { + nmp->nm_wsize = NFS_WSIZE; + nmp->nm_rsize = NFS_RSIZE; + } nmp->nm_readdirsize = NFS_READDIRSIZE; nmp->nm_numgrps = NFS_MAXGRPS; nmp->nm_readahead = NFS_DEFRAHEAD; nmp->nm_leaseterm = NQ_DEFLEASE; nmp->nm_deadthresh = NQ_DEADTHRESH; + nmp->nm_tprintf_delay = nfs_tprintf_delay; + if (nmp->nm_tprintf_delay < 0) + nmp->nm_tprintf_delay = 0; + nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay; + if (nmp->nm_tprintf_initial_delay < 0) + nmp->nm_tprintf_initial_delay = 0; CIRCLEQ_INIT(&nmp->nm_timerhead); nmp->nm_inprog = NULLVP; bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); nmp->nm_nam = nam; - /* - * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes - * no sense in that context. - */ - if (argp->sotype == SOCK_STREAM) - argp->flags &= ~NFSMNT_NOCONN; - if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; if (nmp->nm_timeo < NFS_MINTIMEO) @@ -875,13 +940,6 @@ mountnfs(argp, mp, nam, pth, hst, vpp) (error = nfs_connect(nmp, (struct nfsreq *)0))) goto bad; - /* - * This is silly, but it has to be set so that vinifod() works. - * We do not want to do an nfs_statfs() here since we can get - * stuck on a dead server and we are holding a lock on the mount - * point. - */ - mp->mnt_stat.f_iosize = nfs_iosize(nmp); /* * A reference count is needed on the nfsnode representing the * remote root. If this object is not persistent, then backward @@ -906,17 +964,37 @@ mountnfs(argp, mp, nam, pth, hst, vpp) * effect of filling in (*vpp)->v_type with the correct value. */ curproc = current_proc(); - VOP_GETATTR(*vpp, &attrs, curproc->p_ucred, curproc); + error = VOP_GETATTR(*vpp, &attrs, curproc->p_ucred, curproc); + if (error) { + /* + * we got problems... we couldn't get the attributes + * from the NFS server... so the mount fails. + */ + vput(*vpp); + goto bad; + } + + /* + * Set the mount point's block I/O size. + * We really need to do this after we get info back from + * the server about what its preferred I/O sizes are. + */ + if (nmp->nm_flag & NFSMNT_NFSV3) + nfs_fsinfo(nmp, *vpp, curproc->p_ucred, curproc); + mp->mnt_stat.f_iosize = nfs_iosize(nmp); /* * Lose the lock but keep the ref. */ VOP_UNLOCK(*vpp, 0, curproc); + if (nmp->nm_flag & NFSMNT_RESVPORT) + nfs_resv_mounts++; + nmp->nm_state |= NFSSTA_MOUNTED; return (0); bad: nfs_disconnect(nmp); - _FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT); + FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT); bad2: m_freem(nam); return (error); @@ -936,9 +1014,17 @@ nfs_unmount(mp, mntflags, p) struct vnode *vp; int error, flags = 0; - if (mntflags & MNT_FORCE) - flags |= FORCECLOSE; nmp = VFSTONFS(mp); + /* + * During a force unmount we want to... + * Mark that we are doing a force unmount. + * Make the mountpoint soft. + */ + if (mntflags & MNT_FORCE) { + flags |= FORCECLOSE; + nmp->nm_state |= NFSSTA_FORCE; + nmp->nm_flag |= NFSMNT_SOFT; + } /* * Goes something like this.. * - Call vflush() to clear out vnodes for this file system, @@ -953,7 +1039,7 @@ nfs_unmount(mp, mntflags, p) /* * Must handshake with nqnfs_clientd() if it is active. */ - nmp->nm_flag |= NFSMNT_DISMINPROG; + nmp->nm_state |= NFSSTA_DISMINPROG; while (nmp->nm_inprog != NULLVP) (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0); /* @@ -962,18 +1048,18 @@ nfs_unmount(mp, mntflags, p) * not get EBUSY back. */ error = vflush(mp, vp, SKIPSWAP | flags); - if (mntflags & MNT_FORCE) + if (mntflags & MNT_FORCE) { error = vflush(mp, NULLVP, flags); /* locks vp in the process */ - else { + } else { if (vp->v_usecount > 1) { - nmp->nm_flag &= ~NFSMNT_DISMINPROG; + nmp->nm_state &= ~NFSSTA_DISMINPROG; return (EBUSY); } error = vflush(mp, vp, flags); } if (error) { - nmp->nm_flag &= ~NFSMNT_DISMINPROG; + nmp->nm_state &= ~NFSSTA_DISMINPROG; return (error); } @@ -982,7 +1068,12 @@ nfs_unmount(mp, mntflags, p) * For NQNFS, let the server daemon free the nfsmount structure. */ if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) - nmp->nm_flag |= NFSMNT_DISMNT; + nmp->nm_state |= NFSSTA_DISMNT; + nmp->nm_state &= ~NFSSTA_MOUNTED; + if (nmp->nm_flag & NFSMNT_RESVPORT) { + if (--nfs_resv_mounts == 0) + nfs_bind_resv_thread_wake(); + } /* * Release the root vnode reference held by mountnfs() @@ -1018,7 +1109,12 @@ nfs_unmount(mp, mntflags, p) if (hw_atomic_sub(&nfsreqqusers, 1) != 0) nfsatompanic("unmount sub"); #endif - _FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT); + /* Need to wake up any rcvlock waiters so they notice the unmount. */ + if (nmp->nm_state & NFSSTA_WANTRCV) { + nmp->nm_state &= ~NFSSTA_WANTRCV; + wakeup(&nmp->nm_state); + } + FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT); } return (0); } @@ -1033,13 +1129,18 @@ nfs_root(mp, vpp) { register struct vnode *vp; struct nfsmount *nmp; - int error; + int error, vpid; nmp = VFSTONFS(mp); vp = nmp->nm_dvp; - error = vget(vp, LK_EXCLUSIVE, current_proc()); - if (error) - return (error); + vpid = vp->v_id; + while (error = vget(vp, LK_EXCLUSIVE, current_proc())) { + /* vget may return ENOENT if the dir changes while in vget */ + /* If that happens, try vget again, else return the error */ + if ((error != ENOENT) || (vp->v_id == vpid)) + return (error); + vpid = vp->v_id; + } if (vp->v_type == VNON) vp->v_type = VDIR; vp->v_flag |= VROOT; @@ -1067,17 +1168,15 @@ nfs_sync(mp, waitfor, cred, p) * Force stale buffer cache information to be flushed. */ loop: - for (vp = mp->mnt_vnodelist.lh_first; - vp != NULL; - vp = vp->v_mntvnodes.le_next) { - int didhold = 0; + LIST_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) { + int didhold; /* * If the vnode that we are about to sync is no longer * associated with this mount point, start over. */ if (vp->v_mount != mp) goto loop; - if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL) + if (VOP_ISLOCKED(vp) || LIST_FIRST(&VTONFS(vp)->n_dirtyblkhd) == NULL) continue; if (vget(vp, LK_EXCLUSIVE, p)) goto loop; @@ -1101,7 +1200,7 @@ loop: static int nfs_vget(mp, ino, vpp) struct mount *mp; - ino_t ino; + void *ino; /* XXX void* or ino_t? */ struct vnode **vpp; { @@ -1175,7 +1274,12 @@ static int nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen, struct proc *p) { - int rv; + int error = 0, val; + struct sysctl_req *req; + struct vfsidctl vc; + struct mount *mp; + struct nfsmount *nmp; + struct vfsquery vq; /* * All names at this level are terminal. @@ -1183,6 +1287,25 @@ nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, if(namelen > 1) return ENOTDIR; /* overloaded */ + /* common code for "new style" VFS_CTL sysctl, get the mount. */ + switch (name[0]) { + case VFS_CTL_TIMEO: + case VFS_CTL_QUERY: + case VFS_CTL_NOLOCKS: + req = oldp; + error = SYSCTL_IN(req, &vc, sizeof(vc)); + if (error) + return (error); + mp = vfs_getvfs(&vc.vc_fsid); + if (mp == NULL) + return (ENOENT); + nmp = VFSTONFS(mp); + if (nmp == NULL) + return (ENOENT); + bzero(&vq, sizeof(vq)); + VCTLTOREQ(&vc, req); + } + switch(name[0]) { case NFS_NFSSTATS: if(!oldp) { @@ -1195,8 +1318,9 @@ nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, return ENOMEM; } - rv = copyout(&nfsstats, oldp, sizeof nfsstats); - if(rv) return rv; + error = copyout(&nfsstats, oldp, sizeof nfsstats); + if (error) + return (error); if(newp && newlen != sizeof nfsstats) return EINVAL; @@ -1205,9 +1329,50 @@ nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, return copyin(newp, &nfsstats, sizeof nfsstats); } return 0; - + case VFS_CTL_NOLOCKS: + val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; + if (req->oldptr != NULL) { + error = SYSCTL_OUT(req, &val, sizeof(val)); + if (error) + return (error); + } + if (req->newptr != NULL) { + error = SYSCTL_IN(req, &val, sizeof(val)); + if (error) + return (error); + if (val) + nmp->nm_flag |= NFSMNT_NOLOCKS; + else + nmp->nm_flag &= ~NFSMNT_NOLOCKS; + } + break; + case VFS_CTL_QUERY: + if ((nmp->nm_state & NFSSTA_TIMEO)) + vq.vq_flags |= VQ_NOTRESP; + if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && + (nmp->nm_state & NFSSTA_LOCKTIMEO)) + vq.vq_flags |= VQ_NOTRESPLOCK; + error = SYSCTL_OUT(req, &vq, sizeof(vq)); + break; + case VFS_CTL_TIMEO: + if (req->oldptr != NULL) { + error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, + sizeof(nmp->nm_tprintf_initial_delay)); + if (error) + return (error); + } + if (req->newptr != NULL) { + error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, + sizeof(nmp->nm_tprintf_initial_delay)); + if (error) + return (error); + if (nmp->nm_tprintf_initial_delay < 0) + nmp->nm_tprintf_initial_delay = 0; + } + break; default: - return EOPNOTSUPP; + return (ENOTSUP); } + return (error); }