Home | History | Annotate | Line # | Download | only in server
      1  1.4    simonb /*	$NetBSD: nfs_nfsdport.c,v 1.4 2021/03/29 02:13:38 simonb Exp $	*/
      2  1.1  dholland /*-
      3  1.1  dholland  * Copyright (c) 1989, 1993
      4  1.1  dholland  *	The Regents of the University of California.  All rights reserved.
      5  1.1  dholland  *
      6  1.1  dholland  * This code is derived from software contributed to Berkeley by
      7  1.1  dholland  * Rick Macklem at The University of Guelph.
      8  1.1  dholland  *
      9  1.1  dholland  * Redistribution and use in source and binary forms, with or without
     10  1.1  dholland  * modification, are permitted provided that the following conditions
     11  1.1  dholland  * are met:
     12  1.1  dholland  * 1. Redistributions of source code must retain the above copyright
     13  1.1  dholland  *    notice, this list of conditions and the following disclaimer.
     14  1.1  dholland  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.1  dholland  *    notice, this list of conditions and the following disclaimer in the
     16  1.1  dholland  *    documentation and/or other materials provided with the distribution.
     17  1.1  dholland  * 4. Neither the name of the University nor the names of its contributors
     18  1.1  dholland  *    may be used to endorse or promote products derived from this software
     19  1.1  dholland  *    without specific prior written permission.
     20  1.1  dholland  *
     21  1.1  dholland  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  1.1  dholland  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  1.1  dholland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  1.1  dholland  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  1.1  dholland  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  1.1  dholland  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  1.1  dholland  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  1.1  dholland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  1.1  dholland  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  1.1  dholland  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  1.1  dholland  * SUCH DAMAGE.
     32  1.1  dholland  *
     33  1.1  dholland  */
     34  1.1  dholland 
     35  1.1  dholland #include <sys/cdefs.h>
     36  1.2  pgoyette /* __FBSDID("FreeBSD: head/sys/fs/nfsserver/nfs_nfsdport.c 308212 2016-11-02 12:43:15Z kib "); */
     37  1.4    simonb __RCSID("$NetBSD: nfs_nfsdport.c,v 1.4 2021/03/29 02:13:38 simonb Exp $");
     38  1.1  dholland 
     39  1.2  pgoyette #if 0
     40  1.2  pgoyette #include <sys/capsicum.h>
     41  1.2  pgoyette #endif
     42  1.1  dholland 
     43  1.1  dholland /*
     44  1.1  dholland  * Functions that perform the vfs operations required by the routines in
     45  1.1  dholland  * nfsd_serv.c. It is hoped that this change will make the server more
     46  1.1  dholland  * portable.
     47  1.1  dholland  */
     48  1.1  dholland 
     49  1.2  pgoyette #include <fs/nfs/common/nfsport.h>
     50  1.1  dholland #include <sys/hash.h>
     51  1.1  dholland #include <sys/sysctl.h>
     52  1.2  pgoyette 
     53  1.2  pgoyette #if 0
     54  1.1  dholland #include <nlm/nlm_prot.h>
     55  1.1  dholland #include <nlm/nlm.h>
     56  1.2  pgoyette #endif
     57  1.1  dholland 
     58  1.1  dholland FEATURE(nfsd, "NFSv4 server");
     59  1.1  dholland 
     60  1.1  dholland extern u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
     61  1.1  dholland extern int nfsrv_useacl;
     62  1.1  dholland extern int newnfs_numnfsd;
     63  1.1  dholland extern struct mount nfsv4root_mnt;
     64  1.1  dholland extern struct nfsrv_stablefirst nfsrv_stablefirst;
     65  1.1  dholland extern void (*nfsd_call_servertimer)(void);
     66  1.1  dholland extern SVCPOOL	*nfsrvd_pool;
     67  1.1  dholland extern struct nfsv4lock nfsd_suspend_lock;
     68  1.2  pgoyette extern struct nfsclienthashhead *nfsclienthash;
     69  1.2  pgoyette extern struct nfslockhashhead *nfslockhash;
     70  1.2  pgoyette extern struct nfssessionhash *nfssessionhash;
     71  1.2  pgoyette extern int nfsrv_sessionhashsize;
     72  1.2  pgoyette extern struct nfsstatsv1 nfsstatsv1;
     73  1.1  dholland struct vfsoptlist nfsv4root_opt, nfsv4root_newopt;
     74  1.1  dholland NFSDLOCKMUTEX;
     75  1.1  dholland struct nfsrchash_bucket nfsrchash_table[NFSRVCACHE_HASHSIZE];
     76  1.2  pgoyette struct nfsrchash_bucket nfsrcahash_table[NFSRVCACHE_HASHSIZE];
     77  1.1  dholland struct mtx nfsrc_udpmtx;
     78  1.1  dholland struct mtx nfs_v4root_mutex;
     79  1.1  dholland struct nfsrvfh nfs_rootfh, nfs_pubfh;
     80  1.1  dholland int nfs_pubfhset = 0, nfs_rootfhset = 0;
     81  1.1  dholland struct proc *nfsd_master_proc = NULL;
     82  1.2  pgoyette int nfsd_debuglevel = 0;
     83  1.1  dholland static pid_t nfsd_master_pid = (pid_t)-1;
     84  1.1  dholland static char nfsd_master_comm[MAXCOMLEN + 1];
     85  1.1  dholland static struct timeval nfsd_master_start;
     86  1.1  dholland static uint32_t nfsv4_sysid = 0;
     87  1.1  dholland 
     88  1.1  dholland static int nfssvc_srvcall(struct thread *, struct nfssvc_args *,
     89  1.1  dholland     struct ucred *);
     90  1.1  dholland 
     91  1.1  dholland int nfsrv_enable_crossmntpt = 1;
     92  1.1  dholland static int nfs_commit_blks;
     93  1.1  dholland static int nfs_commit_miss;
     94  1.1  dholland extern int nfsrv_issuedelegs;
     95  1.1  dholland extern int nfsrv_dolocallocks;
     96  1.2  pgoyette extern int nfsd_enable_stringtouid;
     97  1.1  dholland 
     98  1.2  pgoyette SYSCTL_NODE(_vfs, OID_AUTO, nfsd, CTLFLAG_RW, 0, "NFS server");
     99  1.1  dholland SYSCTL_INT(_vfs_nfsd, OID_AUTO, mirrormnt, CTLFLAG_RW,
    100  1.1  dholland     &nfsrv_enable_crossmntpt, 0, "Enable nfsd to cross mount points");
    101  1.1  dholland SYSCTL_INT(_vfs_nfsd, OID_AUTO, commit_blks, CTLFLAG_RW, &nfs_commit_blks,
    102  1.1  dholland     0, "");
    103  1.1  dholland SYSCTL_INT(_vfs_nfsd, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss,
    104  1.1  dholland     0, "");
    105  1.1  dholland SYSCTL_INT(_vfs_nfsd, OID_AUTO, issue_delegations, CTLFLAG_RW,
    106  1.1  dholland     &nfsrv_issuedelegs, 0, "Enable nfsd to issue delegations");
    107  1.1  dholland SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_locallocks, CTLFLAG_RW,
    108  1.1  dholland     &nfsrv_dolocallocks, 0, "Enable nfsd to acquire local locks on files");
    109  1.2  pgoyette SYSCTL_INT(_vfs_nfsd, OID_AUTO, debuglevel, CTLFLAG_RW, &nfsd_debuglevel,
    110  1.2  pgoyette     0, "Debug level for NFS server");
    111  1.2  pgoyette SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_stringtouid, CTLFLAG_RW,
    112  1.2  pgoyette     &nfsd_enable_stringtouid, 0, "Enable nfsd to accept numeric owner_names");
    113  1.1  dholland 
    114  1.1  dholland #define	MAX_REORDERED_RPC	16
    115  1.1  dholland #define	NUM_HEURISTIC		1031
    116  1.1  dholland #define	NHUSE_INIT		64
    117  1.1  dholland #define	NHUSE_INC		16
    118  1.1  dholland #define	NHUSE_MAX		2048
    119  1.1  dholland 
    120  1.1  dholland static struct nfsheur {
    121  1.1  dholland 	struct vnode *nh_vp;	/* vp to match (unreferenced pointer) */
    122  1.1  dholland 	off_t nh_nextoff;	/* next offset for sequential detection */
    123  1.1  dholland 	int nh_use;		/* use count for selection */
    124  1.1  dholland 	int nh_seqcount;	/* heuristic */
    125  1.1  dholland } nfsheur[NUM_HEURISTIC];
    126  1.1  dholland 
    127  1.1  dholland 
    128  1.1  dholland /*
    129  1.1  dholland  * Heuristic to detect sequential operation.
    130  1.1  dholland  */
    131  1.1  dholland static struct nfsheur *
    132  1.1  dholland nfsrv_sequential_heuristic(struct uio *uio, struct vnode *vp)
    133  1.1  dholland {
    134  1.1  dholland 	struct nfsheur *nh;
    135  1.1  dholland 	int hi, try;
    136  1.1  dholland 
    137  1.1  dholland 	/* Locate best candidate. */
    138  1.1  dholland 	try = 32;
    139  1.4    simonb 	hi = ((int)(vaddr_t)vp / sizeof(struct vnode)) % NUM_HEURISTIC;
    140  1.1  dholland 	nh = &nfsheur[hi];
    141  1.1  dholland 	while (try--) {
    142  1.1  dholland 		if (nfsheur[hi].nh_vp == vp) {
    143  1.1  dholland 			nh = &nfsheur[hi];
    144  1.1  dholland 			break;
    145  1.1  dholland 		}
    146  1.1  dholland 		if (nfsheur[hi].nh_use > 0)
    147  1.1  dholland 			--nfsheur[hi].nh_use;
    148  1.1  dholland 		hi = (hi + 1) % NUM_HEURISTIC;
    149  1.1  dholland 		if (nfsheur[hi].nh_use < nh->nh_use)
    150  1.1  dholland 			nh = &nfsheur[hi];
    151  1.1  dholland 	}
    152  1.1  dholland 
    153  1.1  dholland 	/* Initialize hint if this is a new file. */
    154  1.1  dholland 	if (nh->nh_vp != vp) {
    155  1.1  dholland 		nh->nh_vp = vp;
    156  1.1  dholland 		nh->nh_nextoff = uio->uio_offset;
    157  1.1  dholland 		nh->nh_use = NHUSE_INIT;
    158  1.1  dholland 		if (uio->uio_offset == 0)
    159  1.1  dholland 			nh->nh_seqcount = 4;
    160  1.1  dholland 		else
    161  1.1  dholland 			nh->nh_seqcount = 1;
    162  1.1  dholland 	}
    163  1.1  dholland 
    164  1.1  dholland 	/* Calculate heuristic. */
    165  1.1  dholland 	if ((uio->uio_offset == 0 && nh->nh_seqcount > 0) ||
    166  1.1  dholland 	    uio->uio_offset == nh->nh_nextoff) {
    167  1.1  dholland 		/* See comments in vfs_vnops.c:sequential_heuristic(). */
    168  1.1  dholland 		nh->nh_seqcount += howmany(uio->uio_resid, 16384);
    169  1.1  dholland 		if (nh->nh_seqcount > IO_SEQMAX)
    170  1.1  dholland 			nh->nh_seqcount = IO_SEQMAX;
    171  1.1  dholland 	} else if (qabs(uio->uio_offset - nh->nh_nextoff) <= MAX_REORDERED_RPC *
    172  1.1  dholland 	    imax(vp->v_mount->mnt_stat.f_iosize, uio->uio_resid)) {
    173  1.1  dholland 		/* Probably a reordered RPC, leave seqcount alone. */
    174  1.1  dholland 	} else if (nh->nh_seqcount > 1) {
    175  1.1  dholland 		nh->nh_seqcount /= 2;
    176  1.1  dholland 	} else {
    177  1.1  dholland 		nh->nh_seqcount = 0;
    178  1.1  dholland 	}
    179  1.1  dholland 	nh->nh_use += NHUSE_INC;
    180  1.1  dholland 	if (nh->nh_use > NHUSE_MAX)
    181  1.1  dholland 		nh->nh_use = NHUSE_MAX;
    182  1.1  dholland 	return (nh);
    183  1.1  dholland }
    184  1.1  dholland 
    185  1.1  dholland /*
    186  1.1  dholland  * Get attributes into nfsvattr structure.
    187  1.1  dholland  */
    188  1.1  dholland int
    189  1.1  dholland nfsvno_getattr(struct vnode *vp, struct nfsvattr *nvap, struct ucred *cred,
    190  1.1  dholland     struct thread *p, int vpislocked)
    191  1.1  dholland {
    192  1.1  dholland 	int error, lockedit = 0;
    193  1.1  dholland 
    194  1.1  dholland 	if (vpislocked == 0) {
    195  1.1  dholland 		/*
    196  1.1  dholland 		 * When vpislocked == 0, the vnode is either exclusively
    197  1.1  dholland 		 * locked by this thread or not locked by this thread.
    198  1.1  dholland 		 * As such, shared lock it, if not exclusively locked.
    199  1.1  dholland 		 */
    200  1.1  dholland 		if (NFSVOPISLOCKED(vp) != LK_EXCLUSIVE) {
    201  1.1  dholland 			lockedit = 1;
    202  1.1  dholland 			NFSVOPLOCK(vp, LK_SHARED | LK_RETRY);
    203  1.1  dholland 		}
    204  1.1  dholland 	}
    205  1.1  dholland 	error = VOP_GETATTR(vp, &nvap->na_vattr, cred);
    206  1.1  dholland 	if (lockedit != 0)
    207  1.1  dholland 		NFSVOPUNLOCK(vp, 0);
    208  1.1  dholland 
    209  1.1  dholland 	NFSEXITCODE(error);
    210  1.1  dholland 	return (error);
    211  1.1  dholland }
    212  1.1  dholland 
    213  1.1  dholland /*
    214  1.1  dholland  * Get a file handle for a vnode.
    215  1.1  dholland  */
    216  1.1  dholland int
    217  1.1  dholland nfsvno_getfh(struct vnode *vp, fhandle_t *fhp, struct thread *p)
    218  1.1  dholland {
    219  1.1  dholland 	int error;
    220  1.1  dholland 
    221  1.1  dholland 	NFSBZERO((caddr_t)fhp, sizeof(fhandle_t));
    222  1.1  dholland 	fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
    223  1.1  dholland 	error = VOP_VPTOFH(vp, &fhp->fh_fid);
    224  1.1  dholland 
    225  1.1  dholland 	NFSEXITCODE(error);
    226  1.1  dholland 	return (error);
    227  1.1  dholland }
    228  1.1  dholland 
    229  1.1  dholland /*
    230  1.1  dholland  * Perform access checking for vnodes obtained from file handles that would
    231  1.1  dholland  * refer to files already opened by a Unix client. You cannot just use
    232  1.1  dholland  * vn_writechk() and VOP_ACCESSX() for two reasons.
    233  1.1  dholland  * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write
    234  1.1  dholland  *     case.
    235  1.1  dholland  * 2 - The owner is to be given access irrespective of mode bits for some
    236  1.1  dholland  *     operations, so that processes that chmod after opening a file don't
    237  1.1  dholland  *     break.
    238  1.1  dholland  */
    239  1.1  dholland int
    240  1.1  dholland nfsvno_accchk(struct vnode *vp, accmode_t accmode, struct ucred *cred,
    241  1.1  dholland     struct nfsexstuff *exp, struct thread *p, int override, int vpislocked,
    242  1.1  dholland     u_int32_t *supportedtypep)
    243  1.1  dholland {
    244  1.1  dholland 	struct vattr vattr;
    245  1.1  dholland 	int error = 0, getret = 0;
    246  1.1  dholland 
    247  1.1  dholland 	if (vpislocked == 0) {
    248  1.1  dholland 		if (NFSVOPLOCK(vp, LK_SHARED) != 0) {
    249  1.1  dholland 			error = EPERM;
    250  1.1  dholland 			goto out;
    251  1.1  dholland 		}
    252  1.1  dholland 	}
    253  1.1  dholland 	if (accmode & VWRITE) {
    254  1.1  dholland 		/* Just vn_writechk() changed to check rdonly */
    255  1.1  dholland 		/*
    256  1.1  dholland 		 * Disallow write attempts on read-only file systems;
    257  1.1  dholland 		 * unless the file is a socket or a block or character
    258  1.1  dholland 		 * device resident on the file system.
    259  1.1  dholland 		 */
    260  1.1  dholland 		if (NFSVNO_EXRDONLY(exp) ||
    261  1.1  dholland 		    (vp->v_mount->mnt_flag & MNT_RDONLY)) {
    262  1.1  dholland 			switch (vp->v_type) {
    263  1.1  dholland 			case VREG:
    264  1.1  dholland 			case VDIR:
    265  1.1  dholland 			case VLNK:
    266  1.1  dholland 				error = EROFS;
    267  1.1  dholland 			default:
    268  1.1  dholland 				break;
    269  1.1  dholland 			}
    270  1.1  dholland 		}
    271  1.1  dholland 		/*
    272  1.1  dholland 		 * If there's shared text associated with
    273  1.1  dholland 		 * the inode, try to free it up once.  If
    274  1.1  dholland 		 * we fail, we can't allow writing.
    275  1.1  dholland 		 */
    276  1.1  dholland 		if (VOP_IS_TEXT(vp) && error == 0)
    277  1.1  dholland 			error = ETXTBSY;
    278  1.1  dholland 	}
    279  1.1  dholland 	if (error != 0) {
    280  1.1  dholland 		if (vpislocked == 0)
    281  1.1  dholland 			NFSVOPUNLOCK(vp, 0);
    282  1.1  dholland 		goto out;
    283  1.1  dholland 	}
    284  1.1  dholland 
    285  1.1  dholland 	/*
    286  1.1  dholland 	 * Should the override still be applied when ACLs are enabled?
    287  1.1  dholland 	 */
    288  1.1  dholland 	error = VOP_ACCESSX(vp, accmode, cred, p);
    289  1.1  dholland 	if (error != 0 && (accmode & (VDELETE | VDELETE_CHILD))) {
    290  1.1  dholland 		/*
    291  1.1  dholland 		 * Try again with VEXPLICIT_DENY, to see if the test for
    292  1.1  dholland 		 * deletion is supported.
    293  1.1  dholland 		 */
    294  1.1  dholland 		error = VOP_ACCESSX(vp, accmode | VEXPLICIT_DENY, cred, p);
    295  1.1  dholland 		if (error == 0) {
    296  1.1  dholland 			if (vp->v_type == VDIR) {
    297  1.1  dholland 				accmode &= ~(VDELETE | VDELETE_CHILD);
    298  1.1  dholland 				accmode |= VWRITE;
    299  1.1  dholland 				error = VOP_ACCESSX(vp, accmode, cred, p);
    300  1.1  dholland 			} else if (supportedtypep != NULL) {
    301  1.1  dholland 				*supportedtypep &= ~NFSACCESS_DELETE;
    302  1.1  dholland 			}
    303  1.1  dholland 		}
    304  1.1  dholland 	}
    305  1.1  dholland 
    306  1.1  dholland 	/*
    307  1.1  dholland 	 * Allow certain operations for the owner (reads and writes
    308  1.1  dholland 	 * on files that are already open).
    309  1.1  dholland 	 */
    310  1.1  dholland 	if (override != NFSACCCHK_NOOVERRIDE &&
    311  1.1  dholland 	    (error == EPERM || error == EACCES)) {
    312  1.1  dholland 		if (cred->cr_uid == 0 && (override & NFSACCCHK_ALLOWROOT))
    313  1.1  dholland 			error = 0;
    314  1.1  dholland 		else if (override & NFSACCCHK_ALLOWOWNER) {
    315  1.1  dholland 			getret = VOP_GETATTR(vp, &vattr, cred);
    316  1.1  dholland 			if (getret == 0 && cred->cr_uid == vattr.va_uid)
    317  1.1  dholland 				error = 0;
    318  1.1  dholland 		}
    319  1.1  dholland 	}
    320  1.1  dholland 	if (vpislocked == 0)
    321  1.1  dholland 		NFSVOPUNLOCK(vp, 0);
    322  1.1  dholland 
    323  1.1  dholland out:
    324  1.1  dholland 	NFSEXITCODE(error);
    325  1.1  dholland 	return (error);
    326  1.1  dholland }
    327  1.1  dholland 
    328  1.1  dholland /*
    329  1.1  dholland  * Set attribute(s) vnop.
    330  1.1  dholland  */
    331  1.1  dholland int
    332  1.1  dholland nfsvno_setattr(struct vnode *vp, struct nfsvattr *nvap, struct ucred *cred,
    333  1.1  dholland     struct thread *p, struct nfsexstuff *exp)
    334  1.1  dholland {
    335  1.1  dholland 	int error;
    336  1.1  dholland 
    337  1.1  dholland 	error = VOP_SETATTR(vp, &nvap->na_vattr, cred);
    338  1.1  dholland 	NFSEXITCODE(error);
    339  1.1  dholland 	return (error);
    340  1.1  dholland }
    341  1.1  dholland 
    342  1.1  dholland /*
    343  1.1  dholland  * Set up nameidata for a lookup() call and do it.
    344  1.1  dholland  */
    345  1.1  dholland int
    346  1.1  dholland nfsvno_namei(struct nfsrv_descript *nd, struct nameidata *ndp,
    347  1.1  dholland     struct vnode *dp, int islocked, struct nfsexstuff *exp, struct thread *p,
    348  1.1  dholland     struct vnode **retdirp)
    349  1.1  dholland {
    350  1.1  dholland 	struct componentname *cnp = &ndp->ni_cnd;
    351  1.1  dholland 	int i;
    352  1.1  dholland 	struct iovec aiov;
    353  1.1  dholland 	struct uio auio;
    354  1.1  dholland 	int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0, linklen;
    355  1.1  dholland 	int error = 0, crossmnt;
    356  1.1  dholland 	char *cp;
    357  1.1  dholland 
    358  1.1  dholland 	*retdirp = NULL;
    359  1.1  dholland 	cnp->cn_nameptr = cnp->cn_pnbuf;
    360  1.2  pgoyette 	ndp->ni_lcf = 0;
    361  1.1  dholland 	/*
    362  1.1  dholland 	 * Extract and set starting directory.
    363  1.1  dholland 	 */
    364  1.1  dholland 	if (dp->v_type != VDIR) {
    365  1.1  dholland 		if (islocked)
    366  1.1  dholland 			vput(dp);
    367  1.1  dholland 		else
    368  1.1  dholland 			vrele(dp);
    369  1.1  dholland 		nfsvno_relpathbuf(ndp);
    370  1.1  dholland 		error = ENOTDIR;
    371  1.1  dholland 		goto out1;
    372  1.1  dholland 	}
    373  1.1  dholland 	if (islocked)
    374  1.1  dholland 		NFSVOPUNLOCK(dp, 0);
    375  1.1  dholland 	VREF(dp);
    376  1.1  dholland 	*retdirp = dp;
    377  1.1  dholland 	if (NFSVNO_EXRDONLY(exp))
    378  1.1  dholland 		cnp->cn_flags |= RDONLY;
    379  1.1  dholland 	ndp->ni_segflg = UIO_SYSSPACE;
    380  1.1  dholland 	crossmnt = 1;
    381  1.1  dholland 
    382  1.1  dholland 	if (nd->nd_flag & ND_PUBLOOKUP) {
    383  1.1  dholland 		ndp->ni_loopcnt = 0;
    384  1.1  dholland 		if (cnp->cn_pnbuf[0] == '/') {
    385  1.1  dholland 			vrele(dp);
    386  1.1  dholland 			/*
    387  1.1  dholland 			 * Check for degenerate pathnames here, since lookup()
    388  1.1  dholland 			 * panics on them.
    389  1.1  dholland 			 */
    390  1.1  dholland 			for (i = 1; i < ndp->ni_pathlen; i++)
    391  1.1  dholland 				if (cnp->cn_pnbuf[i] != '/')
    392  1.1  dholland 					break;
    393  1.1  dholland 			if (i == ndp->ni_pathlen) {
    394  1.1  dholland 				error = NFSERR_ACCES;
    395  1.1  dholland 				goto out;
    396  1.1  dholland 			}
    397  1.1  dholland 			dp = rootvnode;
    398  1.1  dholland 			VREF(dp);
    399  1.1  dholland 		}
    400  1.1  dholland 	} else if ((nfsrv_enable_crossmntpt == 0 && NFSVNO_EXPORTED(exp)) ||
    401  1.1  dholland 	    (nd->nd_flag & ND_NFSV4) == 0) {
    402  1.1  dholland 		/*
    403  1.1  dholland 		 * Only cross mount points for NFSv4 when doing a
    404  1.1  dholland 		 * mount while traversing the file system above
    405  1.1  dholland 		 * the mount point, unless nfsrv_enable_crossmntpt is set.
    406  1.1  dholland 		 */
    407  1.1  dholland 		cnp->cn_flags |= NOCROSSMOUNT;
    408  1.1  dholland 		crossmnt = 0;
    409  1.1  dholland 	}
    410  1.1  dholland 
    411  1.1  dholland 	/*
    412  1.1  dholland 	 * Initialize for scan, set ni_startdir and bump ref on dp again
    413  1.1  dholland 	 * because lookup() will dereference ni_startdir.
    414  1.1  dholland 	 */
    415  1.1  dholland 
    416  1.1  dholland 	cnp->cn_thread = p;
    417  1.1  dholland 	ndp->ni_startdir = dp;
    418  1.1  dholland 	ndp->ni_rootdir = rootvnode;
    419  1.1  dholland 	ndp->ni_topdir = NULL;
    420  1.1  dholland 
    421  1.1  dholland 	if (!lockleaf)
    422  1.1  dholland 		cnp->cn_flags |= LOCKLEAF;
    423  1.1  dholland 	for (;;) {
    424  1.1  dholland 		cnp->cn_nameptr = cnp->cn_pnbuf;
    425  1.1  dholland 		/*
    426  1.1  dholland 		 * Call lookup() to do the real work.  If an error occurs,
    427  1.1  dholland 		 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
    428  1.1  dholland 		 * we do not have to dereference anything before returning.
    429  1.1  dholland 		 * In either case ni_startdir will be dereferenced and NULLed
    430  1.1  dholland 		 * out.
    431  1.1  dholland 		 */
    432  1.1  dholland 		error = lookup(ndp);
    433  1.1  dholland 		if (error)
    434  1.1  dholland 			break;
    435  1.1  dholland 
    436  1.1  dholland 		/*
    437  1.1  dholland 		 * Check for encountering a symbolic link.  Trivial
    438  1.1  dholland 		 * termination occurs if no symlink encountered.
    439  1.1  dholland 		 */
    440  1.1  dholland 		if ((cnp->cn_flags & ISSYMLINK) == 0) {
    441  1.1  dholland 			if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
    442  1.1  dholland 				nfsvno_relpathbuf(ndp);
    443  1.1  dholland 			if (ndp->ni_vp && !lockleaf)
    444  1.1  dholland 				NFSVOPUNLOCK(ndp->ni_vp, 0);
    445  1.1  dholland 			break;
    446  1.1  dholland 		}
    447  1.1  dholland 
    448  1.1  dholland 		/*
    449  1.1  dholland 		 * Validate symlink
    450  1.1  dholland 		 */
    451  1.1  dholland 		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
    452  1.1  dholland 			NFSVOPUNLOCK(ndp->ni_dvp, 0);
    453  1.1  dholland 		if (!(nd->nd_flag & ND_PUBLOOKUP)) {
    454  1.1  dholland 			error = EINVAL;
    455  1.1  dholland 			goto badlink2;
    456  1.1  dholland 		}
    457  1.1  dholland 
    458  1.1  dholland 		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
    459  1.1  dholland 			error = ELOOP;
    460  1.1  dholland 			goto badlink2;
    461  1.1  dholland 		}
    462  1.1  dholland 		if (ndp->ni_pathlen > 1)
    463  1.1  dholland 			cp = uma_zalloc(namei_zone, M_WAITOK);
    464  1.1  dholland 		else
    465  1.1  dholland 			cp = cnp->cn_pnbuf;
    466  1.1  dholland 		aiov.iov_base = cp;
    467  1.1  dholland 		aiov.iov_len = MAXPATHLEN;
    468  1.1  dholland 		auio.uio_iov = &aiov;
    469  1.1  dholland 		auio.uio_iovcnt = 1;
    470  1.1  dholland 		auio.uio_offset = 0;
    471  1.1  dholland 		auio.uio_rw = UIO_READ;
    472  1.1  dholland 		auio.uio_segflg = UIO_SYSSPACE;
    473  1.1  dholland 		auio.uio_td = NULL;
    474  1.1  dholland 		auio.uio_resid = MAXPATHLEN;
    475  1.1  dholland 		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
    476  1.1  dholland 		if (error) {
    477  1.1  dholland 		badlink1:
    478  1.1  dholland 			if (ndp->ni_pathlen > 1)
    479  1.1  dholland 				uma_zfree(namei_zone, cp);
    480  1.1  dholland 		badlink2:
    481  1.1  dholland 			vrele(ndp->ni_dvp);
    482  1.1  dholland 			vput(ndp->ni_vp);
    483  1.1  dholland 			break;
    484  1.1  dholland 		}
    485  1.1  dholland 		linklen = MAXPATHLEN - auio.uio_resid;
    486  1.1  dholland 		if (linklen == 0) {
    487  1.1  dholland 			error = ENOENT;
    488  1.1  dholland 			goto badlink1;
    489  1.1  dholland 		}
    490  1.1  dholland 		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
    491  1.1  dholland 			error = ENAMETOOLONG;
    492  1.1  dholland 			goto badlink1;
    493  1.1  dholland 		}
    494  1.1  dholland 
    495  1.1  dholland 		/*
    496  1.1  dholland 		 * Adjust or replace path
    497  1.1  dholland 		 */
    498  1.1  dholland 		if (ndp->ni_pathlen > 1) {
    499  1.1  dholland 			NFSBCOPY(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
    500  1.1  dholland 			uma_zfree(namei_zone, cnp->cn_pnbuf);
    501  1.1  dholland 			cnp->cn_pnbuf = cp;
    502  1.1  dholland 		} else
    503  1.1  dholland 			cnp->cn_pnbuf[linklen] = '\0';
    504  1.1  dholland 		ndp->ni_pathlen += linklen;
    505  1.1  dholland 
    506  1.1  dholland 		/*
    507  1.1  dholland 		 * Cleanup refs for next loop and check if root directory
    508  1.1  dholland 		 * should replace current directory.  Normally ni_dvp
    509  1.1  dholland 		 * becomes the new base directory and is cleaned up when
    510  1.1  dholland 		 * we loop.  Explicitly null pointers after invalidation
    511  1.1  dholland 		 * to clarify operation.
    512  1.1  dholland 		 */
    513  1.1  dholland 		vput(ndp->ni_vp);
    514  1.1  dholland 		ndp->ni_vp = NULL;
    515  1.1  dholland 
    516  1.1  dholland 		if (cnp->cn_pnbuf[0] == '/') {
    517  1.1  dholland 			vrele(ndp->ni_dvp);
    518  1.1  dholland 			ndp->ni_dvp = ndp->ni_rootdir;
    519  1.1  dholland 			VREF(ndp->ni_dvp);
    520  1.1  dholland 		}
    521  1.1  dholland 		ndp->ni_startdir = ndp->ni_dvp;
    522  1.1  dholland 		ndp->ni_dvp = NULL;
    523  1.1  dholland 	}
    524  1.1  dholland 	if (!lockleaf)
    525  1.1  dholland 		cnp->cn_flags &= ~LOCKLEAF;
    526  1.1  dholland 
    527  1.1  dholland out:
    528  1.1  dholland 	if (error) {
    529  1.1  dholland 		nfsvno_relpathbuf(ndp);
    530  1.1  dholland 		ndp->ni_vp = NULL;
    531  1.1  dholland 		ndp->ni_dvp = NULL;
    532  1.1  dholland 		ndp->ni_startdir = NULL;
    533  1.1  dholland 	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
    534  1.1  dholland 		ndp->ni_dvp = NULL;
    535  1.1  dholland 	}
    536  1.1  dholland 
    537  1.1  dholland out1:
    538  1.1  dholland 	NFSEXITCODE2(error, nd);
    539  1.1  dholland 	return (error);
    540  1.1  dholland }
    541  1.1  dholland 
    542  1.1  dholland /*
    543  1.1  dholland  * Set up a pathname buffer and return a pointer to it and, optionally
    544  1.1  dholland  * set a hash pointer.
    545  1.1  dholland  */
    546  1.1  dholland void
    547  1.1  dholland nfsvno_setpathbuf(struct nameidata *ndp, char **bufpp, u_long **hashpp)
    548  1.1  dholland {
    549  1.1  dholland 	struct componentname *cnp = &ndp->ni_cnd;
    550  1.1  dholland 
    551  1.1  dholland 	cnp->cn_flags |= (NOMACCHECK | HASBUF);
    552  1.1  dholland 	cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
    553  1.1  dholland 	if (hashpp != NULL)
    554  1.1  dholland 		*hashpp = NULL;
    555  1.1  dholland 	*bufpp = cnp->cn_pnbuf;
    556  1.1  dholland }
    557  1.1  dholland 
    558  1.1  dholland /*
    559  1.1  dholland  * Release the above path buffer, if not released by nfsvno_namei().
    560  1.1  dholland  */
    561  1.1  dholland void
    562  1.1  dholland nfsvno_relpathbuf(struct nameidata *ndp)
    563  1.1  dholland {
    564  1.1  dholland 
    565  1.1  dholland 	if ((ndp->ni_cnd.cn_flags & HASBUF) == 0)
    566  1.1  dholland 		panic("nfsrelpath");
    567  1.1  dholland 	uma_zfree(namei_zone, ndp->ni_cnd.cn_pnbuf);
    568  1.1  dholland 	ndp->ni_cnd.cn_flags &= ~HASBUF;
    569  1.1  dholland }
    570  1.1  dholland 
    571  1.1  dholland /*
    572  1.1  dholland  * Readlink vnode op into an mbuf list.
    573  1.1  dholland  */
    574  1.1  dholland int
    575  1.1  dholland nfsvno_readlink(struct vnode *vp, struct ucred *cred, struct thread *p,
    576  1.1  dholland     struct mbuf **mpp, struct mbuf **mpendp, int *lenp)
    577  1.1  dholland {
    578  1.1  dholland 	struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
    579  1.1  dholland 	struct iovec *ivp = iv;
    580  1.1  dholland 	struct uio io, *uiop = &io;
    581  1.1  dholland 	struct mbuf *mp, *mp2 = NULL, *mp3 = NULL;
    582  1.1  dholland 	int i, len, tlen, error = 0;
    583  1.1  dholland 
    584  1.1  dholland 	len = 0;
    585  1.1  dholland 	i = 0;
    586  1.1  dholland 	while (len < NFS_MAXPATHLEN) {
    587  1.1  dholland 		NFSMGET(mp);
    588  1.1  dholland 		MCLGET(mp, M_WAITOK);
    589  1.2  pgoyette 		mp->m_len = M_SIZE(mp);
    590  1.1  dholland 		if (len == 0) {
    591  1.1  dholland 			mp3 = mp2 = mp;
    592  1.1  dholland 		} else {
    593  1.1  dholland 			mp2->m_next = mp;
    594  1.1  dholland 			mp2 = mp;
    595  1.1  dholland 		}
    596  1.1  dholland 		if ((len + mp->m_len) > NFS_MAXPATHLEN) {
    597  1.1  dholland 			mp->m_len = NFS_MAXPATHLEN - len;
    598  1.1  dholland 			len = NFS_MAXPATHLEN;
    599  1.1  dholland 		} else {
    600  1.1  dholland 			len += mp->m_len;
    601  1.1  dholland 		}
    602  1.1  dholland 		ivp->iov_base = mtod(mp, caddr_t);
    603  1.1  dholland 		ivp->iov_len = mp->m_len;
    604  1.1  dholland 		i++;
    605  1.1  dholland 		ivp++;
    606  1.1  dholland 	}
    607  1.1  dholland 	uiop->uio_iov = iv;
    608  1.1  dholland 	uiop->uio_iovcnt = i;
    609  1.1  dholland 	uiop->uio_offset = 0;
    610  1.1  dholland 	uiop->uio_resid = len;
    611  1.1  dholland 	uiop->uio_rw = UIO_READ;
    612  1.1  dholland 	uiop->uio_segflg = UIO_SYSSPACE;
    613  1.1  dholland 	uiop->uio_td = NULL;
    614  1.1  dholland 	error = VOP_READLINK(vp, uiop, cred);
    615  1.1  dholland 	if (error) {
    616  1.1  dholland 		m_freem(mp3);
    617  1.1  dholland 		*lenp = 0;
    618  1.1  dholland 		goto out;
    619  1.1  dholland 	}
    620  1.1  dholland 	if (uiop->uio_resid > 0) {
    621  1.1  dholland 		len -= uiop->uio_resid;
    622  1.1  dholland 		tlen = NFSM_RNDUP(len);
    623  1.1  dholland 		nfsrv_adj(mp3, NFS_MAXPATHLEN - tlen, tlen - len);
    624  1.1  dholland 	}
    625  1.1  dholland 	*lenp = len;
    626  1.1  dholland 	*mpp = mp3;
    627  1.1  dholland 	*mpendp = mp;
    628  1.1  dholland 
    629  1.1  dholland out:
    630  1.1  dholland 	NFSEXITCODE(error);
    631  1.1  dholland 	return (error);
    632  1.1  dholland }
    633  1.1  dholland 
    634  1.1  dholland /*
    635  1.1  dholland  * Read vnode op call into mbuf list.
    636  1.1  dholland  */
    637  1.1  dholland int
    638  1.1  dholland nfsvno_read(struct vnode *vp, off_t off, int cnt, struct ucred *cred,
    639  1.1  dholland     struct thread *p, struct mbuf **mpp, struct mbuf **mpendp)
    640  1.1  dholland {
    641  1.1  dholland 	struct mbuf *m;
    642  1.1  dholland 	int i;
    643  1.1  dholland 	struct iovec *iv;
    644  1.1  dholland 	struct iovec *iv2;
    645  1.1  dholland 	int error = 0, len, left, siz, tlen, ioflag = 0;
    646  1.1  dholland 	struct mbuf *m2 = NULL, *m3;
    647  1.1  dholland 	struct uio io, *uiop = &io;
    648  1.1  dholland 	struct nfsheur *nh;
    649  1.1  dholland 
    650  1.1  dholland 	len = left = NFSM_RNDUP(cnt);
    651  1.1  dholland 	m3 = NULL;
    652  1.1  dholland 	/*
    653  1.1  dholland 	 * Generate the mbuf list with the uio_iov ref. to it.
    654  1.1  dholland 	 */
    655  1.1  dholland 	i = 0;
    656  1.1  dholland 	while (left > 0) {
    657  1.1  dholland 		NFSMGET(m);
    658  1.1  dholland 		MCLGET(m, M_WAITOK);
    659  1.1  dholland 		m->m_len = 0;
    660  1.3  riastrad 		siz = uimin(M_TRAILINGSPACE(m), left);
    661  1.1  dholland 		left -= siz;
    662  1.1  dholland 		i++;
    663  1.1  dholland 		if (m3)
    664  1.1  dholland 			m2->m_next = m;
    665  1.1  dholland 		else
    666  1.1  dholland 			m3 = m;
    667  1.1  dholland 		m2 = m;
    668  1.1  dholland 	}
    669  1.1  dholland 	MALLOC(iv, struct iovec *, i * sizeof (struct iovec),
    670  1.1  dholland 	    M_TEMP, M_WAITOK);
    671  1.1  dholland 	uiop->uio_iov = iv2 = iv;
    672  1.1  dholland 	m = m3;
    673  1.1  dholland 	left = len;
    674  1.1  dholland 	i = 0;
    675  1.1  dholland 	while (left > 0) {
    676  1.1  dholland 		if (m == NULL)
    677  1.1  dholland 			panic("nfsvno_read iov");
    678  1.3  riastrad 		siz = uimin(M_TRAILINGSPACE(m), left);
    679  1.1  dholland 		if (siz > 0) {
    680  1.1  dholland 			iv->iov_base = mtod(m, caddr_t) + m->m_len;
    681  1.1  dholland 			iv->iov_len = siz;
    682  1.1  dholland 			m->m_len += siz;
    683  1.1  dholland 			left -= siz;
    684  1.1  dholland 			iv++;
    685  1.1  dholland 			i++;
    686  1.1  dholland 		}
    687  1.1  dholland 		m = m->m_next;
    688  1.1  dholland 	}
    689  1.1  dholland 	uiop->uio_iovcnt = i;
    690  1.1  dholland 	uiop->uio_offset = off;
    691  1.1  dholland 	uiop->uio_resid = len;
    692  1.1  dholland 	uiop->uio_rw = UIO_READ;
    693  1.1  dholland 	uiop->uio_segflg = UIO_SYSSPACE;
    694  1.2  pgoyette 	uiop->uio_td = NULL;
    695  1.1  dholland 	nh = nfsrv_sequential_heuristic(uiop, vp);
    696  1.1  dholland 	ioflag |= nh->nh_seqcount << IO_SEQSHIFT;
    697  1.2  pgoyette 	/* XXX KDM make this more systematic? */
    698  1.2  pgoyette 	nfsstatsv1.srvbytes[NFSV4OP_READ] += uiop->uio_resid;
    699  1.1  dholland 	error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred);
    700  1.1  dholland 	FREE((caddr_t)iv2, M_TEMP);
    701  1.1  dholland 	if (error) {
    702  1.1  dholland 		m_freem(m3);
    703  1.1  dholland 		*mpp = NULL;
    704  1.1  dholland 		goto out;
    705  1.1  dholland 	}
    706  1.1  dholland 	nh->nh_nextoff = uiop->uio_offset;
    707  1.1  dholland 	tlen = len - uiop->uio_resid;
    708  1.1  dholland 	cnt = cnt < tlen ? cnt : tlen;
    709  1.1  dholland 	tlen = NFSM_RNDUP(cnt);
    710  1.1  dholland 	if (tlen == 0) {
    711  1.1  dholland 		m_freem(m3);
    712  1.1  dholland 		m3 = NULL;
    713  1.1  dholland 	} else if (len != tlen || tlen != cnt)
    714  1.1  dholland 		nfsrv_adj(m3, len - tlen, tlen - cnt);
    715  1.1  dholland 	*mpp = m3;
    716  1.1  dholland 	*mpendp = m2;
    717  1.1  dholland 
    718  1.1  dholland out:
    719  1.1  dholland 	NFSEXITCODE(error);
    720  1.1  dholland 	return (error);
    721  1.1  dholland }
    722  1.1  dholland 
    723  1.1  dholland /*
    724  1.1  dholland  * Write vnode op from an mbuf list.
    725  1.1  dholland  */
    726  1.1  dholland int
    727  1.1  dholland nfsvno_write(struct vnode *vp, off_t off, int retlen, int cnt, int stable,
    728  1.1  dholland     struct mbuf *mp, char *cp, struct ucred *cred, struct thread *p)
    729  1.1  dholland {
    730  1.1  dholland 	struct iovec *ivp;
    731  1.1  dholland 	int i, len;
    732  1.1  dholland 	struct iovec *iv;
    733  1.1  dholland 	int ioflags, error;
    734  1.1  dholland 	struct uio io, *uiop = &io;
    735  1.1  dholland 	struct nfsheur *nh;
    736  1.1  dholland 
    737  1.1  dholland 	MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
    738  1.1  dholland 	    M_WAITOK);
    739  1.1  dholland 	uiop->uio_iov = iv = ivp;
    740  1.1  dholland 	uiop->uio_iovcnt = cnt;
    741  1.1  dholland 	i = mtod(mp, caddr_t) + mp->m_len - cp;
    742  1.1  dholland 	len = retlen;
    743  1.1  dholland 	while (len > 0) {
    744  1.1  dholland 		if (mp == NULL)
    745  1.1  dholland 			panic("nfsvno_write");
    746  1.1  dholland 		if (i > 0) {
    747  1.3  riastrad 			i = uimin(i, len);
    748  1.1  dholland 			ivp->iov_base = cp;
    749  1.1  dholland 			ivp->iov_len = i;
    750  1.1  dholland 			ivp++;
    751  1.1  dholland 			len -= i;
    752  1.1  dholland 		}
    753  1.1  dholland 		mp = mp->m_next;
    754  1.1  dholland 		if (mp) {
    755  1.1  dholland 			i = mp->m_len;
    756  1.1  dholland 			cp = mtod(mp, caddr_t);
    757  1.1  dholland 		}
    758  1.1  dholland 	}
    759  1.1  dholland 
    760  1.1  dholland 	if (stable == NFSWRITE_UNSTABLE)
    761  1.1  dholland 		ioflags = IO_NODELOCKED;
    762  1.1  dholland 	else
    763  1.1  dholland 		ioflags = (IO_SYNC | IO_NODELOCKED);
    764  1.1  dholland 	uiop->uio_resid = retlen;
    765  1.1  dholland 	uiop->uio_rw = UIO_WRITE;
    766  1.1  dholland 	uiop->uio_segflg = UIO_SYSSPACE;
    767  1.1  dholland 	NFSUIOPROC(uiop, p);
    768  1.1  dholland 	uiop->uio_offset = off;
    769  1.1  dholland 	nh = nfsrv_sequential_heuristic(uiop, vp);
    770  1.1  dholland 	ioflags |= nh->nh_seqcount << IO_SEQSHIFT;
    771  1.2  pgoyette 	/* XXX KDM make this more systematic? */
    772  1.2  pgoyette 	nfsstatsv1.srvbytes[NFSV4OP_WRITE] += uiop->uio_resid;
    773  1.1  dholland 	error = VOP_WRITE(vp, uiop, ioflags, cred);
    774  1.1  dholland 	if (error == 0)
    775  1.1  dholland 		nh->nh_nextoff = uiop->uio_offset;
    776  1.1  dholland 	FREE((caddr_t)iv, M_TEMP);
    777  1.1  dholland 
    778  1.1  dholland 	NFSEXITCODE(error);
    779  1.1  dholland 	return (error);
    780  1.1  dholland }
    781  1.1  dholland 
    782  1.1  dholland /*
    783  1.1  dholland  * Common code for creating a regular file (plus special files for V2).
    784  1.1  dholland  */
    785  1.1  dholland int
    786  1.1  dholland nfsvno_createsub(struct nfsrv_descript *nd, struct nameidata *ndp,
    787  1.1  dholland     struct vnode **vpp, struct nfsvattr *nvap, int *exclusive_flagp,
    788  1.1  dholland     int32_t *cverf, NFSDEV_T rdev, struct thread *p, struct nfsexstuff *exp)
    789  1.1  dholland {
    790  1.1  dholland 	u_quad_t tempsize;
    791  1.1  dholland 	int error;
    792  1.1  dholland 
    793  1.1  dholland 	error = nd->nd_repstat;
    794  1.1  dholland 	if (!error && ndp->ni_vp == NULL) {
    795  1.1  dholland 		if (nvap->na_type == VREG || nvap->na_type == VSOCK) {
    796  1.1  dholland 			vrele(ndp->ni_startdir);
    797  1.1  dholland 			error = VOP_CREATE(ndp->ni_dvp,
    798  1.1  dholland 			    &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr);
    799  1.1  dholland 			vput(ndp->ni_dvp);
    800  1.1  dholland 			nfsvno_relpathbuf(ndp);
    801  1.1  dholland 			if (!error) {
    802  1.1  dholland 				if (*exclusive_flagp) {
    803  1.1  dholland 					*exclusive_flagp = 0;
    804  1.1  dholland 					NFSVNO_ATTRINIT(nvap);
    805  1.1  dholland 					nvap->na_atime.tv_sec = cverf[0];
    806  1.1  dholland 					nvap->na_atime.tv_nsec = cverf[1];
    807  1.1  dholland 					error = VOP_SETATTR(ndp->ni_vp,
    808  1.1  dholland 					    &nvap->na_vattr, nd->nd_cred);
    809  1.2  pgoyette 					if (error != 0) {
    810  1.2  pgoyette 						vput(ndp->ni_vp);
    811  1.2  pgoyette 						ndp->ni_vp = NULL;
    812  1.2  pgoyette 						error = NFSERR_NOTSUPP;
    813  1.2  pgoyette 					}
    814  1.1  dholland 				}
    815  1.1  dholland 			}
    816  1.1  dholland 		/*
    817  1.1  dholland 		 * NFS V2 Only. nfsrvd_mknod() does this for V3.
    818  1.1  dholland 		 * (This implies, just get out on an error.)
    819  1.1  dholland 		 */
    820  1.1  dholland 		} else if (nvap->na_type == VCHR || nvap->na_type == VBLK ||
    821  1.1  dholland 			nvap->na_type == VFIFO) {
    822  1.1  dholland 			if (nvap->na_type == VCHR && rdev == 0xffffffff)
    823  1.1  dholland 				nvap->na_type = VFIFO;
    824  1.1  dholland                         if (nvap->na_type != VFIFO &&
    825  1.1  dholland 			    (error = priv_check_cred(nd->nd_cred,
    826  1.1  dholland 			     PRIV_VFS_MKNOD_DEV, 0))) {
    827  1.1  dholland 				vrele(ndp->ni_startdir);
    828  1.1  dholland 				nfsvno_relpathbuf(ndp);
    829  1.1  dholland 				vput(ndp->ni_dvp);
    830  1.1  dholland 				goto out;
    831  1.1  dholland 			}
    832  1.1  dholland 			nvap->na_rdev = rdev;
    833  1.1  dholland 			error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp,
    834  1.1  dholland 			    &ndp->ni_cnd, &nvap->na_vattr);
    835  1.1  dholland 			vput(ndp->ni_dvp);
    836  1.1  dholland 			nfsvno_relpathbuf(ndp);
    837  1.1  dholland 			vrele(ndp->ni_startdir);
    838  1.1  dholland 			if (error)
    839  1.1  dholland 				goto out;
    840  1.1  dholland 		} else {
    841  1.1  dholland 			vrele(ndp->ni_startdir);
    842  1.1  dholland 			nfsvno_relpathbuf(ndp);
    843  1.1  dholland 			vput(ndp->ni_dvp);
    844  1.1  dholland 			error = ENXIO;
    845  1.1  dholland 			goto out;
    846  1.1  dholland 		}
    847  1.1  dholland 		*vpp = ndp->ni_vp;
    848  1.1  dholland 	} else {
    849  1.1  dholland 		/*
    850  1.1  dholland 		 * Handle cases where error is already set and/or
    851  1.1  dholland 		 * the file exists.
    852  1.1  dholland 		 * 1 - clean up the lookup
    853  1.1  dholland 		 * 2 - iff !error and na_size set, truncate it
    854  1.1  dholland 		 */
    855  1.1  dholland 		vrele(ndp->ni_startdir);
    856  1.1  dholland 		nfsvno_relpathbuf(ndp);
    857  1.1  dholland 		*vpp = ndp->ni_vp;
    858  1.1  dholland 		if (ndp->ni_dvp == *vpp)
    859  1.1  dholland 			vrele(ndp->ni_dvp);
    860  1.1  dholland 		else
    861  1.1  dholland 			vput(ndp->ni_dvp);
    862  1.1  dholland 		if (!error && nvap->na_size != VNOVAL) {
    863  1.1  dholland 			error = nfsvno_accchk(*vpp, VWRITE,
    864  1.1  dholland 			    nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
    865  1.1  dholland 			    NFSACCCHK_VPISLOCKED, NULL);
    866  1.1  dholland 			if (!error) {
    867  1.1  dholland 				tempsize = nvap->na_size;
    868  1.1  dholland 				NFSVNO_ATTRINIT(nvap);
    869  1.1  dholland 				nvap->na_size = tempsize;
    870  1.1  dholland 				error = VOP_SETATTR(*vpp,
    871  1.1  dholland 				    &nvap->na_vattr, nd->nd_cred);
    872  1.1  dholland 			}
    873  1.1  dholland 		}
    874  1.1  dholland 		if (error)
    875  1.1  dholland 			vput(*vpp);
    876  1.1  dholland 	}
    877  1.1  dholland 
    878  1.1  dholland out:
    879  1.1  dholland 	NFSEXITCODE(error);
    880  1.1  dholland 	return (error);
    881  1.1  dholland }
    882  1.1  dholland 
    883  1.1  dholland /*
    884  1.1  dholland  * Do a mknod vnode op.
    885  1.1  dholland  */
    886  1.1  dholland int
    887  1.1  dholland nfsvno_mknod(struct nameidata *ndp, struct nfsvattr *nvap, struct ucred *cred,
    888  1.1  dholland     struct thread *p)
    889  1.1  dholland {
    890  1.1  dholland 	int error = 0;
    891  1.1  dholland 	enum vtype vtyp;
    892  1.1  dholland 
    893  1.1  dholland 	vtyp = nvap->na_type;
    894  1.1  dholland 	/*
    895  1.1  dholland 	 * Iff doesn't exist, create it.
    896  1.1  dholland 	 */
    897  1.1  dholland 	if (ndp->ni_vp) {
    898  1.1  dholland 		vrele(ndp->ni_startdir);
    899  1.1  dholland 		nfsvno_relpathbuf(ndp);
    900  1.1  dholland 		vput(ndp->ni_dvp);
    901  1.1  dholland 		vrele(ndp->ni_vp);
    902  1.1  dholland 		error = EEXIST;
    903  1.1  dholland 		goto out;
    904  1.1  dholland 	}
    905  1.1  dholland 	if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
    906  1.1  dholland 		vrele(ndp->ni_startdir);
    907  1.1  dholland 		nfsvno_relpathbuf(ndp);
    908  1.1  dholland 		vput(ndp->ni_dvp);
    909  1.1  dholland 		error = NFSERR_BADTYPE;
    910  1.1  dholland 		goto out;
    911  1.1  dholland 	}
    912  1.1  dholland 	if (vtyp == VSOCK) {
    913  1.1  dholland 		vrele(ndp->ni_startdir);
    914  1.1  dholland 		error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
    915  1.1  dholland 		    &ndp->ni_cnd, &nvap->na_vattr);
    916  1.1  dholland 		vput(ndp->ni_dvp);
    917  1.1  dholland 		nfsvno_relpathbuf(ndp);
    918  1.1  dholland 	} else {
    919  1.1  dholland 		if (nvap->na_type != VFIFO &&
    920  1.1  dholland 		    (error = priv_check_cred(cred, PRIV_VFS_MKNOD_DEV, 0))) {
    921  1.1  dholland 			vrele(ndp->ni_startdir);
    922  1.1  dholland 			nfsvno_relpathbuf(ndp);
    923  1.1  dholland 			vput(ndp->ni_dvp);
    924  1.1  dholland 			goto out;
    925  1.1  dholland 		}
    926  1.1  dholland 		error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp,
    927  1.1  dholland 		    &ndp->ni_cnd, &nvap->na_vattr);
    928  1.1  dholland 		vput(ndp->ni_dvp);
    929  1.1  dholland 		nfsvno_relpathbuf(ndp);
    930  1.1  dholland 		vrele(ndp->ni_startdir);
    931  1.1  dholland 		/*
    932  1.1  dholland 		 * Since VOP_MKNOD returns the ni_vp, I can't
    933  1.1  dholland 		 * see any reason to do the lookup.
    934  1.1  dholland 		 */
    935  1.1  dholland 	}
    936  1.1  dholland 
    937  1.1  dholland out:
    938  1.1  dholland 	NFSEXITCODE(error);
    939  1.1  dholland 	return (error);
    940  1.1  dholland }
    941  1.1  dholland 
    942  1.1  dholland /*
    943  1.1  dholland  * Mkdir vnode op.
    944  1.1  dholland  */
    945  1.1  dholland int
    946  1.1  dholland nfsvno_mkdir(struct nameidata *ndp, struct nfsvattr *nvap, uid_t saved_uid,
    947  1.1  dholland     struct ucred *cred, struct thread *p, struct nfsexstuff *exp)
    948  1.1  dholland {
    949  1.1  dholland 	int error = 0;
    950  1.1  dholland 
    951  1.1  dholland 	if (ndp->ni_vp != NULL) {
    952  1.1  dholland 		if (ndp->ni_dvp == ndp->ni_vp)
    953  1.1  dholland 			vrele(ndp->ni_dvp);
    954  1.1  dholland 		else
    955  1.1  dholland 			vput(ndp->ni_dvp);
    956  1.1  dholland 		vrele(ndp->ni_vp);
    957  1.1  dholland 		nfsvno_relpathbuf(ndp);
    958  1.1  dholland 		error = EEXIST;
    959  1.1  dholland 		goto out;
    960  1.1  dholland 	}
    961  1.1  dholland 	error = VOP_MKDIR(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd,
    962  1.1  dholland 	    &nvap->na_vattr);
    963  1.1  dholland 	vput(ndp->ni_dvp);
    964  1.1  dholland 	nfsvno_relpathbuf(ndp);
    965  1.1  dholland 
    966  1.1  dholland out:
    967  1.1  dholland 	NFSEXITCODE(error);
    968  1.1  dholland 	return (error);
    969  1.1  dholland }
    970  1.1  dholland 
    971  1.1  dholland /*
    972  1.1  dholland  * symlink vnode op.
    973  1.1  dholland  */
    974  1.1  dholland int
    975  1.1  dholland nfsvno_symlink(struct nameidata *ndp, struct nfsvattr *nvap, char *pathcp,
    976  1.1  dholland     int pathlen, int not_v2, uid_t saved_uid, struct ucred *cred, struct thread *p,
    977  1.1  dholland     struct nfsexstuff *exp)
    978  1.1  dholland {
    979  1.1  dholland 	int error = 0;
    980  1.1  dholland 
    981  1.1  dholland 	if (ndp->ni_vp) {
    982  1.1  dholland 		vrele(ndp->ni_startdir);
    983  1.1  dholland 		nfsvno_relpathbuf(ndp);
    984  1.1  dholland 		if (ndp->ni_dvp == ndp->ni_vp)
    985  1.1  dholland 			vrele(ndp->ni_dvp);
    986  1.1  dholland 		else
    987  1.1  dholland 			vput(ndp->ni_dvp);
    988  1.1  dholland 		vrele(ndp->ni_vp);
    989  1.1  dholland 		error = EEXIST;
    990  1.1  dholland 		goto out;
    991  1.1  dholland 	}
    992  1.1  dholland 
    993  1.1  dholland 	error = VOP_SYMLINK(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd,
    994  1.1  dholland 	    &nvap->na_vattr, pathcp);
    995  1.1  dholland 	vput(ndp->ni_dvp);
    996  1.1  dholland 	vrele(ndp->ni_startdir);
    997  1.1  dholland 	nfsvno_relpathbuf(ndp);
    998  1.1  dholland 	/*
    999  1.1  dholland 	 * Although FreeBSD still had the lookup code in
   1000  1.1  dholland 	 * it for 7/current, there doesn't seem to be any
   1001  1.1  dholland 	 * point, since VOP_SYMLINK() returns the ni_vp.
   1002  1.1  dholland 	 * Just vput it for v2.
   1003  1.1  dholland 	 */
   1004  1.1  dholland 	if (!not_v2 && !error)
   1005  1.1  dholland 		vput(ndp->ni_vp);
   1006  1.1  dholland 
   1007  1.1  dholland out:
   1008  1.1  dholland 	NFSEXITCODE(error);
   1009  1.1  dholland 	return (error);
   1010  1.1  dholland }
   1011  1.1  dholland 
   1012  1.1  dholland /*
   1013  1.1  dholland  * Parse symbolic link arguments.
   1014  1.1  dholland  * This function has an ugly side effect. It will MALLOC() an area for
   1015  1.1  dholland  * the symlink and set iov_base to point to it, only if it succeeds.
   1016  1.1  dholland  * So, if it returns with uiop->uio_iov->iov_base != NULL, that must
   1017  1.1  dholland  * be FREE'd later.
   1018  1.1  dholland  */
   1019  1.1  dholland int
   1020  1.1  dholland nfsvno_getsymlink(struct nfsrv_descript *nd, struct nfsvattr *nvap,
   1021  1.1  dholland     struct thread *p, char **pathcpp, int *lenp)
   1022  1.1  dholland {
   1023  1.1  dholland 	u_int32_t *tl;
   1024  1.1  dholland 	char *pathcp = NULL;
   1025  1.1  dholland 	int error = 0, len;
   1026  1.1  dholland 	struct nfsv2_sattr *sp;
   1027  1.1  dholland 
   1028  1.1  dholland 	*pathcpp = NULL;
   1029  1.1  dholland 	*lenp = 0;
   1030  1.1  dholland 	if ((nd->nd_flag & ND_NFSV3) &&
   1031  1.2  pgoyette 	    (error = nfsrv_sattr(nd, NULL, nvap, NULL, NULL, p)))
   1032  1.1  dholland 		goto nfsmout;
   1033  1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1034  1.1  dholland 	len = fxdr_unsigned(int, *tl);
   1035  1.1  dholland 	if (len > NFS_MAXPATHLEN || len <= 0) {
   1036  1.1  dholland 		error = EBADRPC;
   1037  1.1  dholland 		goto nfsmout;
   1038  1.1  dholland 	}
   1039  1.1  dholland 	MALLOC(pathcp, caddr_t, len + 1, M_TEMP, M_WAITOK);
   1040  1.1  dholland 	error = nfsrv_mtostr(nd, pathcp, len);
   1041  1.1  dholland 	if (error)
   1042  1.1  dholland 		goto nfsmout;
   1043  1.1  dholland 	if (nd->nd_flag & ND_NFSV2) {
   1044  1.1  dholland 		NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
   1045  1.1  dholland 		nvap->na_mode = fxdr_unsigned(u_int16_t, sp->sa_mode);
   1046  1.1  dholland 	}
   1047  1.1  dholland 	*pathcpp = pathcp;
   1048  1.1  dholland 	*lenp = len;
   1049  1.1  dholland 	NFSEXITCODE2(0, nd);
   1050  1.1  dholland 	return (0);
   1051  1.1  dholland nfsmout:
   1052  1.1  dholland 	if (pathcp)
   1053  1.1  dholland 		free(pathcp, M_TEMP);
   1054  1.1  dholland 	NFSEXITCODE2(error, nd);
   1055  1.1  dholland 	return (error);
   1056  1.1  dholland }
   1057  1.1  dholland 
   1058  1.1  dholland /*
   1059  1.1  dholland  * Remove a non-directory object.
   1060  1.1  dholland  */
   1061  1.1  dholland int
   1062  1.1  dholland nfsvno_removesub(struct nameidata *ndp, int is_v4, struct ucred *cred,
   1063  1.1  dholland     struct thread *p, struct nfsexstuff *exp)
   1064  1.1  dholland {
   1065  1.1  dholland 	struct vnode *vp;
   1066  1.1  dholland 	int error = 0;
   1067  1.1  dholland 
   1068  1.1  dholland 	vp = ndp->ni_vp;
   1069  1.1  dholland 	if (vp->v_type == VDIR)
   1070  1.1  dholland 		error = NFSERR_ISDIR;
   1071  1.1  dholland 	else if (is_v4)
   1072  1.1  dholland 		error = nfsrv_checkremove(vp, 1, p);
   1073  1.1  dholland 	if (!error)
   1074  1.1  dholland 		error = VOP_REMOVE(ndp->ni_dvp, vp, &ndp->ni_cnd);
   1075  1.1  dholland 	if (ndp->ni_dvp == vp)
   1076  1.1  dholland 		vrele(ndp->ni_dvp);
   1077  1.1  dholland 	else
   1078  1.1  dholland 		vput(ndp->ni_dvp);
   1079  1.1  dholland 	vput(vp);
   1080  1.1  dholland 	if ((ndp->ni_cnd.cn_flags & SAVENAME) != 0)
   1081  1.1  dholland 		nfsvno_relpathbuf(ndp);
   1082  1.1  dholland 	NFSEXITCODE(error);
   1083  1.1  dholland 	return (error);
   1084  1.1  dholland }
   1085  1.1  dholland 
   1086  1.1  dholland /*
   1087  1.1  dholland  * Remove a directory.
   1088  1.1  dholland  */
   1089  1.1  dholland int
   1090  1.1  dholland nfsvno_rmdirsub(struct nameidata *ndp, int is_v4, struct ucred *cred,
   1091  1.1  dholland     struct thread *p, struct nfsexstuff *exp)
   1092  1.1  dholland {
   1093  1.1  dholland 	struct vnode *vp;
   1094  1.1  dholland 	int error = 0;
   1095  1.1  dholland 
   1096  1.1  dholland 	vp = ndp->ni_vp;
   1097  1.1  dholland 	if (vp->v_type != VDIR) {
   1098  1.1  dholland 		error = ENOTDIR;
   1099  1.1  dholland 		goto out;
   1100  1.1  dholland 	}
   1101  1.1  dholland 	/*
   1102  1.1  dholland 	 * No rmdir "." please.
   1103  1.1  dholland 	 */
   1104  1.1  dholland 	if (ndp->ni_dvp == vp) {
   1105  1.1  dholland 		error = EINVAL;
   1106  1.1  dholland 		goto out;
   1107  1.1  dholland 	}
   1108  1.1  dholland 	/*
   1109  1.1  dholland 	 * The root of a mounted filesystem cannot be deleted.
   1110  1.1  dholland 	 */
   1111  1.1  dholland 	if (vp->v_vflag & VV_ROOT)
   1112  1.1  dholland 		error = EBUSY;
   1113  1.1  dholland out:
   1114  1.1  dholland 	if (!error)
   1115  1.1  dholland 		error = VOP_RMDIR(ndp->ni_dvp, vp, &ndp->ni_cnd);
   1116  1.1  dholland 	if (ndp->ni_dvp == vp)
   1117  1.1  dholland 		vrele(ndp->ni_dvp);
   1118  1.1  dholland 	else
   1119  1.1  dholland 		vput(ndp->ni_dvp);
   1120  1.1  dholland 	vput(vp);
   1121  1.1  dholland 	if ((ndp->ni_cnd.cn_flags & SAVENAME) != 0)
   1122  1.1  dholland 		nfsvno_relpathbuf(ndp);
   1123  1.1  dholland 	NFSEXITCODE(error);
   1124  1.1  dholland 	return (error);
   1125  1.1  dholland }
   1126  1.1  dholland 
   1127  1.1  dholland /*
   1128  1.1  dholland  * Rename vnode op.
   1129  1.1  dholland  */
   1130  1.1  dholland int
   1131  1.1  dholland nfsvno_rename(struct nameidata *fromndp, struct nameidata *tondp,
   1132  1.1  dholland     u_int32_t ndstat, u_int32_t ndflag, struct ucred *cred, struct thread *p)
   1133  1.1  dholland {
   1134  1.1  dholland 	struct vnode *fvp, *tvp, *tdvp;
   1135  1.1  dholland 	int error = 0;
   1136  1.1  dholland 
   1137  1.1  dholland 	fvp = fromndp->ni_vp;
   1138  1.1  dholland 	if (ndstat) {
   1139  1.1  dholland 		vrele(fromndp->ni_dvp);
   1140  1.1  dholland 		vrele(fvp);
   1141  1.1  dholland 		error = ndstat;
   1142  1.1  dholland 		goto out1;
   1143  1.1  dholland 	}
   1144  1.1  dholland 	tdvp = tondp->ni_dvp;
   1145  1.1  dholland 	tvp = tondp->ni_vp;
   1146  1.1  dholland 	if (tvp != NULL) {
   1147  1.1  dholland 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
   1148  1.1  dholland 			error = (ndflag & ND_NFSV2) ? EISDIR : EEXIST;
   1149  1.1  dholland 			goto out;
   1150  1.1  dholland 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
   1151  1.1  dholland 			error = (ndflag & ND_NFSV2) ? ENOTDIR : EEXIST;
   1152  1.1  dholland 			goto out;
   1153  1.1  dholland 		}
   1154  1.1  dholland 		if (tvp->v_type == VDIR && tvp->v_mountedhere) {
   1155  1.1  dholland 			error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EXDEV;
   1156  1.1  dholland 			goto out;
   1157  1.1  dholland 		}
   1158  1.1  dholland 
   1159  1.1  dholland 		/*
   1160  1.1  dholland 		 * A rename to '.' or '..' results in a prematurely
   1161  1.1  dholland 		 * unlocked vnode on FreeBSD5, so I'm just going to fail that
   1162  1.1  dholland 		 * here.
   1163  1.1  dholland 		 */
   1164  1.1  dholland 		if ((tondp->ni_cnd.cn_namelen == 1 &&
   1165  1.1  dholland 		     tondp->ni_cnd.cn_nameptr[0] == '.') ||
   1166  1.1  dholland 		    (tondp->ni_cnd.cn_namelen == 2 &&
   1167  1.1  dholland 		     tondp->ni_cnd.cn_nameptr[0] == '.' &&
   1168  1.1  dholland 		     tondp->ni_cnd.cn_nameptr[1] == '.')) {
   1169  1.1  dholland 			error = EINVAL;
   1170  1.1  dholland 			goto out;
   1171  1.1  dholland 		}
   1172  1.1  dholland 	}
   1173  1.1  dholland 	if (fvp->v_type == VDIR && fvp->v_mountedhere) {
   1174  1.1  dholland 		error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EXDEV;
   1175  1.1  dholland 		goto out;
   1176  1.1  dholland 	}
   1177  1.1  dholland 	if (fvp->v_mount != tdvp->v_mount) {
   1178  1.1  dholland 		error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EXDEV;
   1179  1.1  dholland 		goto out;
   1180  1.1  dholland 	}
   1181  1.1  dholland 	if (fvp == tdvp) {
   1182  1.1  dholland 		error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EINVAL;
   1183  1.1  dholland 		goto out;
   1184  1.1  dholland 	}
   1185  1.1  dholland 	if (fvp == tvp) {
   1186  1.1  dholland 		/*
   1187  1.1  dholland 		 * If source and destination are the same, there is nothing to
   1188  1.1  dholland 		 * do. Set error to -1 to indicate this.
   1189  1.1  dholland 		 */
   1190  1.1  dholland 		error = -1;
   1191  1.1  dholland 		goto out;
   1192  1.1  dholland 	}
   1193  1.1  dholland 	if (ndflag & ND_NFSV4) {
   1194  1.1  dholland 		if (NFSVOPLOCK(fvp, LK_EXCLUSIVE) == 0) {
   1195  1.1  dholland 			error = nfsrv_checkremove(fvp, 0, p);
   1196  1.1  dholland 			NFSVOPUNLOCK(fvp, 0);
   1197  1.1  dholland 		} else
   1198  1.1  dholland 			error = EPERM;
   1199  1.1  dholland 		if (tvp && !error)
   1200  1.1  dholland 			error = nfsrv_checkremove(tvp, 1, p);
   1201  1.1  dholland 	} else {
   1202  1.1  dholland 		/*
   1203  1.1  dholland 		 * For NFSv2 and NFSv3, try to get rid of the delegation, so
   1204  1.1  dholland 		 * that the NFSv4 client won't be confused by the rename.
   1205  1.1  dholland 		 * Since nfsd_recalldelegation() can only be called on an
   1206  1.1  dholland 		 * unlocked vnode at this point and fvp is the file that will
   1207  1.1  dholland 		 * still exist after the rename, just do fvp.
   1208  1.1  dholland 		 */
   1209  1.1  dholland 		nfsd_recalldelegation(fvp, p);
   1210  1.1  dholland 	}
   1211  1.1  dholland out:
   1212  1.1  dholland 	if (!error) {
   1213  1.1  dholland 		error = VOP_RENAME(fromndp->ni_dvp, fromndp->ni_vp,
   1214  1.1  dholland 		    &fromndp->ni_cnd, tondp->ni_dvp, tondp->ni_vp,
   1215  1.1  dholland 		    &tondp->ni_cnd);
   1216  1.1  dholland 	} else {
   1217  1.1  dholland 		if (tdvp == tvp)
   1218  1.1  dholland 			vrele(tdvp);
   1219  1.1  dholland 		else
   1220  1.1  dholland 			vput(tdvp);
   1221  1.1  dholland 		if (tvp)
   1222  1.1  dholland 			vput(tvp);
   1223  1.1  dholland 		vrele(fromndp->ni_dvp);
   1224  1.1  dholland 		vrele(fvp);
   1225  1.1  dholland 		if (error == -1)
   1226  1.1  dholland 			error = 0;
   1227  1.1  dholland 	}
   1228  1.1  dholland 	vrele(tondp->ni_startdir);
   1229  1.1  dholland 	nfsvno_relpathbuf(tondp);
   1230  1.1  dholland out1:
   1231  1.1  dholland 	vrele(fromndp->ni_startdir);
   1232  1.1  dholland 	nfsvno_relpathbuf(fromndp);
   1233  1.1  dholland 	NFSEXITCODE(error);
   1234  1.1  dholland 	return (error);
   1235  1.1  dholland }
   1236  1.1  dholland 
   1237  1.1  dholland /*
   1238  1.1  dholland  * Link vnode op.
   1239  1.1  dholland  */
   1240  1.1  dholland int
   1241  1.1  dholland nfsvno_link(struct nameidata *ndp, struct vnode *vp, struct ucred *cred,
   1242  1.1  dholland     struct thread *p, struct nfsexstuff *exp)
   1243  1.1  dholland {
   1244  1.1  dholland 	struct vnode *xp;
   1245  1.1  dholland 	int error = 0;
   1246  1.1  dholland 
   1247  1.1  dholland 	xp = ndp->ni_vp;
   1248  1.1  dholland 	if (xp != NULL) {
   1249  1.1  dholland 		error = EEXIST;
   1250  1.1  dholland 	} else {
   1251  1.1  dholland 		xp = ndp->ni_dvp;
   1252  1.1  dholland 		if (vp->v_mount != xp->v_mount)
   1253  1.1  dholland 			error = EXDEV;
   1254  1.1  dholland 	}
   1255  1.1  dholland 	if (!error) {
   1256  1.1  dholland 		NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
   1257  1.1  dholland 		if ((vp->v_iflag & VI_DOOMED) == 0)
   1258  1.1  dholland 			error = VOP_LINK(ndp->ni_dvp, vp, &ndp->ni_cnd);
   1259  1.1  dholland 		else
   1260  1.1  dholland 			error = EPERM;
   1261  1.1  dholland 		if (ndp->ni_dvp == vp)
   1262  1.1  dholland 			vrele(ndp->ni_dvp);
   1263  1.1  dholland 		else
   1264  1.1  dholland 			vput(ndp->ni_dvp);
   1265  1.1  dholland 		NFSVOPUNLOCK(vp, 0);
   1266  1.1  dholland 	} else {
   1267  1.1  dholland 		if (ndp->ni_dvp == ndp->ni_vp)
   1268  1.1  dholland 			vrele(ndp->ni_dvp);
   1269  1.1  dholland 		else
   1270  1.1  dholland 			vput(ndp->ni_dvp);
   1271  1.1  dholland 		if (ndp->ni_vp)
   1272  1.1  dholland 			vrele(ndp->ni_vp);
   1273  1.1  dholland 	}
   1274  1.1  dholland 	nfsvno_relpathbuf(ndp);
   1275  1.1  dholland 	NFSEXITCODE(error);
   1276  1.1  dholland 	return (error);
   1277  1.1  dholland }
   1278  1.1  dholland 
   1279  1.1  dholland /*
   1280  1.1  dholland  * Do the fsync() appropriate for the commit.
   1281  1.1  dholland  */
   1282  1.1  dholland int
   1283  1.1  dholland nfsvno_fsync(struct vnode *vp, u_int64_t off, int cnt, struct ucred *cred,
   1284  1.1  dholland     struct thread *td)
   1285  1.1  dholland {
   1286  1.1  dholland 	int error = 0;
   1287  1.1  dholland 
   1288  1.1  dholland 	/*
   1289  1.1  dholland 	 * RFC 1813 3.3.21: if count is 0, a flush from offset to the end of
   1290  1.1  dholland 	 * file is done.  At this time VOP_FSYNC does not accept offset and
   1291  1.1  dholland 	 * byte count parameters so call VOP_FSYNC the whole file for now.
   1292  1.1  dholland 	 * The same is true for NFSv4: RFC 3530 Sec. 14.2.3.
   1293  1.2  pgoyette 	 * File systems that do not use the buffer cache (as indicated
   1294  1.2  pgoyette 	 * by MNTK_USES_BCACHE not being set) must use VOP_FSYNC().
   1295  1.1  dholland 	 */
   1296  1.2  pgoyette 	if (cnt == 0 || cnt > MAX_COMMIT_COUNT ||
   1297  1.2  pgoyette 	    (vp->v_mount->mnt_kern_flag & MNTK_USES_BCACHE) == 0) {
   1298  1.1  dholland 		/*
   1299  1.1  dholland 		 * Give up and do the whole thing
   1300  1.1  dholland 		 */
   1301  1.1  dholland 		if (vp->v_object &&
   1302  1.1  dholland 		   (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
   1303  1.1  dholland 			VM_OBJECT_WLOCK(vp->v_object);
   1304  1.1  dholland 			vm_object_page_clean(vp->v_object, 0, 0, OBJPC_SYNC);
   1305  1.1  dholland 			VM_OBJECT_WUNLOCK(vp->v_object);
   1306  1.1  dholland 		}
   1307  1.1  dholland 		error = VOP_FSYNC(vp, MNT_WAIT, td);
   1308  1.1  dholland 	} else {
   1309  1.1  dholland 		/*
   1310  1.1  dholland 		 * Locate and synchronously write any buffers that fall
   1311  1.1  dholland 		 * into the requested range.  Note:  we are assuming that
   1312  1.1  dholland 		 * f_iosize is a power of 2.
   1313  1.1  dholland 		 */
   1314  1.1  dholland 		int iosize = vp->v_mount->mnt_stat.f_iosize;
   1315  1.1  dholland 		int iomask = iosize - 1;
   1316  1.1  dholland 		struct bufobj *bo;
   1317  1.1  dholland 		daddr_t lblkno;
   1318  1.1  dholland 
   1319  1.1  dholland 		/*
   1320  1.2  pgoyette 		 * Align to iosize boundary, super-align to page boundary.
   1321  1.1  dholland 		 */
   1322  1.1  dholland 		if (off & iomask) {
   1323  1.1  dholland 			cnt += off & iomask;
   1324  1.1  dholland 			off &= ~(u_quad_t)iomask;
   1325  1.1  dholland 		}
   1326  1.1  dholland 		if (off & PAGE_MASK) {
   1327  1.1  dholland 			cnt += off & PAGE_MASK;
   1328  1.1  dholland 			off &= ~(u_quad_t)PAGE_MASK;
   1329  1.1  dholland 		}
   1330  1.1  dholland 		lblkno = off / iosize;
   1331  1.1  dholland 
   1332  1.1  dholland 		if (vp->v_object &&
   1333  1.1  dholland 		   (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
   1334  1.1  dholland 			VM_OBJECT_WLOCK(vp->v_object);
   1335  1.1  dholland 			vm_object_page_clean(vp->v_object, off, off + cnt,
   1336  1.1  dholland 			    OBJPC_SYNC);
   1337  1.1  dholland 			VM_OBJECT_WUNLOCK(vp->v_object);
   1338  1.1  dholland 		}
   1339  1.1  dholland 
   1340  1.1  dholland 		bo = &vp->v_bufobj;
   1341  1.1  dholland 		BO_LOCK(bo);
   1342  1.1  dholland 		while (cnt > 0) {
   1343  1.1  dholland 			struct buf *bp;
   1344  1.1  dholland 
   1345  1.1  dholland 			/*
   1346  1.1  dholland 			 * If we have a buffer and it is marked B_DELWRI we
   1347  1.1  dholland 			 * have to lock and write it.  Otherwise the prior
   1348  1.1  dholland 			 * write is assumed to have already been committed.
   1349  1.1  dholland 			 *
   1350  1.1  dholland 			 * gbincore() can return invalid buffers now so we
   1351  1.1  dholland 			 * have to check that bit as well (though B_DELWRI
   1352  1.1  dholland 			 * should not be set if B_INVAL is set there could be
   1353  1.1  dholland 			 * a race here since we haven't locked the buffer).
   1354  1.1  dholland 			 */
   1355  1.1  dholland 			if ((bp = gbincore(&vp->v_bufobj, lblkno)) != NULL) {
   1356  1.1  dholland 				if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL |
   1357  1.1  dholland 				    LK_INTERLOCK, BO_LOCKPTR(bo)) == ENOLCK) {
   1358  1.1  dholland 					BO_LOCK(bo);
   1359  1.1  dholland 					continue; /* retry */
   1360  1.1  dholland 				}
   1361  1.1  dholland 			    	if ((bp->b_flags & (B_DELWRI|B_INVAL)) ==
   1362  1.1  dholland 				    B_DELWRI) {
   1363  1.1  dholland 					bremfree(bp);
   1364  1.1  dholland 					bp->b_flags &= ~B_ASYNC;
   1365  1.1  dholland 					bwrite(bp);
   1366  1.1  dholland 					++nfs_commit_miss;
   1367  1.1  dholland 				} else
   1368  1.1  dholland 					BUF_UNLOCK(bp);
   1369  1.1  dholland 				BO_LOCK(bo);
   1370  1.1  dholland 			}
   1371  1.1  dholland 			++nfs_commit_blks;
   1372  1.1  dholland 			if (cnt < iosize)
   1373  1.1  dholland 				break;
   1374  1.1  dholland 			cnt -= iosize;
   1375  1.1  dholland 			++lblkno;
   1376  1.1  dholland 		}
   1377  1.1  dholland 		BO_UNLOCK(bo);
   1378  1.1  dholland 	}
   1379  1.1  dholland 	NFSEXITCODE(error);
   1380  1.1  dholland 	return (error);
   1381  1.1  dholland }
   1382  1.1  dholland 
   1383  1.1  dholland /*
   1384  1.1  dholland  * Statfs vnode op.
   1385  1.1  dholland  */
   1386  1.1  dholland int
   1387  1.1  dholland nfsvno_statfs(struct vnode *vp, struct statfs *sf)
   1388  1.1  dholland {
   1389  1.1  dholland 	int error;
   1390  1.1  dholland 
   1391  1.1  dholland 	error = VFS_STATFS(vp->v_mount, sf);
   1392  1.1  dholland 	if (error == 0) {
   1393  1.1  dholland 		/*
   1394  1.1  dholland 		 * Since NFS handles these values as unsigned on the
   1395  1.1  dholland 		 * wire, there is no way to represent negative values,
   1396  1.1  dholland 		 * so set them to 0. Without this, they will appear
   1397  1.1  dholland 		 * to be very large positive values for clients like
   1398  1.1  dholland 		 * Solaris10.
   1399  1.1  dholland 		 */
   1400  1.1  dholland 		if (sf->f_bavail < 0)
   1401  1.1  dholland 			sf->f_bavail = 0;
   1402  1.1  dholland 		if (sf->f_ffree < 0)
   1403  1.1  dholland 			sf->f_ffree = 0;
   1404  1.1  dholland 	}
   1405  1.1  dholland 	NFSEXITCODE(error);
   1406  1.1  dholland 	return (error);
   1407  1.1  dholland }
   1408  1.1  dholland 
   1409  1.1  dholland /*
   1410  1.1  dholland  * Do the vnode op stuff for Open. Similar to nfsvno_createsub(), but
   1411  1.1  dholland  * must handle nfsrv_opencheck() calls after any other access checks.
   1412  1.1  dholland  */
   1413  1.1  dholland void
   1414  1.1  dholland nfsvno_open(struct nfsrv_descript *nd, struct nameidata *ndp,
   1415  1.1  dholland     nfsquad_t clientid, nfsv4stateid_t *stateidp, struct nfsstate *stp,
   1416  1.1  dholland     int *exclusive_flagp, struct nfsvattr *nvap, int32_t *cverf, int create,
   1417  1.1  dholland     NFSACL_T *aclp, nfsattrbit_t *attrbitp, struct ucred *cred, struct thread *p,
   1418  1.1  dholland     struct nfsexstuff *exp, struct vnode **vpp)
   1419  1.1  dholland {
   1420  1.1  dholland 	struct vnode *vp = NULL;
   1421  1.1  dholland 	u_quad_t tempsize;
   1422  1.1  dholland 	struct nfsexstuff nes;
   1423  1.1  dholland 
   1424  1.1  dholland 	if (ndp->ni_vp == NULL)
   1425  1.1  dholland 		nd->nd_repstat = nfsrv_opencheck(clientid,
   1426  1.1  dholland 		    stateidp, stp, NULL, nd, p, nd->nd_repstat);
   1427  1.1  dholland 	if (!nd->nd_repstat) {
   1428  1.1  dholland 		if (ndp->ni_vp == NULL) {
   1429  1.1  dholland 			vrele(ndp->ni_startdir);
   1430  1.1  dholland 			nd->nd_repstat = VOP_CREATE(ndp->ni_dvp,
   1431  1.1  dholland 			    &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr);
   1432  1.1  dholland 			vput(ndp->ni_dvp);
   1433  1.1  dholland 			nfsvno_relpathbuf(ndp);
   1434  1.1  dholland 			if (!nd->nd_repstat) {
   1435  1.1  dholland 				if (*exclusive_flagp) {
   1436  1.1  dholland 					*exclusive_flagp = 0;
   1437  1.1  dholland 					NFSVNO_ATTRINIT(nvap);
   1438  1.1  dholland 					nvap->na_atime.tv_sec = cverf[0];
   1439  1.1  dholland 					nvap->na_atime.tv_nsec = cverf[1];
   1440  1.1  dholland 					nd->nd_repstat = VOP_SETATTR(ndp->ni_vp,
   1441  1.1  dholland 					    &nvap->na_vattr, cred);
   1442  1.2  pgoyette 					if (nd->nd_repstat != 0) {
   1443  1.2  pgoyette 						vput(ndp->ni_vp);
   1444  1.2  pgoyette 						ndp->ni_vp = NULL;
   1445  1.2  pgoyette 						nd->nd_repstat = NFSERR_NOTSUPP;
   1446  1.2  pgoyette 					}
   1447  1.1  dholland 				} else {
   1448  1.1  dholland 					nfsrv_fixattr(nd, ndp->ni_vp, nvap,
   1449  1.1  dholland 					    aclp, p, attrbitp, exp);
   1450  1.1  dholland 				}
   1451  1.1  dholland 			}
   1452  1.1  dholland 			vp = ndp->ni_vp;
   1453  1.1  dholland 		} else {
   1454  1.1  dholland 			if (ndp->ni_startdir)
   1455  1.1  dholland 				vrele(ndp->ni_startdir);
   1456  1.1  dholland 			nfsvno_relpathbuf(ndp);
   1457  1.1  dholland 			vp = ndp->ni_vp;
   1458  1.1  dholland 			if (create == NFSV4OPEN_CREATE) {
   1459  1.1  dholland 				if (ndp->ni_dvp == vp)
   1460  1.1  dholland 					vrele(ndp->ni_dvp);
   1461  1.1  dholland 				else
   1462  1.1  dholland 					vput(ndp->ni_dvp);
   1463  1.1  dholland 			}
   1464  1.1  dholland 			if (NFSVNO_ISSETSIZE(nvap) && vp->v_type == VREG) {
   1465  1.1  dholland 				if (ndp->ni_cnd.cn_flags & RDONLY)
   1466  1.1  dholland 					NFSVNO_SETEXRDONLY(&nes);
   1467  1.1  dholland 				else
   1468  1.1  dholland 					NFSVNO_EXINIT(&nes);
   1469  1.1  dholland 				nd->nd_repstat = nfsvno_accchk(vp,
   1470  1.1  dholland 				    VWRITE, cred, &nes, p,
   1471  1.1  dholland 				    NFSACCCHK_NOOVERRIDE,
   1472  1.1  dholland 				    NFSACCCHK_VPISLOCKED, NULL);
   1473  1.1  dholland 				nd->nd_repstat = nfsrv_opencheck(clientid,
   1474  1.1  dholland 				    stateidp, stp, vp, nd, p, nd->nd_repstat);
   1475  1.1  dholland 				if (!nd->nd_repstat) {
   1476  1.1  dholland 					tempsize = nvap->na_size;
   1477  1.1  dholland 					NFSVNO_ATTRINIT(nvap);
   1478  1.1  dholland 					nvap->na_size = tempsize;
   1479  1.1  dholland 					nd->nd_repstat = VOP_SETATTR(vp,
   1480  1.1  dholland 					    &nvap->na_vattr, cred);
   1481  1.1  dholland 				}
   1482  1.1  dholland 			} else if (vp->v_type == VREG) {
   1483  1.1  dholland 				nd->nd_repstat = nfsrv_opencheck(clientid,
   1484  1.1  dholland 				    stateidp, stp, vp, nd, p, nd->nd_repstat);
   1485  1.1  dholland 			}
   1486  1.1  dholland 		}
   1487  1.1  dholland 	} else {
   1488  1.1  dholland 		if (ndp->ni_cnd.cn_flags & HASBUF)
   1489  1.1  dholland 			nfsvno_relpathbuf(ndp);
   1490  1.1  dholland 		if (ndp->ni_startdir && create == NFSV4OPEN_CREATE) {
   1491  1.1  dholland 			vrele(ndp->ni_startdir);
   1492  1.1  dholland 			if (ndp->ni_dvp == ndp->ni_vp)
   1493  1.1  dholland 				vrele(ndp->ni_dvp);
   1494  1.1  dholland 			else
   1495  1.1  dholland 				vput(ndp->ni_dvp);
   1496  1.1  dholland 			if (ndp->ni_vp)
   1497  1.1  dholland 				vput(ndp->ni_vp);
   1498  1.1  dholland 		}
   1499  1.1  dholland 	}
   1500  1.1  dholland 	*vpp = vp;
   1501  1.1  dholland 
   1502  1.1  dholland 	NFSEXITCODE2(0, nd);
   1503  1.1  dholland }
   1504  1.1  dholland 
   1505  1.1  dholland /*
   1506  1.1  dholland  * Updates the file rev and sets the mtime and ctime
   1507  1.1  dholland  * to the current clock time, returning the va_filerev and va_Xtime
   1508  1.1  dholland  * values.
   1509  1.2  pgoyette  * Return ESTALE to indicate the vnode is VI_DOOMED.
   1510  1.1  dholland  */
   1511  1.2  pgoyette int
   1512  1.1  dholland nfsvno_updfilerev(struct vnode *vp, struct nfsvattr *nvap,
   1513  1.1  dholland     struct ucred *cred, struct thread *p)
   1514  1.1  dholland {
   1515  1.1  dholland 	struct vattr va;
   1516  1.1  dholland 
   1517  1.1  dholland 	VATTR_NULL(&va);
   1518  1.1  dholland 	vfs_timestamp(&va.va_mtime);
   1519  1.2  pgoyette 	if (NFSVOPISLOCKED(vp) != LK_EXCLUSIVE) {
   1520  1.2  pgoyette 		NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY);
   1521  1.2  pgoyette 		if ((vp->v_iflag & VI_DOOMED) != 0)
   1522  1.2  pgoyette 			return (ESTALE);
   1523  1.2  pgoyette 	}
   1524  1.1  dholland 	(void) VOP_SETATTR(vp, &va, cred);
   1525  1.1  dholland 	(void) nfsvno_getattr(vp, nvap, cred, p, 1);
   1526  1.2  pgoyette 	return (0);
   1527  1.1  dholland }
   1528  1.1  dholland 
   1529  1.1  dholland /*
   1530  1.1  dholland  * Glue routine to nfsv4_fillattr().
   1531  1.1  dholland  */
   1532  1.1  dholland int
   1533  1.1  dholland nfsvno_fillattr(struct nfsrv_descript *nd, struct mount *mp, struct vnode *vp,
   1534  1.1  dholland     struct nfsvattr *nvap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp,
   1535  1.1  dholland     struct ucred *cred, struct thread *p, int isdgram, int reterr,
   1536  1.1  dholland     int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
   1537  1.1  dholland {
   1538  1.1  dholland 	int error;
   1539  1.1  dholland 
   1540  1.1  dholland 	error = nfsv4_fillattr(nd, mp, vp, NULL, &nvap->na_vattr, fhp, rderror,
   1541  1.1  dholland 	    attrbitp, cred, p, isdgram, reterr, supports_nfsv4acls, at_root,
   1542  1.1  dholland 	    mounted_on_fileno);
   1543  1.1  dholland 	NFSEXITCODE2(0, nd);
   1544  1.1  dholland 	return (error);
   1545  1.1  dholland }
   1546  1.1  dholland 
   1547  1.1  dholland /* Since the Readdir vnode ops vary, put the entire functions in here. */
   1548  1.1  dholland /*
   1549  1.1  dholland  * nfs readdir service
   1550  1.1  dholland  * - mallocs what it thinks is enough to read
   1551  1.1  dholland  *	count rounded up to a multiple of DIRBLKSIZ <= NFS_MAXREADDIR
   1552  1.1  dholland  * - calls VOP_READDIR()
   1553  1.1  dholland  * - loops around building the reply
   1554  1.1  dholland  *	if the output generated exceeds count break out of loop
   1555  1.1  dholland  *	The NFSM_CLGET macro is used here so that the reply will be packed
   1556  1.1  dholland  *	tightly in mbuf clusters.
   1557  1.1  dholland  * - it trims out records with d_fileno == 0
   1558  1.1  dholland  *	this doesn't matter for Unix clients, but they might confuse clients
   1559  1.1  dholland  *	for other os'.
   1560  1.1  dholland  * - it trims out records with d_type == DT_WHT
   1561  1.1  dholland  *	these cannot be seen through NFS (unless we extend the protocol)
   1562  1.1  dholland  *     The alternate call nfsrvd_readdirplus() does lookups as well.
   1563  1.1  dholland  * PS: The NFS protocol spec. does not clarify what the "count" byte
   1564  1.1  dholland  *	argument is a count of.. just name strings and file id's or the
   1565  1.1  dholland  *	entire reply rpc or ...
   1566  1.1  dholland  *	I tried just file name and id sizes and it confused the Sun client,
   1567  1.1  dholland  *	so I am using the full rpc size now. The "paranoia.." comment refers
   1568  1.1  dholland  *	to including the status longwords that are not a part of the dir.
   1569  1.1  dholland  *	"entry" structures, but are in the rpc.
   1570  1.1  dholland  */
   1571  1.1  dholland int
   1572  1.1  dholland nfsrvd_readdir(struct nfsrv_descript *nd, int isdgram,
   1573  1.1  dholland     struct vnode *vp, struct thread *p, struct nfsexstuff *exp)
   1574  1.1  dholland {
   1575  1.1  dholland 	struct dirent *dp;
   1576  1.1  dholland 	u_int32_t *tl;
   1577  1.1  dholland 	int dirlen;
   1578  1.1  dholland 	char *cpos, *cend, *rbuf;
   1579  1.1  dholland 	struct nfsvattr at;
   1580  1.1  dholland 	int nlen, error = 0, getret = 1;
   1581  1.1  dholland 	int siz, cnt, fullsiz, eofflag, ncookies;
   1582  1.1  dholland 	u_int64_t off, toff, verf;
   1583  1.1  dholland 	u_long *cookies = NULL, *cookiep;
   1584  1.1  dholland 	struct uio io;
   1585  1.1  dholland 	struct iovec iv;
   1586  1.2  pgoyette 	int is_ufs;
   1587  1.1  dholland 
   1588  1.1  dholland 	if (nd->nd_repstat) {
   1589  1.1  dholland 		nfsrv_postopattr(nd, getret, &at);
   1590  1.1  dholland 		goto out;
   1591  1.1  dholland 	}
   1592  1.1  dholland 	if (nd->nd_flag & ND_NFSV2) {
   1593  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1594  1.1  dholland 		off = fxdr_unsigned(u_quad_t, *tl++);
   1595  1.1  dholland 	} else {
   1596  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1597  1.1  dholland 		off = fxdr_hyper(tl);
   1598  1.1  dholland 		tl += 2;
   1599  1.1  dholland 		verf = fxdr_hyper(tl);
   1600  1.1  dholland 		tl += 2;
   1601  1.1  dholland 	}
   1602  1.1  dholland 	toff = off;
   1603  1.1  dholland 	cnt = fxdr_unsigned(int, *tl);
   1604  1.1  dholland 	if (cnt > NFS_SRVMAXDATA(nd) || cnt < 0)
   1605  1.1  dholland 		cnt = NFS_SRVMAXDATA(nd);
   1606  1.1  dholland 	siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
   1607  1.1  dholland 	fullsiz = siz;
   1608  1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
   1609  1.1  dholland 		nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd->nd_cred,
   1610  1.1  dholland 		    p, 1);
   1611  1.1  dholland #if 0
   1612  1.1  dholland 		/*
   1613  1.1  dholland 		 * va_filerev is not sufficient as a cookie verifier,
   1614  1.1  dholland 		 * since it is not supposed to change when entries are
   1615  1.1  dholland 		 * removed/added unless that offset cookies returned to
   1616  1.1  dholland 		 * the client are no longer valid.
   1617  1.1  dholland 		 */
   1618  1.1  dholland 		if (!nd->nd_repstat && toff && verf != at.na_filerev)
   1619  1.1  dholland 			nd->nd_repstat = NFSERR_BAD_COOKIE;
   1620  1.1  dholland #endif
   1621  1.1  dholland 	}
   1622  1.1  dholland 	if (!nd->nd_repstat && vp->v_type != VDIR)
   1623  1.1  dholland 		nd->nd_repstat = NFSERR_NOTDIR;
   1624  1.1  dholland 	if (nd->nd_repstat == 0 && cnt == 0) {
   1625  1.1  dholland 		if (nd->nd_flag & ND_NFSV2)
   1626  1.1  dholland 			/* NFSv2 does not have NFSERR_TOOSMALL */
   1627  1.1  dholland 			nd->nd_repstat = EPERM;
   1628  1.1  dholland 		else
   1629  1.1  dholland 			nd->nd_repstat = NFSERR_TOOSMALL;
   1630  1.1  dholland 	}
   1631  1.1  dholland 	if (!nd->nd_repstat)
   1632  1.1  dholland 		nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
   1633  1.1  dholland 		    nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
   1634  1.1  dholland 		    NFSACCCHK_VPISLOCKED, NULL);
   1635  1.1  dholland 	if (nd->nd_repstat) {
   1636  1.1  dholland 		vput(vp);
   1637  1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
   1638  1.1  dholland 			nfsrv_postopattr(nd, getret, &at);
   1639  1.1  dholland 		goto out;
   1640  1.1  dholland 	}
   1641  1.2  pgoyette 	is_ufs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "ufs") == 0;
   1642  1.1  dholland 	MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
   1643  1.1  dholland again:
   1644  1.1  dholland 	eofflag = 0;
   1645  1.1  dholland 	if (cookies) {
   1646  1.1  dholland 		free((caddr_t)cookies, M_TEMP);
   1647  1.1  dholland 		cookies = NULL;
   1648  1.1  dholland 	}
   1649  1.1  dholland 
   1650  1.1  dholland 	iv.iov_base = rbuf;
   1651  1.1  dholland 	iv.iov_len = siz;
   1652  1.1  dholland 	io.uio_iov = &iv;
   1653  1.1  dholland 	io.uio_iovcnt = 1;
   1654  1.1  dholland 	io.uio_offset = (off_t)off;
   1655  1.1  dholland 	io.uio_resid = siz;
   1656  1.1  dholland 	io.uio_segflg = UIO_SYSSPACE;
   1657  1.1  dholland 	io.uio_rw = UIO_READ;
   1658  1.1  dholland 	io.uio_td = NULL;
   1659  1.1  dholland 	nd->nd_repstat = VOP_READDIR(vp, &io, nd->nd_cred, &eofflag, &ncookies,
   1660  1.1  dholland 	    &cookies);
   1661  1.1  dholland 	off = (u_int64_t)io.uio_offset;
   1662  1.1  dholland 	if (io.uio_resid)
   1663  1.1  dholland 		siz -= io.uio_resid;
   1664  1.1  dholland 
   1665  1.1  dholland 	if (!cookies && !nd->nd_repstat)
   1666  1.1  dholland 		nd->nd_repstat = NFSERR_PERM;
   1667  1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
   1668  1.1  dholland 		getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
   1669  1.1  dholland 		if (!nd->nd_repstat)
   1670  1.1  dholland 			nd->nd_repstat = getret;
   1671  1.1  dholland 	}
   1672  1.1  dholland 
   1673  1.1  dholland 	/*
   1674  1.1  dholland 	 * Handles the failed cases. nd->nd_repstat == 0 past here.
   1675  1.1  dholland 	 */
   1676  1.1  dholland 	if (nd->nd_repstat) {
   1677  1.1  dholland 		vput(vp);
   1678  1.1  dholland 		free((caddr_t)rbuf, M_TEMP);
   1679  1.1  dholland 		if (cookies)
   1680  1.1  dholland 			free((caddr_t)cookies, M_TEMP);
   1681  1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
   1682  1.1  dholland 			nfsrv_postopattr(nd, getret, &at);
   1683  1.1  dholland 		goto out;
   1684  1.1  dholland 	}
   1685  1.1  dholland 	/*
   1686  1.1  dholland 	 * If nothing read, return eof
   1687  1.1  dholland 	 * rpc reply
   1688  1.1  dholland 	 */
   1689  1.1  dholland 	if (siz == 0) {
   1690  1.1  dholland 		vput(vp);
   1691  1.1  dholland 		if (nd->nd_flag & ND_NFSV2) {
   1692  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1693  1.1  dholland 		} else {
   1694  1.1  dholland 			nfsrv_postopattr(nd, getret, &at);
   1695  1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
   1696  1.1  dholland 			txdr_hyper(at.na_filerev, tl);
   1697  1.1  dholland 			tl += 2;
   1698  1.1  dholland 		}
   1699  1.1  dholland 		*tl++ = newnfs_false;
   1700  1.1  dholland 		*tl = newnfs_true;
   1701  1.1  dholland 		FREE((caddr_t)rbuf, M_TEMP);
   1702  1.1  dholland 		FREE((caddr_t)cookies, M_TEMP);
   1703  1.1  dholland 		goto out;
   1704  1.1  dholland 	}
   1705  1.1  dholland 
   1706  1.1  dholland 	/*
   1707  1.1  dholland 	 * Check for degenerate cases of nothing useful read.
   1708  1.1  dholland 	 * If so go try again
   1709  1.1  dholland 	 */
   1710  1.1  dholland 	cpos = rbuf;
   1711  1.1  dholland 	cend = rbuf + siz;
   1712  1.1  dholland 	dp = (struct dirent *)cpos;
   1713  1.1  dholland 	cookiep = cookies;
   1714  1.1  dholland 
   1715  1.1  dholland 	/*
   1716  1.1  dholland 	 * For some reason FreeBSD's ufs_readdir() chooses to back the
   1717  1.1  dholland 	 * directory offset up to a block boundary, so it is necessary to
   1718  1.1  dholland 	 * skip over the records that precede the requested offset. This
   1719  1.1  dholland 	 * requires the assumption that file offset cookies monotonically
   1720  1.1  dholland 	 * increase.
   1721  1.1  dholland 	 */
   1722  1.1  dholland 	while (cpos < cend && ncookies > 0 &&
   1723  1.1  dholland 	    (dp->d_fileno == 0 || dp->d_type == DT_WHT ||
   1724  1.2  pgoyette 	     (is_ufs == 1 && ((u_quad_t)(*cookiep)) <= toff))) {
   1725  1.1  dholland 		cpos += dp->d_reclen;
   1726  1.1  dholland 		dp = (struct dirent *)cpos;
   1727  1.1  dholland 		cookiep++;
   1728  1.1  dholland 		ncookies--;
   1729  1.1  dholland 	}
   1730  1.1  dholland 	if (cpos >= cend || ncookies == 0) {
   1731  1.1  dholland 		siz = fullsiz;
   1732  1.1  dholland 		toff = off;
   1733  1.1  dholland 		goto again;
   1734  1.1  dholland 	}
   1735  1.1  dholland 	vput(vp);
   1736  1.1  dholland 
   1737  1.1  dholland 	/*
   1738  1.1  dholland 	 * dirlen is the size of the reply, including all XDR and must
   1739  1.1  dholland 	 * not exceed cnt. For NFSv2, RFC1094 didn't clearly indicate
   1740  1.1  dholland 	 * if the XDR should be included in "count", but to be safe, we do.
   1741  1.1  dholland 	 * (Include the two booleans at the end of the reply in dirlen now.)
   1742  1.1  dholland 	 */
   1743  1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
   1744  1.1  dholland 		nfsrv_postopattr(nd, getret, &at);
   1745  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1746  1.1  dholland 		txdr_hyper(at.na_filerev, tl);
   1747  1.1  dholland 		dirlen = NFSX_V3POSTOPATTR + NFSX_VERF + 2 * NFSX_UNSIGNED;
   1748  1.1  dholland 	} else {
   1749  1.1  dholland 		dirlen = 2 * NFSX_UNSIGNED;
   1750  1.1  dholland 	}
   1751  1.1  dholland 
   1752  1.1  dholland 	/* Loop through the records and build reply */
   1753  1.1  dholland 	while (cpos < cend && ncookies > 0) {
   1754  1.1  dholland 		nlen = dp->d_namlen;
   1755  1.1  dholland 		if (dp->d_fileno != 0 && dp->d_type != DT_WHT &&
   1756  1.1  dholland 			nlen <= NFS_MAXNAMLEN) {
   1757  1.1  dholland 			if (nd->nd_flag & ND_NFSV3)
   1758  1.1  dholland 				dirlen += (6*NFSX_UNSIGNED + NFSM_RNDUP(nlen));
   1759  1.1  dholland 			else
   1760  1.1  dholland 				dirlen += (4*NFSX_UNSIGNED + NFSM_RNDUP(nlen));
   1761  1.1  dholland 			if (dirlen > cnt) {
   1762  1.1  dholland 				eofflag = 0;
   1763  1.1  dholland 				break;
   1764  1.1  dholland 			}
   1765  1.1  dholland 
   1766  1.1  dholland 			/*
   1767  1.1  dholland 			 * Build the directory record xdr from
   1768  1.1  dholland 			 * the dirent entry.
   1769  1.1  dholland 			 */
   1770  1.1  dholland 			if (nd->nd_flag & ND_NFSV3) {
   1771  1.1  dholland 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   1772  1.1  dholland 				*tl++ = newnfs_true;
   1773  1.1  dholland 				*tl++ = 0;
   1774  1.1  dholland 			} else {
   1775  1.1  dholland 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1776  1.1  dholland 				*tl++ = newnfs_true;
   1777  1.1  dholland 			}
   1778  1.1  dholland 			*tl = txdr_unsigned(dp->d_fileno);
   1779  1.1  dholland 			(void) nfsm_strtom(nd, dp->d_name, nlen);
   1780  1.1  dholland 			if (nd->nd_flag & ND_NFSV3) {
   1781  1.1  dholland 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1782  1.1  dholland 				*tl++ = 0;
   1783  1.1  dholland 			} else
   1784  1.1  dholland 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   1785  1.1  dholland 			*tl = txdr_unsigned(*cookiep);
   1786  1.1  dholland 		}
   1787  1.1  dholland 		cpos += dp->d_reclen;
   1788  1.1  dholland 		dp = (struct dirent *)cpos;
   1789  1.1  dholland 		cookiep++;
   1790  1.1  dholland 		ncookies--;
   1791  1.1  dholland 	}
   1792  1.1  dholland 	if (cpos < cend)
   1793  1.1  dholland 		eofflag = 0;
   1794  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1795  1.1  dholland 	*tl++ = newnfs_false;
   1796  1.1  dholland 	if (eofflag)
   1797  1.1  dholland 		*tl = newnfs_true;
   1798  1.1  dholland 	else
   1799  1.1  dholland 		*tl = newnfs_false;
   1800  1.1  dholland 	FREE((caddr_t)rbuf, M_TEMP);
   1801  1.1  dholland 	FREE((caddr_t)cookies, M_TEMP);
   1802  1.1  dholland 
   1803  1.1  dholland out:
   1804  1.1  dholland 	NFSEXITCODE2(0, nd);
   1805  1.1  dholland 	return (0);
   1806  1.1  dholland nfsmout:
   1807  1.1  dholland 	vput(vp);
   1808  1.1  dholland 	NFSEXITCODE2(error, nd);
   1809  1.1  dholland 	return (error);
   1810  1.1  dholland }
   1811  1.1  dholland 
   1812  1.1  dholland /*
   1813  1.1  dholland  * Readdirplus for V3 and Readdir for V4.
   1814  1.1  dholland  */
   1815  1.1  dholland int
   1816  1.1  dholland nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
   1817  1.1  dholland     struct vnode *vp, struct thread *p, struct nfsexstuff *exp)
   1818  1.1  dholland {
   1819  1.1  dholland 	struct dirent *dp;
   1820  1.1  dholland 	u_int32_t *tl;
   1821  1.1  dholland 	int dirlen;
   1822  1.1  dholland 	char *cpos, *cend, *rbuf;
   1823  1.1  dholland 	struct vnode *nvp;
   1824  1.1  dholland 	fhandle_t nfh;
   1825  1.1  dholland 	struct nfsvattr nva, at, *nvap = &nva;
   1826  1.1  dholland 	struct mbuf *mb0, *mb1;
   1827  1.1  dholland 	struct nfsreferral *refp;
   1828  1.1  dholland 	int nlen, r, error = 0, getret = 1, usevget = 1;
   1829  1.1  dholland 	int siz, cnt, fullsiz, eofflag, ncookies, entrycnt;
   1830  1.1  dholland 	caddr_t bpos0, bpos1;
   1831  1.1  dholland 	u_int64_t off, toff, verf;
   1832  1.1  dholland 	u_long *cookies = NULL, *cookiep;
   1833  1.1  dholland 	nfsattrbit_t attrbits, rderrbits, savbits;
   1834  1.1  dholland 	struct uio io;
   1835  1.1  dholland 	struct iovec iv;
   1836  1.1  dholland 	struct componentname cn;
   1837  1.2  pgoyette 	int at_root, is_ufs, is_zfs, needs_unbusy, supports_nfsv4acls;
   1838  1.1  dholland 	struct mount *mp, *new_mp;
   1839  1.1  dholland 	uint64_t mounted_on_fileno;
   1840  1.1  dholland 
   1841  1.1  dholland 	if (nd->nd_repstat) {
   1842  1.1  dholland 		nfsrv_postopattr(nd, getret, &at);
   1843  1.1  dholland 		goto out;
   1844  1.1  dholland 	}
   1845  1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
   1846  1.1  dholland 	off = fxdr_hyper(tl);
   1847  1.1  dholland 	toff = off;
   1848  1.1  dholland 	tl += 2;
   1849  1.1  dholland 	verf = fxdr_hyper(tl);
   1850  1.1  dholland 	tl += 2;
   1851  1.1  dholland 	siz = fxdr_unsigned(int, *tl++);
   1852  1.1  dholland 	cnt = fxdr_unsigned(int, *tl);
   1853  1.1  dholland 
   1854  1.1  dholland 	/*
   1855  1.1  dholland 	 * Use the server's maximum data transfer size as the upper bound
   1856  1.1  dholland 	 * on reply datalen.
   1857  1.1  dholland 	 */
   1858  1.1  dholland 	if (cnt > NFS_SRVMAXDATA(nd) || cnt < 0)
   1859  1.1  dholland 		cnt = NFS_SRVMAXDATA(nd);
   1860  1.1  dholland 
   1861  1.1  dholland 	/*
   1862  1.1  dholland 	 * siz is a "hint" of how much directory information (name, fileid,
   1863  1.1  dholland 	 * cookie) should be in the reply. At least one client "hints" 0,
   1864  1.1  dholland 	 * so I set it to cnt for that case. I also round it up to the
   1865  1.1  dholland 	 * next multiple of DIRBLKSIZ.
   1866  1.1  dholland 	 */
   1867  1.1  dholland 	if (siz <= 0)
   1868  1.1  dholland 		siz = cnt;
   1869  1.1  dholland 	siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
   1870  1.1  dholland 
   1871  1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   1872  1.1  dholland 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
   1873  1.1  dholland 		if (error)
   1874  1.1  dholland 			goto nfsmout;
   1875  1.1  dholland 		NFSSET_ATTRBIT(&savbits, &attrbits);
   1876  1.1  dholland 		NFSCLRNOTFILLABLE_ATTRBIT(&attrbits);
   1877  1.1  dholland 		NFSZERO_ATTRBIT(&rderrbits);
   1878  1.1  dholland 		NFSSETBIT_ATTRBIT(&rderrbits, NFSATTRBIT_RDATTRERROR);
   1879  1.1  dholland 	} else {
   1880  1.1  dholland 		NFSZERO_ATTRBIT(&attrbits);
   1881  1.1  dholland 	}
   1882  1.1  dholland 	fullsiz = siz;
   1883  1.1  dholland 	nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
   1884  1.1  dholland 	if (!nd->nd_repstat) {
   1885  1.1  dholland 	    if (off && verf != at.na_filerev) {
   1886  1.1  dholland 		/*
   1887  1.1  dholland 		 * va_filerev is not sufficient as a cookie verifier,
   1888  1.1  dholland 		 * since it is not supposed to change when entries are
   1889  1.1  dholland 		 * removed/added unless that offset cookies returned to
   1890  1.1  dholland 		 * the client are no longer valid.
   1891  1.1  dholland 		 */
   1892  1.1  dholland #if 0
   1893  1.1  dholland 		if (nd->nd_flag & ND_NFSV4) {
   1894  1.1  dholland 			nd->nd_repstat = NFSERR_NOTSAME;
   1895  1.1  dholland 		} else {
   1896  1.1  dholland 			nd->nd_repstat = NFSERR_BAD_COOKIE;
   1897  1.1  dholland 		}
   1898  1.1  dholland #endif
   1899  1.1  dholland 	    } else if ((nd->nd_flag & ND_NFSV4) && off == 0 && verf != 0) {
   1900  1.1  dholland 		nd->nd_repstat = NFSERR_BAD_COOKIE;
   1901  1.1  dholland 	    }
   1902  1.1  dholland 	}
   1903  1.1  dholland 	if (!nd->nd_repstat && vp->v_type != VDIR)
   1904  1.1  dholland 		nd->nd_repstat = NFSERR_NOTDIR;
   1905  1.1  dholland 	if (!nd->nd_repstat && cnt == 0)
   1906  1.1  dholland 		nd->nd_repstat = NFSERR_TOOSMALL;
   1907  1.1  dholland 	if (!nd->nd_repstat)
   1908  1.1  dholland 		nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
   1909  1.1  dholland 		    nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
   1910  1.1  dholland 		    NFSACCCHK_VPISLOCKED, NULL);
   1911  1.1  dholland 	if (nd->nd_repstat) {
   1912  1.1  dholland 		vput(vp);
   1913  1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
   1914  1.1  dholland 			nfsrv_postopattr(nd, getret, &at);
   1915  1.1  dholland 		goto out;
   1916  1.1  dholland 	}
   1917  1.2  pgoyette 	is_ufs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "ufs") == 0;
   1918  1.2  pgoyette 	is_zfs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "zfs") == 0;
   1919  1.1  dholland 
   1920  1.1  dholland 	MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
   1921  1.1  dholland again:
   1922  1.1  dholland 	eofflag = 0;
   1923  1.1  dholland 	if (cookies) {
   1924  1.1  dholland 		free((caddr_t)cookies, M_TEMP);
   1925  1.1  dholland 		cookies = NULL;
   1926  1.1  dholland 	}
   1927  1.1  dholland 
   1928  1.1  dholland 	iv.iov_base = rbuf;
   1929  1.1  dholland 	iv.iov_len = siz;
   1930  1.1  dholland 	io.uio_iov = &iv;
   1931  1.1  dholland 	io.uio_iovcnt = 1;
   1932  1.1  dholland 	io.uio_offset = (off_t)off;
   1933  1.1  dholland 	io.uio_resid = siz;
   1934  1.1  dholland 	io.uio_segflg = UIO_SYSSPACE;
   1935  1.1  dholland 	io.uio_rw = UIO_READ;
   1936  1.1  dholland 	io.uio_td = NULL;
   1937  1.1  dholland 	nd->nd_repstat = VOP_READDIR(vp, &io, nd->nd_cred, &eofflag, &ncookies,
   1938  1.1  dholland 	    &cookies);
   1939  1.1  dholland 	off = (u_int64_t)io.uio_offset;
   1940  1.1  dholland 	if (io.uio_resid)
   1941  1.1  dholland 		siz -= io.uio_resid;
   1942  1.1  dholland 
   1943  1.1  dholland 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
   1944  1.1  dholland 
   1945  1.1  dholland 	if (!cookies && !nd->nd_repstat)
   1946  1.1  dholland 		nd->nd_repstat = NFSERR_PERM;
   1947  1.1  dholland 	if (!nd->nd_repstat)
   1948  1.1  dholland 		nd->nd_repstat = getret;
   1949  1.1  dholland 	if (nd->nd_repstat) {
   1950  1.1  dholland 		vput(vp);
   1951  1.1  dholland 		if (cookies)
   1952  1.1  dholland 			free((caddr_t)cookies, M_TEMP);
   1953  1.1  dholland 		free((caddr_t)rbuf, M_TEMP);
   1954  1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
   1955  1.1  dholland 			nfsrv_postopattr(nd, getret, &at);
   1956  1.1  dholland 		goto out;
   1957  1.1  dholland 	}
   1958  1.1  dholland 	/*
   1959  1.1  dholland 	 * If nothing read, return eof
   1960  1.1  dholland 	 * rpc reply
   1961  1.1  dholland 	 */
   1962  1.1  dholland 	if (siz == 0) {
   1963  1.1  dholland 		vput(vp);
   1964  1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
   1965  1.1  dholland 			nfsrv_postopattr(nd, getret, &at);
   1966  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
   1967  1.1  dholland 		txdr_hyper(at.na_filerev, tl);
   1968  1.1  dholland 		tl += 2;
   1969  1.1  dholland 		*tl++ = newnfs_false;
   1970  1.1  dholland 		*tl = newnfs_true;
   1971  1.1  dholland 		free((caddr_t)cookies, M_TEMP);
   1972  1.1  dholland 		free((caddr_t)rbuf, M_TEMP);
   1973  1.1  dholland 		goto out;
   1974  1.1  dholland 	}
   1975  1.1  dholland 
   1976  1.1  dholland 	/*
   1977  1.1  dholland 	 * Check for degenerate cases of nothing useful read.
   1978  1.1  dholland 	 * If so go try again
   1979  1.1  dholland 	 */
   1980  1.1  dholland 	cpos = rbuf;
   1981  1.1  dholland 	cend = rbuf + siz;
   1982  1.1  dholland 	dp = (struct dirent *)cpos;
   1983  1.1  dholland 	cookiep = cookies;
   1984  1.1  dholland 
   1985  1.1  dholland 	/*
   1986  1.1  dholland 	 * For some reason FreeBSD's ufs_readdir() chooses to back the
   1987  1.1  dholland 	 * directory offset up to a block boundary, so it is necessary to
   1988  1.1  dholland 	 * skip over the records that precede the requested offset. This
   1989  1.1  dholland 	 * requires the assumption that file offset cookies monotonically
   1990  1.1  dholland 	 * increase.
   1991  1.1  dholland 	 */
   1992  1.1  dholland 	while (cpos < cend && ncookies > 0 &&
   1993  1.1  dholland 	  (dp->d_fileno == 0 || dp->d_type == DT_WHT ||
   1994  1.2  pgoyette 	   (is_ufs == 1 && ((u_quad_t)(*cookiep)) <= toff) ||
   1995  1.1  dholland 	   ((nd->nd_flag & ND_NFSV4) &&
   1996  1.1  dholland 	    ((dp->d_namlen == 1 && dp->d_name[0] == '.') ||
   1997  1.1  dholland 	     (dp->d_namlen==2 && dp->d_name[0]=='.' && dp->d_name[1]=='.'))))) {
   1998  1.1  dholland 		cpos += dp->d_reclen;
   1999  1.1  dholland 		dp = (struct dirent *)cpos;
   2000  1.1  dholland 		cookiep++;
   2001  1.1  dholland 		ncookies--;
   2002  1.1  dholland 	}
   2003  1.1  dholland 	if (cpos >= cend || ncookies == 0) {
   2004  1.1  dholland 		siz = fullsiz;
   2005  1.1  dholland 		toff = off;
   2006  1.1  dholland 		goto again;
   2007  1.1  dholland 	}
   2008  1.1  dholland 
   2009  1.1  dholland 	/*
   2010  1.1  dholland 	 * Busy the file system so that the mount point won't go away
   2011  1.1  dholland 	 * and, as such, VFS_VGET() can be used safely.
   2012  1.1  dholland 	 */
   2013  1.1  dholland 	mp = vp->v_mount;
   2014  1.1  dholland 	vfs_ref(mp);
   2015  1.1  dholland 	NFSVOPUNLOCK(vp, 0);
   2016  1.1  dholland 	nd->nd_repstat = vfs_busy(mp, 0);
   2017  1.1  dholland 	vfs_rel(mp);
   2018  1.1  dholland 	if (nd->nd_repstat != 0) {
   2019  1.1  dholland 		vrele(vp);
   2020  1.1  dholland 		free(cookies, M_TEMP);
   2021  1.1  dholland 		free(rbuf, M_TEMP);
   2022  1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
   2023  1.1  dholland 			nfsrv_postopattr(nd, getret, &at);
   2024  1.1  dholland 		goto out;
   2025  1.1  dholland 	}
   2026  1.1  dholland 
   2027  1.1  dholland 	/*
   2028  1.2  pgoyette 	 * Check to see if entries in this directory can be safely acquired
   2029  1.2  pgoyette 	 * via VFS_VGET() or if a switch to VOP_LOOKUP() is required.
   2030  1.2  pgoyette 	 * ZFS snapshot directories need VOP_LOOKUP(), so that any
   2031  1.2  pgoyette 	 * automount of the snapshot directory that is required will
   2032  1.2  pgoyette 	 * be done.
   2033  1.2  pgoyette 	 * This needs to be done here for NFSv4, since NFSv4 never does
   2034  1.2  pgoyette 	 * a VFS_VGET() for "." or "..".
   2035  1.2  pgoyette 	 */
   2036  1.2  pgoyette 	if (is_zfs == 1) {
   2037  1.2  pgoyette 		r = VFS_VGET(mp, at.na_fileid, LK_SHARED, &nvp);
   2038  1.2  pgoyette 		if (r == EOPNOTSUPP) {
   2039  1.2  pgoyette 			usevget = 0;
   2040  1.2  pgoyette 			cn.cn_nameiop = LOOKUP;
   2041  1.2  pgoyette 			cn.cn_lkflags = LK_SHARED | LK_RETRY;
   2042  1.2  pgoyette 			cn.cn_cred = nd->nd_cred;
   2043  1.2  pgoyette 			cn.cn_thread = p;
   2044  1.2  pgoyette 		} else if (r == 0)
   2045  1.2  pgoyette 			vput(nvp);
   2046  1.2  pgoyette 	}
   2047  1.2  pgoyette 
   2048  1.2  pgoyette 	/*
   2049  1.1  dholland 	 * Save this position, in case there is an error before one entry
   2050  1.1  dholland 	 * is created.
   2051  1.1  dholland 	 */
   2052  1.1  dholland 	mb0 = nd->nd_mb;
   2053  1.1  dholland 	bpos0 = nd->nd_bpos;
   2054  1.1  dholland 
   2055  1.1  dholland 	/*
   2056  1.1  dholland 	 * Fill in the first part of the reply.
   2057  1.1  dholland 	 * dirlen is the reply length in bytes and cannot exceed cnt.
   2058  1.1  dholland 	 * (Include the two booleans at the end of the reply in dirlen now,
   2059  1.1  dholland 	 *  so we recognize when we have exceeded cnt.)
   2060  1.1  dholland 	 */
   2061  1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
   2062  1.1  dholland 		dirlen = NFSX_V3POSTOPATTR + NFSX_VERF + 2 * NFSX_UNSIGNED;
   2063  1.1  dholland 		nfsrv_postopattr(nd, getret, &at);
   2064  1.1  dholland 	} else {
   2065  1.1  dholland 		dirlen = NFSX_VERF + 2 * NFSX_UNSIGNED;
   2066  1.1  dholland 	}
   2067  1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
   2068  1.1  dholland 	txdr_hyper(at.na_filerev, tl);
   2069  1.1  dholland 
   2070  1.1  dholland 	/*
   2071  1.1  dholland 	 * Save this position, in case there is an empty reply needed.
   2072  1.1  dholland 	 */
   2073  1.1  dholland 	mb1 = nd->nd_mb;
   2074  1.1  dholland 	bpos1 = nd->nd_bpos;
   2075  1.1  dholland 
   2076  1.1  dholland 	/* Loop through the records and build reply */
   2077  1.1  dholland 	entrycnt = 0;
   2078  1.1  dholland 	while (cpos < cend && ncookies > 0 && dirlen < cnt) {
   2079  1.1  dholland 		nlen = dp->d_namlen;
   2080  1.1  dholland 		if (dp->d_fileno != 0 && dp->d_type != DT_WHT &&
   2081  1.1  dholland 		    nlen <= NFS_MAXNAMLEN &&
   2082  1.1  dholland 		    ((nd->nd_flag & ND_NFSV3) || nlen > 2 ||
   2083  1.1  dholland 		     (nlen==2 && (dp->d_name[0]!='.' || dp->d_name[1]!='.'))
   2084  1.1  dholland 		      || (nlen == 1 && dp->d_name[0] != '.'))) {
   2085  1.1  dholland 			/*
   2086  1.1  dholland 			 * Save the current position in the reply, in case
   2087  1.1  dholland 			 * this entry exceeds cnt.
   2088  1.1  dholland 			 */
   2089  1.1  dholland 			mb1 = nd->nd_mb;
   2090  1.1  dholland 			bpos1 = nd->nd_bpos;
   2091  1.1  dholland 
   2092  1.1  dholland 			/*
   2093  1.1  dholland 			 * For readdir_and_lookup get the vnode using
   2094  1.1  dholland 			 * the file number.
   2095  1.1  dholland 			 */
   2096  1.1  dholland 			nvp = NULL;
   2097  1.1  dholland 			refp = NULL;
   2098  1.1  dholland 			r = 0;
   2099  1.1  dholland 			at_root = 0;
   2100  1.1  dholland 			needs_unbusy = 0;
   2101  1.1  dholland 			new_mp = mp;
   2102  1.1  dholland 			mounted_on_fileno = (uint64_t)dp->d_fileno;
   2103  1.1  dholland 			if ((nd->nd_flag & ND_NFSV3) ||
   2104  1.1  dholland 			    NFSNONZERO_ATTRBIT(&savbits)) {
   2105  1.1  dholland 				if (nd->nd_flag & ND_NFSV4)
   2106  1.1  dholland 					refp = nfsv4root_getreferral(NULL,
   2107  1.1  dholland 					    vp, dp->d_fileno);
   2108  1.1  dholland 				if (refp == NULL) {
   2109  1.1  dholland 					if (usevget)
   2110  1.1  dholland 						r = VFS_VGET(mp, dp->d_fileno,
   2111  1.1  dholland 						    LK_SHARED, &nvp);
   2112  1.1  dholland 					else
   2113  1.1  dholland 						r = EOPNOTSUPP;
   2114  1.1  dholland 					if (r == EOPNOTSUPP) {
   2115  1.1  dholland 						if (usevget) {
   2116  1.1  dholland 							usevget = 0;
   2117  1.1  dholland 							cn.cn_nameiop = LOOKUP;
   2118  1.1  dholland 							cn.cn_lkflags =
   2119  1.1  dholland 							    LK_SHARED |
   2120  1.1  dholland 							    LK_RETRY;
   2121  1.1  dholland 							cn.cn_cred =
   2122  1.1  dholland 							    nd->nd_cred;
   2123  1.1  dholland 							cn.cn_thread = p;
   2124  1.1  dholland 						}
   2125  1.1  dholland 						cn.cn_nameptr = dp->d_name;
   2126  1.1  dholland 						cn.cn_namelen = nlen;
   2127  1.1  dholland 						cn.cn_flags = ISLASTCN |
   2128  1.1  dholland 						    NOFOLLOW | LOCKLEAF;
   2129  1.1  dholland 						if (nlen == 2 &&
   2130  1.1  dholland 						    dp->d_name[0] == '.' &&
   2131  1.1  dholland 						    dp->d_name[1] == '.')
   2132  1.1  dholland 							cn.cn_flags |=
   2133  1.1  dholland 							    ISDOTDOT;
   2134  1.1  dholland 						if (NFSVOPLOCK(vp, LK_SHARED)
   2135  1.1  dholland 						    != 0) {
   2136  1.1  dholland 							nd->nd_repstat = EPERM;
   2137  1.1  dholland 							break;
   2138  1.1  dholland 						}
   2139  1.1  dholland 						if ((vp->v_vflag & VV_ROOT) != 0
   2140  1.1  dholland 						    && (cn.cn_flags & ISDOTDOT)
   2141  1.1  dholland 						    != 0) {
   2142  1.1  dholland 							vref(vp);
   2143  1.1  dholland 							nvp = vp;
   2144  1.1  dholland 							r = 0;
   2145  1.1  dholland 						} else {
   2146  1.1  dholland 							r = VOP_LOOKUP(vp, &nvp,
   2147  1.1  dholland 							    &cn);
   2148  1.1  dholland 							if (vp != nvp)
   2149  1.1  dholland 								NFSVOPUNLOCK(vp,
   2150  1.1  dholland 								    0);
   2151  1.1  dholland 						}
   2152  1.1  dholland 					}
   2153  1.1  dholland 
   2154  1.1  dholland 					/*
   2155  1.1  dholland 					 * For NFSv4, check to see if nvp is
   2156  1.1  dholland 					 * a mount point and get the mount
   2157  1.1  dholland 					 * point vnode, as required.
   2158  1.1  dholland 					 */
   2159  1.1  dholland 					if (r == 0 &&
   2160  1.1  dholland 					    nfsrv_enable_crossmntpt != 0 &&
   2161  1.1  dholland 					    (nd->nd_flag & ND_NFSV4) != 0 &&
   2162  1.1  dholland 					    nvp->v_type == VDIR &&
   2163  1.1  dholland 					    nvp->v_mountedhere != NULL) {
   2164  1.1  dholland 						new_mp = nvp->v_mountedhere;
   2165  1.1  dholland 						r = vfs_busy(new_mp, 0);
   2166  1.1  dholland 						vput(nvp);
   2167  1.1  dholland 						nvp = NULL;
   2168  1.1  dholland 						if (r == 0) {
   2169  1.1  dholland 							r = VFS_ROOT(new_mp,
   2170  1.1  dholland 							    LK_SHARED, &nvp);
   2171  1.1  dholland 							needs_unbusy = 1;
   2172  1.1  dholland 							if (r == 0)
   2173  1.1  dholland 								at_root = 1;
   2174  1.1  dholland 						}
   2175  1.1  dholland 					}
   2176  1.1  dholland 				}
   2177  1.1  dholland 				if (!r) {
   2178  1.1  dholland 				    if (refp == NULL &&
   2179  1.1  dholland 					((nd->nd_flag & ND_NFSV3) ||
   2180  1.1  dholland 					 NFSNONZERO_ATTRBIT(&attrbits))) {
   2181  1.1  dholland 					r = nfsvno_getfh(nvp, &nfh, p);
   2182  1.1  dholland 					if (!r)
   2183  1.1  dholland 					    r = nfsvno_getattr(nvp, nvap,
   2184  1.1  dholland 						nd->nd_cred, p, 1);
   2185  1.2  pgoyette 					if (r == 0 && is_zfs == 1 &&
   2186  1.2  pgoyette 					    nfsrv_enable_crossmntpt != 0 &&
   2187  1.2  pgoyette 					    (nd->nd_flag & ND_NFSV4) != 0 &&
   2188  1.2  pgoyette 					    nvp->v_type == VDIR &&
   2189  1.2  pgoyette 					    vp->v_mount != nvp->v_mount) {
   2190  1.2  pgoyette 					    /*
   2191  1.2  pgoyette 					     * For a ZFS snapshot, there is a
   2192  1.2  pgoyette 					     * pseudo mount that does not set
   2193  1.2  pgoyette 					     * v_mountedhere, so it needs to
   2194  1.2  pgoyette 					     * be detected via a different
   2195  1.2  pgoyette 					     * mount structure.
   2196  1.2  pgoyette 					     */
   2197  1.2  pgoyette 					    at_root = 1;
   2198  1.2  pgoyette 					    if (new_mp == mp)
   2199  1.2  pgoyette 						new_mp = nvp->v_mount;
   2200  1.2  pgoyette 					}
   2201  1.1  dholland 				    }
   2202  1.1  dholland 				} else {
   2203  1.1  dholland 				    nvp = NULL;
   2204  1.1  dholland 				}
   2205  1.1  dholland 				if (r) {
   2206  1.1  dholland 					if (!NFSISSET_ATTRBIT(&attrbits,
   2207  1.1  dholland 					    NFSATTRBIT_RDATTRERROR)) {
   2208  1.1  dholland 						if (nvp != NULL)
   2209  1.1  dholland 							vput(nvp);
   2210  1.1  dholland 						if (needs_unbusy != 0)
   2211  1.1  dholland 							vfs_unbusy(new_mp);
   2212  1.1  dholland 						nd->nd_repstat = r;
   2213  1.1  dholland 						break;
   2214  1.1  dholland 					}
   2215  1.1  dholland 				}
   2216  1.1  dholland 			}
   2217  1.1  dholland 
   2218  1.1  dholland 			/*
   2219  1.1  dholland 			 * Build the directory record xdr
   2220  1.1  dholland 			 */
   2221  1.1  dholland 			if (nd->nd_flag & ND_NFSV3) {
   2222  1.1  dholland 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   2223  1.1  dholland 				*tl++ = newnfs_true;
   2224  1.1  dholland 				*tl++ = 0;
   2225  1.1  dholland 				*tl = txdr_unsigned(dp->d_fileno);
   2226  1.1  dholland 				dirlen += nfsm_strtom(nd, dp->d_name, nlen);
   2227  1.1  dholland 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2228  1.1  dholland 				*tl++ = 0;
   2229  1.1  dholland 				*tl = txdr_unsigned(*cookiep);
   2230  1.1  dholland 				nfsrv_postopattr(nd, 0, nvap);
   2231  1.1  dholland 				dirlen += nfsm_fhtom(nd,(u_int8_t *)&nfh,0,1);
   2232  1.1  dholland 				dirlen += (5*NFSX_UNSIGNED+NFSX_V3POSTOPATTR);
   2233  1.1  dholland 				if (nvp != NULL)
   2234  1.1  dholland 					vput(nvp);
   2235  1.1  dholland 			} else {
   2236  1.1  dholland 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   2237  1.1  dholland 				*tl++ = newnfs_true;
   2238  1.1  dholland 				*tl++ = 0;
   2239  1.1  dholland 				*tl = txdr_unsigned(*cookiep);
   2240  1.1  dholland 				dirlen += nfsm_strtom(nd, dp->d_name, nlen);
   2241  1.1  dholland 				if (nvp != NULL) {
   2242  1.1  dholland 					supports_nfsv4acls =
   2243  1.1  dholland 					    nfs_supportsnfsv4acls(nvp);
   2244  1.1  dholland 					NFSVOPUNLOCK(nvp, 0);
   2245  1.1  dholland 				} else
   2246  1.1  dholland 					supports_nfsv4acls = 0;
   2247  1.1  dholland 				if (refp != NULL) {
   2248  1.1  dholland 					dirlen += nfsrv_putreferralattr(nd,
   2249  1.1  dholland 					    &savbits, refp, 0,
   2250  1.1  dholland 					    &nd->nd_repstat);
   2251  1.1  dholland 					if (nd->nd_repstat) {
   2252  1.1  dholland 						if (nvp != NULL)
   2253  1.1  dholland 							vrele(nvp);
   2254  1.1  dholland 						if (needs_unbusy != 0)
   2255  1.1  dholland 							vfs_unbusy(new_mp);
   2256  1.1  dholland 						break;
   2257  1.1  dholland 					}
   2258  1.1  dholland 				} else if (r) {
   2259  1.1  dholland 					dirlen += nfsvno_fillattr(nd, new_mp,
   2260  1.1  dholland 					    nvp, nvap, &nfh, r, &rderrbits,
   2261  1.1  dholland 					    nd->nd_cred, p, isdgram, 0,
   2262  1.1  dholland 					    supports_nfsv4acls, at_root,
   2263  1.1  dholland 					    mounted_on_fileno);
   2264  1.1  dholland 				} else {
   2265  1.1  dholland 					dirlen += nfsvno_fillattr(nd, new_mp,
   2266  1.1  dholland 					    nvp, nvap, &nfh, r, &attrbits,
   2267  1.1  dholland 					    nd->nd_cred, p, isdgram, 0,
   2268  1.1  dholland 					    supports_nfsv4acls, at_root,
   2269  1.1  dholland 					    mounted_on_fileno);
   2270  1.1  dholland 				}
   2271  1.1  dholland 				if (nvp != NULL)
   2272  1.1  dholland 					vrele(nvp);
   2273  1.1  dholland 				dirlen += (3 * NFSX_UNSIGNED);
   2274  1.1  dholland 			}
   2275  1.1  dholland 			if (needs_unbusy != 0)
   2276  1.1  dholland 				vfs_unbusy(new_mp);
   2277  1.1  dholland 			if (dirlen <= cnt)
   2278  1.1  dholland 				entrycnt++;
   2279  1.1  dholland 		}
   2280  1.1  dholland 		cpos += dp->d_reclen;
   2281  1.1  dholland 		dp = (struct dirent *)cpos;
   2282  1.1  dholland 		cookiep++;
   2283  1.1  dholland 		ncookies--;
   2284  1.1  dholland 	}
   2285  1.1  dholland 	vrele(vp);
   2286  1.1  dholland 	vfs_unbusy(mp);
   2287  1.1  dholland 
   2288  1.1  dholland 	/*
   2289  1.1  dholland 	 * If dirlen > cnt, we must strip off the last entry. If that
   2290  1.1  dholland 	 * results in an empty reply, report NFSERR_TOOSMALL.
   2291  1.1  dholland 	 */
   2292  1.1  dholland 	if (dirlen > cnt || nd->nd_repstat) {
   2293  1.1  dholland 		if (!nd->nd_repstat && entrycnt == 0)
   2294  1.1  dholland 			nd->nd_repstat = NFSERR_TOOSMALL;
   2295  1.2  pgoyette 		if (nd->nd_repstat) {
   2296  1.1  dholland 			newnfs_trimtrailing(nd, mb0, bpos0);
   2297  1.2  pgoyette 			if (nd->nd_flag & ND_NFSV3)
   2298  1.2  pgoyette 				nfsrv_postopattr(nd, getret, &at);
   2299  1.2  pgoyette 		} else
   2300  1.1  dholland 			newnfs_trimtrailing(nd, mb1, bpos1);
   2301  1.1  dholland 		eofflag = 0;
   2302  1.1  dholland 	} else if (cpos < cend)
   2303  1.1  dholland 		eofflag = 0;
   2304  1.1  dholland 	if (!nd->nd_repstat) {
   2305  1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2306  1.1  dholland 		*tl++ = newnfs_false;
   2307  1.1  dholland 		if (eofflag)
   2308  1.1  dholland 			*tl = newnfs_true;
   2309  1.1  dholland 		else
   2310  1.1  dholland 			*tl = newnfs_false;
   2311  1.1  dholland 	}
   2312  1.1  dholland 	FREE((caddr_t)cookies, M_TEMP);
   2313  1.1  dholland 	FREE((caddr_t)rbuf, M_TEMP);
   2314  1.1  dholland 
   2315  1.1  dholland out:
   2316  1.1  dholland 	NFSEXITCODE2(0, nd);
   2317  1.1  dholland 	return (0);
   2318  1.1  dholland nfsmout:
   2319  1.1  dholland 	vput(vp);
   2320  1.1  dholland 	NFSEXITCODE2(error, nd);
   2321  1.1  dholland 	return (error);
   2322  1.1  dholland }
   2323  1.1  dholland 
   2324  1.1  dholland /*
   2325  1.1  dholland  * Get the settable attributes out of the mbuf list.
   2326  1.1  dholland  * (Return 0 or EBADRPC)
   2327  1.1  dholland  */
   2328  1.1  dholland int
   2329  1.2  pgoyette nfsrv_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
   2330  1.1  dholland     nfsattrbit_t *attrbitp, NFSACL_T *aclp, struct thread *p)
   2331  1.1  dholland {
   2332  1.1  dholland 	u_int32_t *tl;
   2333  1.1  dholland 	struct nfsv2_sattr *sp;
   2334  1.1  dholland 	int error = 0, toclient = 0;
   2335  1.1  dholland 
   2336  1.1  dholland 	switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
   2337  1.1  dholland 	case ND_NFSV2:
   2338  1.1  dholland 		NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
   2339  1.1  dholland 		/*
   2340  1.1  dholland 		 * Some old clients didn't fill in the high order 16bits.
   2341  1.1  dholland 		 * --> check the low order 2 bytes for 0xffff
   2342  1.1  dholland 		 */
   2343  1.1  dholland 		if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
   2344  1.1  dholland 			nvap->na_mode = nfstov_mode(sp->sa_mode);
   2345  1.1  dholland 		if (sp->sa_uid != newnfs_xdrneg1)
   2346  1.1  dholland 			nvap->na_uid = fxdr_unsigned(uid_t, sp->sa_uid);
   2347  1.1  dholland 		if (sp->sa_gid != newnfs_xdrneg1)
   2348  1.1  dholland 			nvap->na_gid = fxdr_unsigned(gid_t, sp->sa_gid);
   2349  1.1  dholland 		if (sp->sa_size != newnfs_xdrneg1)
   2350  1.1  dholland 			nvap->na_size = fxdr_unsigned(u_quad_t, sp->sa_size);
   2351  1.1  dholland 		if (sp->sa_atime.nfsv2_sec != newnfs_xdrneg1) {
   2352  1.1  dholland #ifdef notyet
   2353  1.1  dholland 			fxdr_nfsv2time(&sp->sa_atime, &nvap->na_atime);
   2354  1.1  dholland #else
   2355  1.1  dholland 			nvap->na_atime.tv_sec =
   2356  1.1  dholland 				fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec);
   2357  1.1  dholland 			nvap->na_atime.tv_nsec = 0;
   2358  1.1  dholland #endif
   2359  1.1  dholland 		}
   2360  1.1  dholland 		if (sp->sa_mtime.nfsv2_sec != newnfs_xdrneg1)
   2361  1.1  dholland 			fxdr_nfsv2time(&sp->sa_mtime, &nvap->na_mtime);
   2362  1.1  dholland 		break;
   2363  1.1  dholland 	case ND_NFSV3:
   2364  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2365  1.1  dholland 		if (*tl == newnfs_true) {
   2366  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2367  1.1  dholland 			nvap->na_mode = nfstov_mode(*tl);
   2368  1.1  dholland 		}
   2369  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2370  1.1  dholland 		if (*tl == newnfs_true) {
   2371  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2372  1.1  dholland 			nvap->na_uid = fxdr_unsigned(uid_t, *tl);
   2373  1.1  dholland 		}
   2374  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2375  1.1  dholland 		if (*tl == newnfs_true) {
   2376  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2377  1.1  dholland 			nvap->na_gid = fxdr_unsigned(gid_t, *tl);
   2378  1.1  dholland 		}
   2379  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2380  1.1  dholland 		if (*tl == newnfs_true) {
   2381  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2382  1.1  dholland 			nvap->na_size = fxdr_hyper(tl);
   2383  1.1  dholland 		}
   2384  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2385  1.1  dholland 		switch (fxdr_unsigned(int, *tl)) {
   2386  1.1  dholland 		case NFSV3SATTRTIME_TOCLIENT:
   2387  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2388  1.1  dholland 			fxdr_nfsv3time(tl, &nvap->na_atime);
   2389  1.1  dholland 			toclient = 1;
   2390  1.1  dholland 			break;
   2391  1.1  dholland 		case NFSV3SATTRTIME_TOSERVER:
   2392  1.1  dholland 			vfs_timestamp(&nvap->na_atime);
   2393  1.1  dholland 			nvap->na_vaflags |= VA_UTIMES_NULL;
   2394  1.1  dholland 			break;
   2395  1.2  pgoyette 		}
   2396  1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2397  1.1  dholland 		switch (fxdr_unsigned(int, *tl)) {
   2398  1.1  dholland 		case NFSV3SATTRTIME_TOCLIENT:
   2399  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2400  1.1  dholland 			fxdr_nfsv3time(tl, &nvap->na_mtime);
   2401  1.1  dholland 			nvap->na_vaflags &= ~VA_UTIMES_NULL;
   2402  1.1  dholland 			break;
   2403  1.1  dholland 		case NFSV3SATTRTIME_TOSERVER:
   2404  1.1  dholland 			vfs_timestamp(&nvap->na_mtime);
   2405  1.1  dholland 			if (!toclient)
   2406  1.1  dholland 				nvap->na_vaflags |= VA_UTIMES_NULL;
   2407  1.1  dholland 			break;
   2408  1.2  pgoyette 		}
   2409  1.1  dholland 		break;
   2410  1.1  dholland 	case ND_NFSV4:
   2411  1.2  pgoyette 		error = nfsv4_sattr(nd, vp, nvap, attrbitp, aclp, p);
   2412  1.2  pgoyette 	}
   2413  1.1  dholland nfsmout:
   2414  1.1  dholland 	NFSEXITCODE2(error, nd);
   2415  1.1  dholland 	return (error);
   2416  1.1  dholland }
   2417  1.1  dholland 
   2418  1.1  dholland /*
   2419  1.1  dholland  * Handle the setable attributes for V4.
   2420  1.1  dholland  * Returns NFSERR_BADXDR if it can't be parsed, 0 otherwise.
   2421  1.1  dholland  */
   2422  1.1  dholland int
   2423  1.2  pgoyette nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
   2424  1.1  dholland     nfsattrbit_t *attrbitp, NFSACL_T *aclp, struct thread *p)
   2425  1.1  dholland {
   2426  1.1  dholland 	u_int32_t *tl;
   2427  1.1  dholland 	int attrsum = 0;
   2428  1.1  dholland 	int i, j;
   2429  1.1  dholland 	int error, attrsize, bitpos, aclsize, aceerr, retnotsup = 0;
   2430  1.1  dholland 	int toclient = 0;
   2431  1.1  dholland 	u_char *cp, namestr[NFSV4_SMALLSTR + 1];
   2432  1.1  dholland 	uid_t uid;
   2433  1.1  dholland 	gid_t gid;
   2434  1.1  dholland 
   2435  1.1  dholland 	error = nfsrv_getattrbits(nd, attrbitp, NULL, &retnotsup);
   2436  1.1  dholland 	if (error)
   2437  1.1  dholland 		goto nfsmout;
   2438  1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2439  1.1  dholland 	attrsize = fxdr_unsigned(int, *tl);
   2440  1.1  dholland 
   2441  1.1  dholland 	/*
   2442  1.1  dholland 	 * Loop around getting the setable attributes. If an unsupported
   2443  1.1  dholland 	 * one is found, set nd_repstat == NFSERR_ATTRNOTSUPP and return.
   2444  1.1  dholland 	 */
   2445  1.1  dholland 	if (retnotsup) {
   2446  1.1  dholland 		nd->nd_repstat = NFSERR_ATTRNOTSUPP;
   2447  1.1  dholland 		bitpos = NFSATTRBIT_MAX;
   2448  1.1  dholland 	} else {
   2449  1.1  dholland 		bitpos = 0;
   2450  1.1  dholland 	}
   2451  1.1  dholland 	for (; bitpos < NFSATTRBIT_MAX; bitpos++) {
   2452  1.1  dholland 	    if (attrsum > attrsize) {
   2453  1.1  dholland 		error = NFSERR_BADXDR;
   2454  1.1  dholland 		goto nfsmout;
   2455  1.1  dholland 	    }
   2456  1.1  dholland 	    if (NFSISSET_ATTRBIT(attrbitp, bitpos))
   2457  1.1  dholland 		switch (bitpos) {
   2458  1.1  dholland 		case NFSATTRBIT_SIZE:
   2459  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   2460  1.2  pgoyette                      if (vp != NULL && vp->v_type != VREG) {
   2461  1.2  pgoyette                             error = (vp->v_type == VDIR) ? NFSERR_ISDIR :
   2462  1.2  pgoyette                                 NFSERR_INVAL;
   2463  1.2  pgoyette                             goto nfsmout;
   2464  1.2  pgoyette 			}
   2465  1.1  dholland 			nvap->na_size = fxdr_hyper(tl);
   2466  1.1  dholland 			attrsum += NFSX_HYPER;
   2467  1.1  dholland 			break;
   2468  1.1  dholland 		case NFSATTRBIT_ACL:
   2469  1.1  dholland 			error = nfsrv_dissectacl(nd, aclp, &aceerr, &aclsize,
   2470  1.1  dholland 			    p);
   2471  1.1  dholland 			if (error)
   2472  1.1  dholland 				goto nfsmout;
   2473  1.1  dholland 			if (aceerr && !nd->nd_repstat)
   2474  1.1  dholland 				nd->nd_repstat = aceerr;
   2475  1.1  dholland 			attrsum += aclsize;
   2476  1.1  dholland 			break;
   2477  1.1  dholland 		case NFSATTRBIT_ARCHIVE:
   2478  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2479  1.1  dholland 			if (!nd->nd_repstat)
   2480  1.1  dholland 				nd->nd_repstat = NFSERR_ATTRNOTSUPP;
   2481  1.1  dholland 			attrsum += NFSX_UNSIGNED;
   2482  1.1  dholland 			break;
   2483  1.1  dholland 		case NFSATTRBIT_HIDDEN:
   2484  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2485  1.1  dholland 			if (!nd->nd_repstat)
   2486  1.1  dholland 				nd->nd_repstat = NFSERR_ATTRNOTSUPP;
   2487  1.1  dholland 			attrsum += NFSX_UNSIGNED;
   2488  1.1  dholland 			break;
   2489  1.1  dholland 		case NFSATTRBIT_MIMETYPE:
   2490  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2491  1.1  dholland 			i = fxdr_unsigned(int, *tl);
   2492  1.1  dholland 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
   2493  1.1  dholland 			if (error)
   2494  1.1  dholland 				goto nfsmout;
   2495  1.1  dholland 			if (!nd->nd_repstat)
   2496  1.1  dholland 				nd->nd_repstat = NFSERR_ATTRNOTSUPP;
   2497  1.1  dholland 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
   2498  1.1  dholland 			break;
   2499  1.1  dholland 		case NFSATTRBIT_MODE:
   2500  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2501  1.1  dholland 			nvap->na_mode = nfstov_mode(*tl);
   2502  1.1  dholland 			attrsum += NFSX_UNSIGNED;
   2503  1.1  dholland 			break;
   2504  1.1  dholland 		case NFSATTRBIT_OWNER:
   2505  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2506  1.1  dholland 			j = fxdr_unsigned(int, *tl);
   2507  1.1  dholland 			if (j < 0) {
   2508  1.1  dholland 				error = NFSERR_BADXDR;
   2509  1.1  dholland 				goto nfsmout;
   2510  1.1  dholland 			}
   2511  1.1  dholland 			if (j > NFSV4_SMALLSTR)
   2512  1.1  dholland 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
   2513  1.1  dholland 			else
   2514  1.1  dholland 				cp = namestr;
   2515  1.1  dholland 			error = nfsrv_mtostr(nd, cp, j);
   2516  1.1  dholland 			if (error) {
   2517  1.1  dholland 				if (j > NFSV4_SMALLSTR)
   2518  1.1  dholland 					free(cp, M_NFSSTRING);
   2519  1.1  dholland 				goto nfsmout;
   2520  1.1  dholland 			}
   2521  1.1  dholland 			if (!nd->nd_repstat) {
   2522  1.1  dholland 				nd->nd_repstat = nfsv4_strtouid(nd, cp, j, &uid,
   2523  1.1  dholland 				    p);
   2524  1.1  dholland 				if (!nd->nd_repstat)
   2525  1.1  dholland 					nvap->na_uid = uid;
   2526  1.1  dholland 			}
   2527  1.1  dholland 			if (j > NFSV4_SMALLSTR)
   2528  1.1  dholland 				free(cp, M_NFSSTRING);
   2529  1.1  dholland 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
   2530  1.1  dholland 			break;
   2531  1.1  dholland 		case NFSATTRBIT_OWNERGROUP:
   2532  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2533  1.1  dholland 			j = fxdr_unsigned(int, *tl);
   2534  1.1  dholland 			if (j < 0) {
   2535  1.1  dholland 				error = NFSERR_BADXDR;
   2536  1.1  dholland 				goto nfsmout;
   2537  1.1  dholland 			}
   2538  1.1  dholland 			if (j > NFSV4_SMALLSTR)
   2539  1.1  dholland 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
   2540  1.1  dholland 			else
   2541  1.1  dholland 				cp = namestr;
   2542  1.1  dholland 			error = nfsrv_mtostr(nd, cp, j);
   2543  1.1  dholland 			if (error) {
   2544  1.1  dholland 				if (j > NFSV4_SMALLSTR)
   2545  1.1  dholland 					free(cp, M_NFSSTRING);
   2546  1.1  dholland 				goto nfsmout;
   2547  1.1  dholland 			}
   2548  1.1  dholland 			if (!nd->nd_repstat) {
   2549  1.1  dholland 				nd->nd_repstat = nfsv4_strtogid(nd, cp, j, &gid,
   2550  1.1  dholland 				    p);
   2551  1.1  dholland 				if (!nd->nd_repstat)
   2552  1.1  dholland 					nvap->na_gid = gid;
   2553  1.1  dholland 			}
   2554  1.1  dholland 			if (j > NFSV4_SMALLSTR)
   2555  1.1  dholland 				free(cp, M_NFSSTRING);
   2556  1.1  dholland 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
   2557  1.1  dholland 			break;
   2558  1.1  dholland 		case NFSATTRBIT_SYSTEM:
   2559  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2560  1.1  dholland 			if (!nd->nd_repstat)
   2561  1.1  dholland 				nd->nd_repstat = NFSERR_ATTRNOTSUPP;
   2562  1.1  dholland 			attrsum += NFSX_UNSIGNED;
   2563  1.1  dholland 			break;
   2564  1.1  dholland 		case NFSATTRBIT_TIMEACCESSSET:
   2565  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2566  1.1  dholland 			attrsum += NFSX_UNSIGNED;
   2567  1.1  dholland 			if (fxdr_unsigned(int, *tl)==NFSV4SATTRTIME_TOCLIENT) {
   2568  1.1  dholland 			    NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
   2569  1.1  dholland 			    fxdr_nfsv4time(tl, &nvap->na_atime);
   2570  1.1  dholland 			    toclient = 1;
   2571  1.1  dholland 			    attrsum += NFSX_V4TIME;
   2572  1.1  dholland 			} else {
   2573  1.1  dholland 			    vfs_timestamp(&nvap->na_atime);
   2574  1.1  dholland 			    nvap->na_vaflags |= VA_UTIMES_NULL;
   2575  1.1  dholland 			}
   2576  1.1  dholland 			break;
   2577  1.1  dholland 		case NFSATTRBIT_TIMEBACKUP:
   2578  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
   2579  1.1  dholland 			if (!nd->nd_repstat)
   2580  1.1  dholland 				nd->nd_repstat = NFSERR_ATTRNOTSUPP;
   2581  1.1  dholland 			attrsum += NFSX_V4TIME;
   2582  1.1  dholland 			break;
   2583  1.1  dholland 		case NFSATTRBIT_TIMECREATE:
   2584  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
   2585  1.1  dholland 			if (!nd->nd_repstat)
   2586  1.1  dholland 				nd->nd_repstat = NFSERR_ATTRNOTSUPP;
   2587  1.1  dholland 			attrsum += NFSX_V4TIME;
   2588  1.1  dholland 			break;
   2589  1.1  dholland 		case NFSATTRBIT_TIMEMODIFYSET:
   2590  1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2591  1.1  dholland 			attrsum += NFSX_UNSIGNED;
   2592  1.1  dholland 			if (fxdr_unsigned(int, *tl)==NFSV4SATTRTIME_TOCLIENT) {
   2593  1.1  dholland 			    NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
   2594  1.1  dholland 			    fxdr_nfsv4time(tl, &nvap->na_mtime);
   2595  1.1  dholland 			    nvap->na_vaflags &= ~VA_UTIMES_NULL;
   2596  1.1  dholland 			    attrsum += NFSX_V4TIME;
   2597  1.1  dholland 			} else {
   2598  1.1  dholland 			    vfs_timestamp(&nvap->na_mtime);
   2599  1.1  dholland 			    if (!toclient)
   2600  1.1  dholland 				nvap->na_vaflags |= VA_UTIMES_NULL;
   2601  1.1  dholland 			}
   2602  1.1  dholland 			break;
   2603  1.1  dholland 		default:
   2604  1.1  dholland 			nd->nd_repstat = NFSERR_ATTRNOTSUPP;
   2605  1.1  dholland 			/*
   2606  1.1  dholland 			 * set bitpos so we drop out of the loop.
   2607  1.1  dholland 			 */
   2608  1.1  dholland 			bitpos = NFSATTRBIT_MAX;
   2609  1.1  dholland 			break;
   2610  1.2  pgoyette 		}
   2611  1.1  dholland 	}
   2612  1.1  dholland 
   2613  1.1  dholland 	/*
   2614  1.1  dholland 	 * some clients pad the attrlist, so we need to skip over the
   2615  1.1  dholland 	 * padding.
   2616  1.1  dholland 	 */
   2617  1.1  dholland 	if (attrsum > attrsize) {
   2618  1.1  dholland 		error = NFSERR_BADXDR;
   2619  1.1  dholland 	} else {
   2620  1.1  dholland 		attrsize = NFSM_RNDUP(attrsize);
   2621  1.1  dholland 		if (attrsum < attrsize)
   2622  1.1  dholland 			error = nfsm_advance(nd, attrsize - attrsum, -1);
   2623  1.1  dholland 	}
   2624  1.1  dholland nfsmout:
   2625  1.1  dholland 	NFSEXITCODE2(error, nd);
   2626  1.1  dholland 	return (error);
   2627  1.1  dholland }
   2628  1.1  dholland 
   2629  1.1  dholland /*
   2630  1.1  dholland  * Check/setup export credentials.
   2631  1.1  dholland  */
   2632  1.1  dholland int
   2633  1.1  dholland nfsd_excred(struct nfsrv_descript *nd, struct nfsexstuff *exp,
   2634  1.1  dholland     struct ucred *credanon)
   2635  1.1  dholland {
   2636  1.1  dholland 	int error = 0;
   2637  1.1  dholland 
   2638  1.1  dholland 	/*
   2639  1.1  dholland 	 * Check/setup credentials.
   2640  1.1  dholland 	 */
   2641  1.1  dholland 	if (nd->nd_flag & ND_GSS)
   2642  1.1  dholland 		exp->nes_exflag &= ~MNT_EXPORTANON;
   2643  1.1  dholland 
   2644  1.1  dholland 	/*
   2645  1.1  dholland 	 * Check to see if the operation is allowed for this security flavor.
   2646  1.1  dholland 	 * RFC2623 suggests that the NFSv3 Fsinfo RPC be allowed to
   2647  1.1  dholland 	 * AUTH_NONE or AUTH_SYS for file systems requiring RPCSEC_GSS.
   2648  1.1  dholland 	 * Also, allow Secinfo, so that it can acquire the correct flavor(s).
   2649  1.1  dholland 	 */
   2650  1.1  dholland 	if (nfsvno_testexp(nd, exp) &&
   2651  1.1  dholland 	    nd->nd_procnum != NFSV4OP_SECINFO &&
   2652  1.1  dholland 	    nd->nd_procnum != NFSPROC_FSINFO) {
   2653  1.1  dholland 		if (nd->nd_flag & ND_NFSV4)
   2654  1.1  dholland 			error = NFSERR_WRONGSEC;
   2655  1.1  dholland 		else
   2656  1.1  dholland 			error = (NFSERR_AUTHERR | AUTH_TOOWEAK);
   2657  1.1  dholland 		goto out;
   2658  1.1  dholland 	}
   2659  1.1  dholland 
   2660  1.1  dholland 	/*
   2661  1.1  dholland 	 * Check to see if the file system is exported V4 only.
   2662  1.1  dholland 	 */
   2663  1.1  dholland 	if (NFSVNO_EXV4ONLY(exp) && !(nd->nd_flag & ND_NFSV4)) {
   2664  1.1  dholland 		error = NFSERR_PROGNOTV4;
   2665  1.1  dholland 		goto out;
   2666  1.1  dholland 	}
   2667  1.1  dholland 
   2668  1.1  dholland 	/*
   2669  1.1  dholland 	 * Now, map the user credentials.
   2670  1.1  dholland 	 * (Note that ND_AUTHNONE will only be set for an NFSv3
   2671  1.1  dholland 	 *  Fsinfo RPC. If set for anything else, this code might need
   2672  1.1  dholland 	 *  to change.)
   2673  1.1  dholland 	 */
   2674  1.2  pgoyette 	if (NFSVNO_EXPORTED(exp)) {
   2675  1.2  pgoyette 		if (((nd->nd_flag & ND_GSS) == 0 && nd->nd_cred->cr_uid == 0) ||
   2676  1.2  pgoyette 		     NFSVNO_EXPORTANON(exp) ||
   2677  1.2  pgoyette 		     (nd->nd_flag & ND_AUTHNONE) != 0) {
   2678  1.2  pgoyette 			nd->nd_cred->cr_uid = credanon->cr_uid;
   2679  1.2  pgoyette 			nd->nd_cred->cr_gid = credanon->cr_gid;
   2680  1.2  pgoyette 			crsetgroups(nd->nd_cred, credanon->cr_ngroups,
   2681  1.2  pgoyette 			    credanon->cr_groups);
   2682  1.2  pgoyette 		} else if ((nd->nd_flag & ND_GSS) == 0) {
   2683  1.2  pgoyette 			/*
   2684  1.2  pgoyette 			 * If using AUTH_SYS, call nfsrv_getgrpscred() to see
   2685  1.2  pgoyette 			 * if there is a replacement credential with a group
   2686  1.2  pgoyette 			 * list set up by "nfsuserd -manage-gids".
   2687  1.2  pgoyette 			 * If there is no replacement, nfsrv_getgrpscred()
   2688  1.2  pgoyette 			 * simply returns its argument.
   2689  1.2  pgoyette 			 */
   2690  1.2  pgoyette 			nd->nd_cred = nfsrv_getgrpscred(nd->nd_cred);
   2691  1.2  pgoyette 		}
   2692  1.1  dholland 	}
   2693  1.1  dholland 
   2694  1.1  dholland out:
   2695  1.1  dholland 	NFSEXITCODE2(error, nd);
   2696  1.1  dholland 	return (error);
   2697  1.1  dholland }
   2698  1.1  dholland 
   2699  1.1  dholland /*
   2700  1.1  dholland  * Check exports.
   2701  1.1  dholland  */
   2702  1.1  dholland int
   2703  1.1  dholland nfsvno_checkexp(struct mount *mp, struct sockaddr *nam, struct nfsexstuff *exp,
   2704  1.1  dholland     struct ucred **credp)
   2705  1.1  dholland {
   2706  1.1  dholland 	int i, error, *secflavors;
   2707  1.1  dholland 
   2708  1.1  dholland 	error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp,
   2709  1.1  dholland 	    &exp->nes_numsecflavor, &secflavors);
   2710  1.1  dholland 	if (error) {
   2711  1.1  dholland 		if (nfs_rootfhset) {
   2712  1.1  dholland 			exp->nes_exflag = 0;
   2713  1.1  dholland 			exp->nes_numsecflavor = 0;
   2714  1.1  dholland 			error = 0;
   2715  1.1  dholland 		}
   2716  1.1  dholland 	} else {
   2717  1.1  dholland 		/* Copy the security flavors. */
   2718  1.1  dholland 		for (i = 0; i < exp->nes_numsecflavor; i++)
   2719  1.1  dholland 			exp->nes_secflavors[i] = secflavors[i];
   2720  1.1  dholland 	}
   2721  1.1  dholland 	NFSEXITCODE(error);
   2722  1.1  dholland 	return (error);
   2723  1.1  dholland }
   2724  1.1  dholland 
   2725  1.1  dholland /*
   2726  1.1  dholland  * Get a vnode for a file handle and export stuff.
   2727  1.1  dholland  */
   2728  1.1  dholland int
   2729  1.1  dholland nfsvno_fhtovp(struct mount *mp, fhandle_t *fhp, struct sockaddr *nam,
   2730  1.1  dholland     int lktype, struct vnode **vpp, struct nfsexstuff *exp,
   2731  1.1  dholland     struct ucred **credp)
   2732  1.1  dholland {
   2733  1.1  dholland 	int i, error, *secflavors;
   2734  1.1  dholland 
   2735  1.1  dholland 	*credp = NULL;
   2736  1.1  dholland 	exp->nes_numsecflavor = 0;
   2737  1.1  dholland 	error = VFS_FHTOVP(mp, &fhp->fh_fid, lktype, vpp);
   2738  1.1  dholland 	if (error != 0)
   2739  1.1  dholland 		/* Make sure the server replies ESTALE to the client. */
   2740  1.1  dholland 		error = ESTALE;
   2741  1.1  dholland 	if (nam && !error) {
   2742  1.1  dholland 		error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp,
   2743  1.1  dholland 		    &exp->nes_numsecflavor, &secflavors);
   2744  1.1  dholland 		if (error) {
   2745  1.1  dholland 			if (nfs_rootfhset) {
   2746  1.1  dholland 				exp->nes_exflag = 0;
   2747  1.1  dholland 				exp->nes_numsecflavor = 0;
   2748  1.1  dholland 				error = 0;
   2749  1.1  dholland 			} else {
   2750  1.1  dholland 				vput(*vpp);
   2751  1.1  dholland 			}
   2752  1.1  dholland 		} else {
   2753  1.1  dholland 			/* Copy the security flavors. */
   2754  1.1  dholland 			for (i = 0; i < exp->nes_numsecflavor; i++)
   2755  1.1  dholland 				exp->nes_secflavors[i] = secflavors[i];
   2756  1.1  dholland 		}
   2757  1.1  dholland 	}
   2758  1.1  dholland 	NFSEXITCODE(error);
   2759  1.1  dholland 	return (error);
   2760  1.1  dholland }
   2761  1.1  dholland 
   2762  1.1  dholland /*
   2763  1.1  dholland  * nfsd_fhtovp() - convert a fh to a vnode ptr
   2764  1.1  dholland  * 	- look up fsid in mount list (if not found ret error)
   2765  1.1  dholland  *	- get vp and export rights by calling nfsvno_fhtovp()
   2766  1.1  dholland  *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
   2767  1.1  dholland  *	  for AUTH_SYS
   2768  1.1  dholland  *	- if mpp != NULL, return the mount point so that it can
   2769  1.1  dholland  *	  be used for vn_finished_write() by the caller
   2770  1.1  dholland  */
   2771  1.1  dholland void
   2772  1.1  dholland nfsd_fhtovp(struct nfsrv_descript *nd, struct nfsrvfh *nfp, int lktype,
   2773  1.1  dholland     struct vnode **vpp, struct nfsexstuff *exp,
   2774  1.1  dholland     struct mount **mpp, int startwrite, struct thread *p)
   2775  1.1  dholland {
   2776  1.1  dholland 	struct mount *mp;
   2777  1.1  dholland 	struct ucred *credanon;
   2778  1.1  dholland 	fhandle_t *fhp;
   2779  1.1  dholland 
   2780  1.1  dholland 	fhp = (fhandle_t *)nfp->nfsrvfh_data;
   2781  1.1  dholland 	/*
   2782  1.1  dholland 	 * Check for the special case of the nfsv4root_fh.
   2783  1.1  dholland 	 */
   2784  1.1  dholland 	mp = vfs_busyfs(&fhp->fh_fsid);
   2785  1.1  dholland 	if (mpp != NULL)
   2786  1.1  dholland 		*mpp = mp;
   2787  1.1  dholland 	if (mp == NULL) {
   2788  1.1  dholland 		*vpp = NULL;
   2789  1.1  dholland 		nd->nd_repstat = ESTALE;
   2790  1.1  dholland 		goto out;
   2791  1.1  dholland 	}
   2792  1.1  dholland 
   2793  1.1  dholland 	if (startwrite) {
   2794  1.1  dholland 		vn_start_write(NULL, mpp, V_WAIT);
   2795  1.1  dholland 		if (lktype == LK_SHARED && !(MNT_SHARED_WRITES(mp)))
   2796  1.1  dholland 			lktype = LK_EXCLUSIVE;
   2797  1.1  dholland 	}
   2798  1.1  dholland 	nd->nd_repstat = nfsvno_fhtovp(mp, fhp, nd->nd_nam, lktype, vpp, exp,
   2799  1.1  dholland 	    &credanon);
   2800  1.1  dholland 	vfs_unbusy(mp);
   2801  1.1  dholland 
   2802  1.1  dholland 	/*
   2803  1.1  dholland 	 * For NFSv4 without a pseudo root fs, unexported file handles
   2804  1.1  dholland 	 * can be returned, so that Lookup works everywhere.
   2805  1.1  dholland 	 */
   2806  1.1  dholland 	if (!nd->nd_repstat && exp->nes_exflag == 0 &&
   2807  1.1  dholland 	    !(nd->nd_flag & ND_NFSV4)) {
   2808  1.1  dholland 		vput(*vpp);
   2809  1.1  dholland 		nd->nd_repstat = EACCES;
   2810  1.1  dholland 	}
   2811  1.1  dholland 
   2812  1.1  dholland 	/*
   2813  1.1  dholland 	 * Personally, I've never seen any point in requiring a
   2814  1.1  dholland 	 * reserved port#, since only in the rare case where the
   2815  1.2  pgoyette 	 * clients are all boxes with secure system privileges,
   2816  1.1  dholland 	 * does it provide any enhanced security, but... some people
   2817  1.1  dholland 	 * believe it to be useful and keep putting this code back in.
   2818  1.1  dholland 	 * (There is also some "security checker" out there that
   2819  1.1  dholland 	 *  complains if the nfs server doesn't enforce this.)
   2820  1.1  dholland 	 * However, note the following:
   2821  1.1  dholland 	 * RFC3530 (NFSv4) specifies that a reserved port# not be
   2822  1.1  dholland 	 *	required.
   2823  1.1  dholland 	 * RFC2623 recommends that, if a reserved port# is checked for,
   2824  1.1  dholland 	 *	that there be a way to turn that off--> ifdef'd.
   2825  1.1  dholland 	 */
   2826  1.1  dholland #ifdef NFS_REQRSVPORT
   2827  1.1  dholland 	if (!nd->nd_repstat) {
   2828  1.1  dholland 		struct sockaddr_in *saddr;
   2829  1.1  dholland 		struct sockaddr_in6 *saddr6;
   2830  1.1  dholland 
   2831  1.1  dholland 		saddr = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *);
   2832  1.1  dholland 		saddr6 = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in6 *);
   2833  1.1  dholland 		if (!(nd->nd_flag & ND_NFSV4) &&
   2834  1.1  dholland 		    ((saddr->sin_family == AF_INET &&
   2835  1.1  dholland 		      ntohs(saddr->sin_port) >= IPPORT_RESERVED) ||
   2836  1.1  dholland 		     (saddr6->sin6_family == AF_INET6 &&
   2837  1.1  dholland 		      ntohs(saddr6->sin6_port) >= IPPORT_RESERVED))) {
   2838  1.1  dholland 			vput(*vpp);
   2839  1.1  dholland 			nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
   2840  1.1  dholland 		}
   2841  1.1  dholland 	}
   2842  1.1  dholland #endif	/* NFS_REQRSVPORT */
   2843  1.1  dholland 
   2844  1.1  dholland 	/*
   2845  1.1  dholland 	 * Check/setup credentials.
   2846  1.1  dholland 	 */
   2847  1.1  dholland 	if (!nd->nd_repstat) {
   2848  1.1  dholland 		nd->nd_saveduid = nd->nd_cred->cr_uid;
   2849  1.1  dholland 		nd->nd_repstat = nfsd_excred(nd, exp, credanon);
   2850  1.1  dholland 		if (nd->nd_repstat)
   2851  1.1  dholland 			vput(*vpp);
   2852  1.1  dholland 	}
   2853  1.1  dholland 	if (credanon != NULL)
   2854  1.1  dholland 		crfree(credanon);
   2855  1.1  dholland 	if (nd->nd_repstat) {
   2856  1.1  dholland 		if (startwrite)
   2857  1.1  dholland 			vn_finished_write(mp);
   2858  1.1  dholland 		*vpp = NULL;
   2859  1.1  dholland 		if (mpp != NULL)
   2860  1.1  dholland 			*mpp = NULL;
   2861  1.1  dholland 	}
   2862  1.1  dholland 
   2863  1.1  dholland out:
   2864  1.1  dholland 	NFSEXITCODE2(0, nd);
   2865  1.1  dholland }
   2866  1.1  dholland 
   2867  1.1  dholland /*
   2868  1.1  dholland  * glue for fp.
   2869  1.1  dholland  */
   2870  1.1  dholland static int
   2871  1.1  dholland fp_getfvp(struct thread *p, int fd, struct file **fpp, struct vnode **vpp)
   2872  1.1  dholland {
   2873  1.1  dholland 	struct filedesc *fdp;
   2874  1.1  dholland 	struct file *fp;
   2875  1.1  dholland 	int error = 0;
   2876  1.1  dholland 
   2877  1.1  dholland 	fdp = p->td_proc->p_fd;
   2878  1.1  dholland 	if (fd < 0 || fd >= fdp->fd_nfiles ||
   2879  1.1  dholland 	    (fp = fdp->fd_ofiles[fd].fde_file) == NULL) {
   2880  1.1  dholland 		error = EBADF;
   2881  1.1  dholland 		goto out;
   2882  1.1  dholland 	}
   2883  1.1  dholland 	*fpp = fp;
   2884  1.1  dholland 
   2885  1.1  dholland out:
   2886  1.1  dholland 	NFSEXITCODE(error);
   2887  1.1  dholland 	return (error);
   2888  1.1  dholland }
   2889  1.1  dholland 
   2890  1.1  dholland /*
   2891  1.1  dholland  * Called from nfssvc() to update the exports list. Just call
   2892  1.1  dholland  * vfs_export(). This has to be done, since the v4 root fake fs isn't
   2893  1.1  dholland  * in the mount list.
   2894  1.1  dholland  */
   2895  1.1  dholland int
   2896  1.1  dholland nfsrv_v4rootexport(void *argp, struct ucred *cred, struct thread *p)
   2897  1.1  dholland {
   2898  1.1  dholland 	struct nfsex_args *nfsexargp = (struct nfsex_args *)argp;
   2899  1.1  dholland 	int error = 0;
   2900  1.1  dholland 	struct nameidata nd;
   2901  1.1  dholland 	fhandle_t fh;
   2902  1.1  dholland 
   2903  1.1  dholland 	error = vfs_export(&nfsv4root_mnt, &nfsexargp->export);
   2904  1.1  dholland 	if ((nfsexargp->export.ex_flags & MNT_DELEXPORT) != 0)
   2905  1.1  dholland 		nfs_rootfhset = 0;
   2906  1.1  dholland 	else if (error == 0) {
   2907  1.1  dholland 		if (nfsexargp->fspec == NULL) {
   2908  1.1  dholland 			error = EPERM;
   2909  1.1  dholland 			goto out;
   2910  1.1  dholland 		}
   2911  1.1  dholland 		/*
   2912  1.1  dholland 		 * If fspec != NULL, this is the v4root path.
   2913  1.1  dholland 		 */
   2914  1.1  dholland 		NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
   2915  1.1  dholland 		    nfsexargp->fspec, p);
   2916  1.1  dholland 		if ((error = namei(&nd)) != 0)
   2917  1.1  dholland 			goto out;
   2918  1.1  dholland 		error = nfsvno_getfh(nd.ni_vp, &fh, p);
   2919  1.1  dholland 		vrele(nd.ni_vp);
   2920  1.1  dholland 		if (!error) {
   2921  1.1  dholland 			nfs_rootfh.nfsrvfh_len = NFSX_MYFH;
   2922  1.1  dholland 			NFSBCOPY((caddr_t)&fh,
   2923  1.1  dholland 			    nfs_rootfh.nfsrvfh_data,
   2924  1.1  dholland 			    sizeof (fhandle_t));
   2925  1.1  dholland 			nfs_rootfhset = 1;
   2926  1.1  dholland 		}
   2927  1.1  dholland 	}
   2928  1.1  dholland 
   2929  1.1  dholland out:
   2930  1.1  dholland 	NFSEXITCODE(error);
   2931  1.1  dholland 	return (error);
   2932  1.1  dholland }
   2933  1.1  dholland 
   2934  1.1  dholland /*
   2935  1.1  dholland  * This function needs to test to see if the system is near its limit
   2936  1.1  dholland  * for memory allocation via malloc() or mget() and return True iff
   2937  1.1  dholland  * either of these resources are near their limit.
   2938  1.1  dholland  * XXX (For now, this is just a stub.)
   2939  1.1  dholland  */
   2940  1.1  dholland int nfsrv_testmalloclimit = 0;
   2941  1.1  dholland int
   2942  1.1  dholland nfsrv_mallocmget_limit(void)
   2943  1.1  dholland {
   2944  1.1  dholland 	static int printmesg = 0;
   2945  1.1  dholland 	static int testval = 1;
   2946  1.1  dholland 
   2947  1.1  dholland 	if (nfsrv_testmalloclimit && (testval++ % 1000) == 0) {
   2948  1.1  dholland 		if ((printmesg++ % 100) == 0)
   2949  1.1  dholland 			printf("nfsd: malloc/mget near limit\n");
   2950  1.1  dholland 		return (1);
   2951  1.1  dholland 	}
   2952  1.1  dholland 	return (0);
   2953  1.1  dholland }
   2954  1.1  dholland 
   2955  1.1  dholland /*
   2956  1.1  dholland  * BSD specific initialization of a mount point.
   2957  1.1  dholland  */
   2958  1.1  dholland void
   2959  1.1  dholland nfsd_mntinit(void)
   2960  1.1  dholland {
   2961  1.1  dholland 	static int inited = 0;
   2962  1.1  dholland 
   2963  1.1  dholland 	if (inited)
   2964  1.1  dholland 		return;
   2965  1.1  dholland 	inited = 1;
   2966  1.1  dholland 	nfsv4root_mnt.mnt_flag = (MNT_RDONLY | MNT_EXPORTED);
   2967  1.1  dholland 	TAILQ_INIT(&nfsv4root_mnt.mnt_nvnodelist);
   2968  1.1  dholland 	TAILQ_INIT(&nfsv4root_mnt.mnt_activevnodelist);
   2969  1.1  dholland 	nfsv4root_mnt.mnt_export = NULL;
   2970  1.1  dholland 	TAILQ_INIT(&nfsv4root_opt);
   2971  1.1  dholland 	TAILQ_INIT(&nfsv4root_newopt);
   2972  1.1  dholland 	nfsv4root_mnt.mnt_opt = &nfsv4root_opt;
   2973  1.1  dholland 	nfsv4root_mnt.mnt_optnew = &nfsv4root_newopt;
   2974  1.1  dholland 	nfsv4root_mnt.mnt_nvnodelistsize = 0;
   2975  1.1  dholland 	nfsv4root_mnt.mnt_activevnodelistsize = 0;
   2976  1.1  dholland }
   2977  1.1  dholland 
   2978  1.1  dholland /*
   2979  1.1  dholland  * Get a vnode for a file handle, without checking exports, etc.
   2980  1.1  dholland  */
   2981  1.1  dholland struct vnode *
   2982  1.1  dholland nfsvno_getvp(fhandle_t *fhp)
   2983  1.1  dholland {
   2984  1.1  dholland 	struct mount *mp;
   2985  1.1  dholland 	struct vnode *vp;
   2986  1.1  dholland 	int error;
   2987  1.1  dholland 
   2988  1.1  dholland 	mp = vfs_busyfs(&fhp->fh_fsid);
   2989  1.1  dholland 	if (mp == NULL)
   2990  1.1  dholland 		return (NULL);
   2991  1.1  dholland 	error = VFS_FHTOVP(mp, &fhp->fh_fid, LK_EXCLUSIVE, &vp);
   2992  1.1  dholland 	vfs_unbusy(mp);
   2993  1.1  dholland 	if (error)
   2994  1.1  dholland 		return (NULL);
   2995  1.1  dholland 	return (vp);
   2996  1.1  dholland }
   2997  1.1  dholland 
   2998  1.1  dholland /*
   2999  1.1  dholland  * Do a local VOP_ADVLOCK().
   3000  1.1  dholland  */
   3001  1.1  dholland int
   3002  1.1  dholland nfsvno_advlock(struct vnode *vp, int ftype, u_int64_t first,
   3003  1.1  dholland     u_int64_t end, struct thread *td)
   3004  1.1  dholland {
   3005  1.1  dholland 	int error = 0;
   3006  1.1  dholland 	struct flock fl;
   3007  1.1  dholland 	u_int64_t tlen;
   3008  1.1  dholland 
   3009  1.1  dholland 	if (nfsrv_dolocallocks == 0)
   3010  1.1  dholland 		goto out;
   3011  1.2  pgoyette 	ASSERT_VOP_UNLOCKED(vp, "nfsvno_advlock: vp locked");
   3012  1.1  dholland 
   3013  1.1  dholland 	fl.l_whence = SEEK_SET;
   3014  1.1  dholland 	fl.l_type = ftype;
   3015  1.1  dholland 	fl.l_start = (off_t)first;
   3016  1.1  dholland 	if (end == NFS64BITSSET) {
   3017  1.1  dholland 		fl.l_len = 0;
   3018  1.1  dholland 	} else {
   3019  1.1  dholland 		tlen = end - first;
   3020  1.1  dholland 		fl.l_len = (off_t)tlen;
   3021  1.1  dholland 	}
   3022  1.1  dholland 	/*
   3023  1.1  dholland 	 * For FreeBSD8, the l_pid and l_sysid must be set to the same
   3024  1.1  dholland 	 * values for all calls, so that all locks will be held by the
   3025  1.1  dholland 	 * nfsd server. (The nfsd server handles conflicts between the
   3026  1.1  dholland 	 * various clients.)
   3027  1.1  dholland 	 * Since an NFSv4 lockowner is a ClientID plus an array of up to 1024
   3028  1.1  dholland 	 * bytes, so it can't be put in l_sysid.
   3029  1.1  dholland 	 */
   3030  1.1  dholland 	if (nfsv4_sysid == 0)
   3031  1.1  dholland 		nfsv4_sysid = nlm_acquire_next_sysid();
   3032  1.1  dholland 	fl.l_pid = (pid_t)0;
   3033  1.1  dholland 	fl.l_sysid = (int)nfsv4_sysid;
   3034  1.1  dholland 
   3035  1.1  dholland 	if (ftype == F_UNLCK)
   3036  1.1  dholland 		error = VOP_ADVLOCK(vp, (caddr_t)td->td_proc, F_UNLCK, &fl,
   3037  1.1  dholland 		    (F_POSIX | F_REMOTE));
   3038  1.1  dholland 	else
   3039  1.1  dholland 		error = VOP_ADVLOCK(vp, (caddr_t)td->td_proc, F_SETLK, &fl,
   3040  1.1  dholland 		    (F_POSIX | F_REMOTE));
   3041  1.1  dholland 
   3042  1.1  dholland out:
   3043  1.1  dholland 	NFSEXITCODE(error);
   3044  1.1  dholland 	return (error);
   3045  1.1  dholland }
   3046  1.1  dholland 
   3047  1.1  dholland /*
   3048  1.1  dholland  * Check the nfsv4 root exports.
   3049  1.1  dholland  */
   3050  1.1  dholland int
   3051  1.1  dholland nfsvno_v4rootexport(struct nfsrv_descript *nd)
   3052  1.1  dholland {
   3053  1.1  dholland 	struct ucred *credanon;
   3054  1.1  dholland 	int exflags, error = 0, numsecflavor, *secflavors, i;
   3055  1.1  dholland 
   3056  1.1  dholland 	error = vfs_stdcheckexp(&nfsv4root_mnt, nd->nd_nam, &exflags,
   3057  1.1  dholland 	    &credanon, &numsecflavor, &secflavors);
   3058  1.1  dholland 	if (error) {
   3059  1.1  dholland 		error = NFSERR_PROGUNAVAIL;
   3060  1.1  dholland 		goto out;
   3061  1.1  dholland 	}
   3062  1.1  dholland 	if (credanon != NULL)
   3063  1.1  dholland 		crfree(credanon);
   3064  1.1  dholland 	for (i = 0; i < numsecflavor; i++) {
   3065  1.1  dholland 		if (secflavors[i] == AUTH_SYS)
   3066  1.1  dholland 			nd->nd_flag |= ND_EXAUTHSYS;
   3067  1.1  dholland 		else if (secflavors[i] == RPCSEC_GSS_KRB5)
   3068  1.1  dholland 			nd->nd_flag |= ND_EXGSS;
   3069  1.1  dholland 		else if (secflavors[i] == RPCSEC_GSS_KRB5I)
   3070  1.1  dholland 			nd->nd_flag |= ND_EXGSSINTEGRITY;
   3071  1.1  dholland 		else if (secflavors[i] == RPCSEC_GSS_KRB5P)
   3072  1.1  dholland 			nd->nd_flag |= ND_EXGSSPRIVACY;
   3073  1.1  dholland 	}
   3074  1.1  dholland 
   3075  1.1  dholland out:
   3076  1.1  dholland 	NFSEXITCODE(error);
   3077  1.1  dholland 	return (error);
   3078  1.1  dholland }
   3079  1.1  dholland 
   3080  1.1  dholland /*
   3081  1.2  pgoyette  * Nfs server pseudo system call for the nfsd's
   3082  1.1  dholland  */
   3083  1.1  dholland /*
   3084  1.1  dholland  * MPSAFE
   3085  1.1  dholland  */
   3086  1.1  dholland static int
   3087  1.1  dholland nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap)
   3088  1.1  dholland {
   3089  1.1  dholland 	struct file *fp;
   3090  1.1  dholland 	struct nfsd_addsock_args sockarg;
   3091  1.1  dholland 	struct nfsd_nfsd_args nfsdarg;
   3092  1.1  dholland 	cap_rights_t rights;
   3093  1.1  dholland 	int error;
   3094  1.1  dholland 
   3095  1.1  dholland 	if (uap->flag & NFSSVC_NFSDADDSOCK) {
   3096  1.1  dholland 		error = copyin(uap->argp, (caddr_t)&sockarg, sizeof (sockarg));
   3097  1.1  dholland 		if (error)
   3098  1.1  dholland 			goto out;
   3099  1.1  dholland 		/*
   3100  1.1  dholland 		 * Since we don't know what rights might be required,
   3101  1.1  dholland 		 * pretend that we need them all. It is better to be too
   3102  1.1  dholland 		 * careful than too reckless.
   3103  1.1  dholland 		 */
   3104  1.1  dholland 		error = fget(td, sockarg.sock,
   3105  1.1  dholland 		    cap_rights_init(&rights, CAP_SOCK_SERVER), &fp);
   3106  1.1  dholland 		if (error != 0)
   3107  1.1  dholland 			goto out;
   3108  1.1  dholland 		if (fp->f_type != DTYPE_SOCKET) {
   3109  1.1  dholland 			fdrop(fp, td);
   3110  1.1  dholland 			error = EPERM;
   3111  1.1  dholland 			goto out;
   3112  1.1  dholland 		}
   3113  1.1  dholland 		error = nfsrvd_addsock(fp);
   3114  1.1  dholland 		fdrop(fp, td);
   3115  1.1  dholland 	} else if (uap->flag & NFSSVC_NFSDNFSD) {
   3116  1.1  dholland 		if (uap->argp == NULL) {
   3117  1.1  dholland 			error = EINVAL;
   3118  1.1  dholland 			goto out;
   3119  1.1  dholland 		}
   3120  1.1  dholland 		error = copyin(uap->argp, (caddr_t)&nfsdarg,
   3121  1.1  dholland 		    sizeof (nfsdarg));
   3122  1.1  dholland 		if (error)
   3123  1.1  dholland 			goto out;
   3124  1.1  dholland 		error = nfsrvd_nfsd(td, &nfsdarg);
   3125  1.1  dholland 	} else {
   3126  1.1  dholland 		error = nfssvc_srvcall(td, uap, td->td_ucred);
   3127  1.1  dholland 	}
   3128  1.1  dholland 
   3129  1.1  dholland out:
   3130  1.1  dholland 	NFSEXITCODE(error);
   3131  1.1  dholland 	return (error);
   3132  1.1  dholland }
   3133  1.1  dholland 
   3134  1.1  dholland static int
   3135  1.1  dholland nfssvc_srvcall(struct thread *p, struct nfssvc_args *uap, struct ucred *cred)
   3136  1.1  dholland {
   3137  1.1  dholland 	struct nfsex_args export;
   3138  1.1  dholland 	struct file *fp = NULL;
   3139  1.1  dholland 	int stablefd, len;
   3140  1.1  dholland 	struct nfsd_clid adminrevoke;
   3141  1.1  dholland 	struct nfsd_dumplist dumplist;
   3142  1.1  dholland 	struct nfsd_dumpclients *dumpclients;
   3143  1.1  dholland 	struct nfsd_dumplocklist dumplocklist;
   3144  1.1  dholland 	struct nfsd_dumplocks *dumplocks;
   3145  1.1  dholland 	struct nameidata nd;
   3146  1.1  dholland 	vnode_t vp;
   3147  1.1  dholland 	int error = EINVAL, igotlock;
   3148  1.1  dholland 	struct proc *procp;
   3149  1.1  dholland 	static int suspend_nfsd = 0;
   3150  1.1  dholland 
   3151  1.1  dholland 	if (uap->flag & NFSSVC_PUBLICFH) {
   3152  1.1  dholland 		NFSBZERO((caddr_t)&nfs_pubfh.nfsrvfh_data,
   3153  1.1  dholland 		    sizeof (fhandle_t));
   3154  1.1  dholland 		error = copyin(uap->argp,
   3155  1.1  dholland 		    &nfs_pubfh.nfsrvfh_data, sizeof (fhandle_t));
   3156  1.1  dholland 		if (!error)
   3157  1.1  dholland 			nfs_pubfhset = 1;
   3158  1.1  dholland 	} else if (uap->flag & NFSSVC_V4ROOTEXPORT) {
   3159  1.1  dholland 		error = copyin(uap->argp,(caddr_t)&export,
   3160  1.1  dholland 		    sizeof (struct nfsex_args));
   3161  1.1  dholland 		if (!error)
   3162  1.1  dholland 			error = nfsrv_v4rootexport(&export, cred, p);
   3163  1.1  dholland 	} else if (uap->flag & NFSSVC_NOPUBLICFH) {
   3164  1.1  dholland 		nfs_pubfhset = 0;
   3165  1.1  dholland 		error = 0;
   3166  1.1  dholland 	} else if (uap->flag & NFSSVC_STABLERESTART) {
   3167  1.1  dholland 		error = copyin(uap->argp, (caddr_t)&stablefd,
   3168  1.1  dholland 		    sizeof (int));
   3169  1.1  dholland 		if (!error)
   3170  1.1  dholland 			error = fp_getfvp(p, stablefd, &fp, &vp);
   3171  1.1  dholland 		if (!error && (NFSFPFLAG(fp) & (FREAD | FWRITE)) != (FREAD | FWRITE))
   3172  1.1  dholland 			error = EBADF;
   3173  1.1  dholland 		if (!error && newnfs_numnfsd != 0)
   3174  1.1  dholland 			error = EPERM;
   3175  1.1  dholland 		if (!error) {
   3176  1.1  dholland 			nfsrv_stablefirst.nsf_fp = fp;
   3177  1.1  dholland 			nfsrv_setupstable(p);
   3178  1.1  dholland 		}
   3179  1.1  dholland 	} else if (uap->flag & NFSSVC_ADMINREVOKE) {
   3180  1.1  dholland 		error = copyin(uap->argp, (caddr_t)&adminrevoke,
   3181  1.1  dholland 		    sizeof (struct nfsd_clid));
   3182  1.1  dholland 		if (!error)
   3183  1.1  dholland 			error = nfsrv_adminrevoke(&adminrevoke, p);
   3184  1.1  dholland 	} else if (uap->flag & NFSSVC_DUMPCLIENTS) {
   3185  1.1  dholland 		error = copyin(uap->argp, (caddr_t)&dumplist,
   3186  1.1  dholland 		    sizeof (struct nfsd_dumplist));
   3187  1.1  dholland 		if (!error && (dumplist.ndl_size < 1 ||
   3188  1.1  dholland 			dumplist.ndl_size > NFSRV_MAXDUMPLIST))
   3189  1.1  dholland 			error = EPERM;
   3190  1.1  dholland 		if (!error) {
   3191  1.1  dholland 		    len = sizeof (struct nfsd_dumpclients) * dumplist.ndl_size;
   3192  1.1  dholland 		    dumpclients = (struct nfsd_dumpclients *)malloc(len,
   3193  1.1  dholland 			M_TEMP, M_WAITOK);
   3194  1.1  dholland 		    nfsrv_dumpclients(dumpclients, dumplist.ndl_size);
   3195  1.1  dholland 		    error = copyout(dumpclients,
   3196  1.1  dholland 			CAST_USER_ADDR_T(dumplist.ndl_list), len);
   3197  1.1  dholland 		    free((caddr_t)dumpclients, M_TEMP);
   3198  1.1  dholland 		}
   3199  1.1  dholland 	} else if (uap->flag & NFSSVC_DUMPLOCKS) {
   3200  1.1  dholland 		error = copyin(uap->argp, (caddr_t)&dumplocklist,
   3201  1.1  dholland 		    sizeof (struct nfsd_dumplocklist));
   3202  1.1  dholland 		if (!error && (dumplocklist.ndllck_size < 1 ||
   3203  1.1  dholland 			dumplocklist.ndllck_size > NFSRV_MAXDUMPLIST))
   3204  1.1  dholland 			error = EPERM;
   3205  1.1  dholland 		if (!error)
   3206  1.1  dholland 			error = nfsrv_lookupfilename(&nd,
   3207  1.1  dholland 				dumplocklist.ndllck_fname, p);
   3208  1.1  dholland 		if (!error) {
   3209  1.1  dholland 			len = sizeof (struct nfsd_dumplocks) *
   3210  1.1  dholland 				dumplocklist.ndllck_size;
   3211  1.1  dholland 			dumplocks = (struct nfsd_dumplocks *)malloc(len,
   3212  1.1  dholland 				M_TEMP, M_WAITOK);
   3213  1.1  dholland 			nfsrv_dumplocks(nd.ni_vp, dumplocks,
   3214  1.1  dholland 			    dumplocklist.ndllck_size, p);
   3215  1.1  dholland 			vput(nd.ni_vp);
   3216  1.1  dholland 			error = copyout(dumplocks,
   3217  1.1  dholland 			    CAST_USER_ADDR_T(dumplocklist.ndllck_list), len);
   3218  1.1  dholland 			free((caddr_t)dumplocks, M_TEMP);
   3219  1.1  dholland 		}
   3220  1.1  dholland 	} else if (uap->flag & NFSSVC_BACKUPSTABLE) {
   3221  1.1  dholland 		procp = p->td_proc;
   3222  1.1  dholland 		PROC_LOCK(procp);
   3223  1.1  dholland 		nfsd_master_pid = procp->p_pid;
   3224  1.1  dholland 		bcopy(procp->p_comm, nfsd_master_comm, MAXCOMLEN + 1);
   3225  1.1  dholland 		nfsd_master_start = procp->p_stats->p_start;
   3226  1.1  dholland 		nfsd_master_proc = procp;
   3227  1.1  dholland 		PROC_UNLOCK(procp);
   3228  1.1  dholland 	} else if ((uap->flag & NFSSVC_SUSPENDNFSD) != 0) {
   3229  1.1  dholland 		NFSLOCKV4ROOTMUTEX();
   3230  1.1  dholland 		if (suspend_nfsd == 0) {
   3231  1.1  dholland 			/* Lock out all nfsd threads */
   3232  1.1  dholland 			do {
   3233  1.1  dholland 				igotlock = nfsv4_lock(&nfsd_suspend_lock, 1,
   3234  1.1  dholland 				    NULL, NFSV4ROOTLOCKMUTEXPTR, NULL);
   3235  1.1  dholland 			} while (igotlock == 0 && suspend_nfsd == 0);
   3236  1.1  dholland 			suspend_nfsd = 1;
   3237  1.1  dholland 		}
   3238  1.1  dholland 		NFSUNLOCKV4ROOTMUTEX();
   3239  1.1  dholland 		error = 0;
   3240  1.1  dholland 	} else if ((uap->flag & NFSSVC_RESUMENFSD) != 0) {
   3241  1.1  dholland 		NFSLOCKV4ROOTMUTEX();
   3242  1.1  dholland 		if (suspend_nfsd != 0) {
   3243  1.1  dholland 			nfsv4_unlock(&nfsd_suspend_lock, 0);
   3244  1.1  dholland 			suspend_nfsd = 0;
   3245  1.1  dholland 		}
   3246  1.1  dholland 		NFSUNLOCKV4ROOTMUTEX();
   3247  1.1  dholland 		error = 0;
   3248  1.1  dholland 	}
   3249  1.1  dholland 
   3250  1.1  dholland 	NFSEXITCODE(error);
   3251  1.1  dholland 	return (error);
   3252  1.1  dholland }
   3253  1.1  dholland 
   3254  1.1  dholland /*
   3255  1.1  dholland  * Check exports.
   3256  1.1  dholland  * Returns 0 if ok, 1 otherwise.
   3257  1.1  dholland  */
   3258  1.1  dholland int
   3259  1.1  dholland nfsvno_testexp(struct nfsrv_descript *nd, struct nfsexstuff *exp)
   3260  1.1  dholland {
   3261  1.1  dholland 	int i;
   3262  1.1  dholland 
   3263  1.1  dholland 	/*
   3264  1.1  dholland 	 * This seems odd, but allow the case where the security flavor
   3265  1.1  dholland 	 * list is empty. This happens when NFSv4 is traversing non-exported
   3266  1.1  dholland 	 * file systems. Exported file systems should always have a non-empty
   3267  1.1  dholland 	 * security flavor list.
   3268  1.1  dholland 	 */
   3269  1.1  dholland 	if (exp->nes_numsecflavor == 0)
   3270  1.1  dholland 		return (0);
   3271  1.1  dholland 
   3272  1.1  dholland 	for (i = 0; i < exp->nes_numsecflavor; i++) {
   3273  1.1  dholland 		/*
   3274  1.1  dholland 		 * The tests for privacy and integrity must be first,
   3275  1.1  dholland 		 * since ND_GSS is set for everything but AUTH_SYS.
   3276  1.1  dholland 		 */
   3277  1.1  dholland 		if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5P &&
   3278  1.1  dholland 		    (nd->nd_flag & ND_GSSPRIVACY))
   3279  1.1  dholland 			return (0);
   3280  1.1  dholland 		if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5I &&
   3281  1.1  dholland 		    (nd->nd_flag & ND_GSSINTEGRITY))
   3282  1.1  dholland 			return (0);
   3283  1.1  dholland 		if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5 &&
   3284  1.1  dholland 		    (nd->nd_flag & ND_GSS))
   3285  1.1  dholland 			return (0);
   3286  1.1  dholland 		if (exp->nes_secflavors[i] == AUTH_SYS &&
   3287  1.1  dholland 		    (nd->nd_flag & ND_GSS) == 0)
   3288  1.1  dholland 			return (0);
   3289  1.1  dholland 	}
   3290  1.1  dholland 	return (1);
   3291  1.1  dholland }
   3292  1.1  dholland 
   3293  1.1  dholland /*
   3294  1.1  dholland  * Calculate a hash value for the fid in a file handle.
   3295  1.1  dholland  */
   3296  1.1  dholland uint32_t
   3297  1.1  dholland nfsrv_hashfh(fhandle_t *fhp)
   3298  1.1  dholland {
   3299  1.1  dholland 	uint32_t hashval;
   3300  1.1  dholland 
   3301  1.1  dholland 	hashval = hash32_buf(&fhp->fh_fid, sizeof(struct fid), 0);
   3302  1.1  dholland 	return (hashval);
   3303  1.1  dholland }
   3304  1.1  dholland 
   3305  1.1  dholland /*
   3306  1.2  pgoyette  * Calculate a hash value for the sessionid.
   3307  1.2  pgoyette  */
   3308  1.2  pgoyette uint32_t
   3309  1.2  pgoyette nfsrv_hashsessionid(uint8_t *sessionid)
   3310  1.2  pgoyette {
   3311  1.2  pgoyette 	uint32_t hashval;
   3312  1.2  pgoyette 
   3313  1.2  pgoyette 	hashval = hash32_buf(sessionid, NFSX_V4SESSIONID, 0);
   3314  1.2  pgoyette 	return (hashval);
   3315  1.2  pgoyette }
   3316  1.2  pgoyette 
   3317  1.2  pgoyette /*
   3318  1.1  dholland  * Signal the userland master nfsd to backup the stable restart file.
   3319  1.1  dholland  */
   3320  1.1  dholland void
   3321  1.1  dholland nfsrv_backupstable(void)
   3322  1.1  dholland {
   3323  1.1  dholland 	struct proc *procp;
   3324  1.1  dholland 
   3325  1.1  dholland 	if (nfsd_master_proc != NULL) {
   3326  1.1  dholland 		procp = pfind(nfsd_master_pid);
   3327  1.1  dholland 		/* Try to make sure it is the correct process. */
   3328  1.1  dholland 		if (procp == nfsd_master_proc &&
   3329  1.1  dholland 		    procp->p_stats->p_start.tv_sec ==
   3330  1.1  dholland 		    nfsd_master_start.tv_sec &&
   3331  1.1  dholland 		    procp->p_stats->p_start.tv_usec ==
   3332  1.1  dholland 		    nfsd_master_start.tv_usec &&
   3333  1.1  dholland 		    strcmp(procp->p_comm, nfsd_master_comm) == 0)
   3334  1.1  dholland 			kern_psignal(procp, SIGUSR2);
   3335  1.1  dholland 		else
   3336  1.1  dholland 			nfsd_master_proc = NULL;
   3337  1.1  dholland 
   3338  1.1  dholland 		if (procp != NULL)
   3339  1.1  dholland 			PROC_UNLOCK(procp);
   3340  1.1  dholland 	}
   3341  1.1  dholland }
   3342  1.1  dholland 
   3343  1.1  dholland extern int (*nfsd_call_nfsd)(struct thread *, struct nfssvc_args *);
   3344  1.1  dholland 
   3345  1.1  dholland /*
   3346  1.1  dholland  * Called once to initialize data structures...
   3347  1.1  dholland  */
   3348  1.1  dholland static int
   3349  1.1  dholland nfsd_modevent(module_t mod, int type, void *data)
   3350  1.1  dholland {
   3351  1.1  dholland 	int error = 0, i;
   3352  1.1  dholland 	static int loaded = 0;
   3353  1.1  dholland 
   3354  1.1  dholland 	switch (type) {
   3355  1.1  dholland 	case MOD_LOAD:
   3356  1.1  dholland 		if (loaded)
   3357  1.1  dholland 			goto out;
   3358  1.1  dholland 		newnfs_portinit();
   3359  1.1  dholland 		for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) {
   3360  1.2  pgoyette 			mtx_init(&nfsrchash_table[i].mtx, "nfsrtc", NULL,
   3361  1.2  pgoyette 			    MTX_DEF);
   3362  1.2  pgoyette 			mtx_init(&nfsrcahash_table[i].mtx, "nfsrtca", NULL,
   3363  1.2  pgoyette 			    MTX_DEF);
   3364  1.2  pgoyette 		}
   3365  1.2  pgoyette 		mtx_init(&nfsrc_udpmtx, "nfsuc", NULL, MTX_DEF);
   3366  1.2  pgoyette 		mtx_init(&nfs_v4root_mutex, "nfs4rt", NULL, MTX_DEF);
   3367  1.2  pgoyette 		mtx_init(&nfsv4root_mnt.mnt_mtx, "nfs4mnt", NULL, MTX_DEF);
   3368  1.1  dholland 		lockinit(&nfsv4root_mnt.mnt_explock, PVFS, "explock", 0, 0);
   3369  1.1  dholland 		nfsrvd_initcache();
   3370  1.1  dholland 		nfsd_init();
   3371  1.1  dholland 		NFSD_LOCK();
   3372  1.1  dholland 		nfsrvd_init(0);
   3373  1.1  dholland 		NFSD_UNLOCK();
   3374  1.1  dholland 		nfsd_mntinit();
   3375  1.1  dholland #ifdef VV_DISABLEDELEG
   3376  1.1  dholland 		vn_deleg_ops.vndeleg_recall = nfsd_recalldelegation;
   3377  1.1  dholland 		vn_deleg_ops.vndeleg_disable = nfsd_disabledelegation;
   3378  1.1  dholland #endif
   3379  1.1  dholland 		nfsd_call_servertimer = nfsrv_servertimer;
   3380  1.1  dholland 		nfsd_call_nfsd = nfssvc_nfsd;
   3381  1.1  dholland 		loaded = 1;
   3382  1.1  dholland 		break;
   3383  1.1  dholland 
   3384  1.1  dholland 	case MOD_UNLOAD:
   3385  1.1  dholland 		if (newnfs_numnfsd != 0) {
   3386  1.1  dholland 			error = EBUSY;
   3387  1.1  dholland 			break;
   3388  1.1  dholland 		}
   3389  1.1  dholland 
   3390  1.1  dholland #ifdef VV_DISABLEDELEG
   3391  1.1  dholland 		vn_deleg_ops.vndeleg_recall = NULL;
   3392  1.1  dholland 		vn_deleg_ops.vndeleg_disable = NULL;
   3393  1.1  dholland #endif
   3394  1.1  dholland 		nfsd_call_servertimer = NULL;
   3395  1.1  dholland 		nfsd_call_nfsd = NULL;
   3396  1.1  dholland 
   3397  1.1  dholland 		/* Clean out all NFSv4 state. */
   3398  1.1  dholland 		nfsrv_throwawayallstate(curthread);
   3399  1.1  dholland 
   3400  1.1  dholland 		/* Clean the NFS server reply cache */
   3401  1.1  dholland 		nfsrvd_cleancache();
   3402  1.1  dholland 
   3403  1.1  dholland 		/* Free up the krpc server pool. */
   3404  1.1  dholland 		if (nfsrvd_pool != NULL)
   3405  1.1  dholland 			svcpool_destroy(nfsrvd_pool);
   3406  1.1  dholland 
   3407  1.1  dholland 		/* and get rid of the locks */
   3408  1.2  pgoyette 		for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) {
   3409  1.1  dholland 			mtx_destroy(&nfsrchash_table[i].mtx);
   3410  1.2  pgoyette 			mtx_destroy(&nfsrcahash_table[i].mtx);
   3411  1.2  pgoyette 		}
   3412  1.1  dholland 		mtx_destroy(&nfsrc_udpmtx);
   3413  1.1  dholland 		mtx_destroy(&nfs_v4root_mutex);
   3414  1.1  dholland 		mtx_destroy(&nfsv4root_mnt.mnt_mtx);
   3415  1.2  pgoyette 		for (i = 0; i < nfsrv_sessionhashsize; i++)
   3416  1.2  pgoyette 			mtx_destroy(&nfssessionhash[i].mtx);
   3417  1.1  dholland 		lockdestroy(&nfsv4root_mnt.mnt_explock);
   3418  1.2  pgoyette 		free(nfsclienthash, M_NFSDCLIENT);
   3419  1.2  pgoyette 		free(nfslockhash, M_NFSDLOCKFILE);
   3420  1.2  pgoyette 		free(nfssessionhash, M_NFSDSESSION);
   3421  1.1  dholland 		loaded = 0;
   3422  1.1  dholland 		break;
   3423  1.1  dholland 	default:
   3424  1.1  dholland 		error = EOPNOTSUPP;
   3425  1.1  dholland 		break;
   3426  1.1  dholland 	}
   3427  1.1  dholland 
   3428  1.1  dholland out:
   3429  1.1  dholland 	NFSEXITCODE(error);
   3430  1.1  dholland 	return (error);
   3431  1.1  dholland }
   3432  1.1  dholland static moduledata_t nfsd_mod = {
   3433  1.1  dholland 	"nfsd",
   3434  1.1  dholland 	nfsd_modevent,
   3435  1.1  dholland 	NULL,
   3436  1.1  dholland };
   3437  1.1  dholland DECLARE_MODULE(nfsd, nfsd_mod, SI_SUB_VFS, SI_ORDER_ANY);
   3438  1.1  dholland 
   3439  1.1  dholland /* So that loader and kldload(2) can find us, wherever we are.. */
   3440  1.1  dholland MODULE_VERSION(nfsd, 1);
   3441  1.1  dholland MODULE_DEPEND(nfsd, nfscommon, 1, 1, 1);
   3442  1.1  dholland MODULE_DEPEND(nfsd, nfslock, 1, 1, 1);
   3443  1.1  dholland MODULE_DEPEND(nfsd, nfslockd, 1, 1, 1);
   3444  1.1  dholland MODULE_DEPEND(nfsd, krpc, 1, 1, 1);
   3445  1.1  dholland MODULE_DEPEND(nfsd, nfssvc, 1, 1, 1);
   3446  1.1  dholland 
   3447