nfs_nfsdport.c revision 216894
198944Sobrien/*- 298944Sobrien * Copyright (c) 1989, 1993 398944Sobrien * The Regents of the University of California. All rights reserved. 498944Sobrien * 598944Sobrien * This code is derived from software contributed to Berkeley by 698944Sobrien * Rick Macklem at The University of Guelph. 798944Sobrien * 898944Sobrien * Redistribution and use in source and binary forms, with or without 998944Sobrien * modification, are permitted provided that the following conditions 1098944Sobrien * are met: 1198944Sobrien * 1. Redistributions of source code must retain the above copyright 1298944Sobrien * notice, this list of conditions and the following disclaimer. 1398944Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1498944Sobrien * notice, this list of conditions and the following disclaimer in the 1598944Sobrien * documentation and/or other materials provided with the distribution. 1698944Sobrien * 4. Neither the name of the University nor the names of its contributors 1798944Sobrien * may be used to endorse or promote products derived from this software 1898944Sobrien * without specific prior written permission. 1998944Sobrien * 2098944Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2198944Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2298944Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2398944Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2498944Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2598944Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2698944Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2798944Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2898944Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2998944Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3098944Sobrien * SUCH DAMAGE. 3198944Sobrien * 3298944Sobrien */ 3398944Sobrien 3498944Sobrien#include <sys/cdefs.h> 3598944Sobrien__FBSDID("$FreeBSD: head/sys/fs/nfsserver/nfs_nfsdport.c 216894 2011-01-02 21:34:01Z rmacklem $"); 3698944Sobrien 3798944Sobrien/* 3898944Sobrien * Functions that perform the vfs operations required by the routines in 3998944Sobrien * nfsd_serv.c. It is hoped that this change will make the server more 4098944Sobrien * portable. 4198944Sobrien */ 4298944Sobrien 4398944Sobrien#include <fs/nfs/nfsport.h> 4498944Sobrien#include <sys/hash.h> 4598944Sobrien#include <sys/sysctl.h> 4698944Sobrien#include <nlm/nlm_prot.h> 4798944Sobrien#include <nlm/nlm.h> 4898944Sobrien 4998944Sobrienextern u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1; 5098944Sobrienextern int nfsrv_useacl; 5198944Sobrienextern int newnfs_numnfsd; 5298944Sobrienextern struct mount nfsv4root_mnt; 5398944Sobrienextern struct nfsrv_stablefirst nfsrv_stablefirst; 5498944Sobrienextern void (*nfsd_call_servertimer)(void); 5598944Sobrienstruct vfsoptlist nfsv4root_opt, nfsv4root_newopt; 5698944SobrienNFSDLOCKMUTEX; 5798944Sobrienstruct mtx nfs_cache_mutex; 5898944Sobrienstruct mtx nfs_v4root_mutex; 5998944Sobrienstruct nfsrvfh nfs_rootfh, nfs_pubfh; 6098944Sobrienint nfs_pubfhset = 0, nfs_rootfhset = 0; 6198944Sobrienstatic uint32_t nfsv4_sysid = 0; 6298944Sobrien 6398944Sobrienstatic int nfssvc_srvcall(struct thread *, struct nfssvc_args *, 6498944Sobrien struct ucred *); 6598944Sobrien 6698944Sobrienstatic int enable_crossmntpt = 1; 6798944Sobrienstatic int nfs_commit_blks; 6898944Sobrienstatic int nfs_commit_miss; 6998944Sobrienextern int nfsrv_issuedelegs; 7098944Sobrienextern int nfsrv_dolocallocks; 7198944Sobrien 7298944SobrienSYSCTL_DECL(_vfs_newnfs); 7398944SobrienSYSCTL_INT(_vfs_newnfs, OID_AUTO, mirrormnt, CTLFLAG_RW, &enable_crossmntpt, 7498944Sobrien 0, "Enable nfsd to cross mount points"); 7598944SobrienSYSCTL_INT(_vfs_newnfs, OID_AUTO, commit_blks, CTLFLAG_RW, &nfs_commit_blks, 7698944Sobrien 0, ""); 7798944SobrienSYSCTL_INT(_vfs_newnfs, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss, 7898944Sobrien 0, ""); 7998944SobrienSYSCTL_INT(_vfs_newnfs, OID_AUTO, issue_delegations, CTLFLAG_RW, 8098944Sobrien &nfsrv_issuedelegs, 0, "Enable nfsd to issue delegations"); 8198944SobrienSYSCTL_INT(_vfs_newnfs, OID_AUTO, enable_locallocks, CTLFLAG_RW, 8298944Sobrien &nfsrv_dolocallocks, 0, "Enable nfsd to acquire local locks on files"); 8398944Sobrien 8498944Sobrien#define NUM_HEURISTIC 1017 8598944Sobrien#define NHUSE_INIT 64 8698944Sobrien#define NHUSE_INC 16 8798944Sobrien#define NHUSE_MAX 2048 8898944Sobrien 8998944Sobrienstatic struct nfsheur { 9098944Sobrien struct vnode *nh_vp; /* vp to match (unreferenced pointer) */ 9198944Sobrien off_t nh_nextr; /* next offset for sequential detection */ 9298944Sobrien int nh_use; /* use count for selection */ 9398944Sobrien int nh_seqcount; /* heuristic */ 9498944Sobrien} nfsheur[NUM_HEURISTIC]; 9598944Sobrien 9698944Sobrien 9798944Sobrien/* 9898944Sobrien * Get attributes into nfsvattr structure. 9998944Sobrien */ 10098944Sobrienint 10198944Sobriennfsvno_getattr(struct vnode *vp, struct nfsvattr *nvap, struct ucred *cred, 10298944Sobrien struct thread *p, int vpislocked) 10398944Sobrien{ 10498944Sobrien int error, lockedit = 0; 10598944Sobrien 10698944Sobrien if (vpislocked == 0) { 10798944Sobrien /* 10898944Sobrien * When vpislocked == 0, the vnode is either exclusively 10998944Sobrien * locked by this thread or not locked by this thread. 11098944Sobrien * As such, shared lock it, if not exclusively locked. 11198944Sobrien */ 11298944Sobrien if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { 11398944Sobrien lockedit = 1; 11498944Sobrien vn_lock(vp, LK_SHARED | LK_RETRY); 11598944Sobrien } 11698944Sobrien } 11798944Sobrien error = VOP_GETATTR(vp, &nvap->na_vattr, cred); 11898944Sobrien if (lockedit != 0) 11998944Sobrien VOP_UNLOCK(vp, 0); 12098944Sobrien return (error); 12198944Sobrien} 12298944Sobrien 12398944Sobrien/* 12498944Sobrien * Get a file handle for a vnode. 12598944Sobrien */ 12698944Sobrienint 12798944Sobriennfsvno_getfh(struct vnode *vp, fhandle_t *fhp, struct thread *p) 12898944Sobrien{ 12998944Sobrien int error; 13098944Sobrien 13198944Sobrien NFSBZERO((caddr_t)fhp, sizeof(fhandle_t)); 13298944Sobrien fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 13398944Sobrien error = VOP_VPTOFH(vp, &fhp->fh_fid); 13498944Sobrien return (error); 13598944Sobrien} 13698944Sobrien 13798944Sobrien/* 13898944Sobrien * Perform access checking for vnodes obtained from file handles that would 13998944Sobrien * refer to files already opened by a Unix client. You cannot just use 14098944Sobrien * vn_writechk() and VOP_ACCESSX() for two reasons. 14198944Sobrien * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write 14298944Sobrien * case. 14398944Sobrien * 2 - The owner is to be given access irrespective of mode bits for some 14498944Sobrien * operations, so that processes that chmod after opening a file don't 14598944Sobrien * break. 14698944Sobrien */ 14798944Sobrienint 14898944Sobriennfsvno_accchk(struct vnode *vp, accmode_t accmode, struct ucred *cred, 14998944Sobrien struct nfsexstuff *exp, struct thread *p, int override, int vpislocked, 15098944Sobrien u_int32_t *supportedtypep) 15198944Sobrien{ 15298944Sobrien struct vattr vattr; 15398944Sobrien int error = 0, getret = 0; 15498944Sobrien 15598944Sobrien if (vpislocked == 0) { 15698944Sobrien if (vn_lock(vp, LK_SHARED) != 0) 15798944Sobrien return (EPERM); 15898944Sobrien } 15998944Sobrien if (accmode & VWRITE) { 16098944Sobrien /* Just vn_writechk() changed to check rdonly */ 16198944Sobrien /* 16298944Sobrien * Disallow write attempts on read-only file systems; 16398944Sobrien * unless the file is a socket or a block or character 16498944Sobrien * device resident on the file system. 16598944Sobrien */ 16698944Sobrien if (NFSVNO_EXRDONLY(exp) || 16798944Sobrien (vp->v_mount->mnt_flag & MNT_RDONLY)) { 16898944Sobrien switch (vp->v_type) { 16998944Sobrien case VREG: 17098944Sobrien case VDIR: 17198944Sobrien case VLNK: 17298944Sobrien error = EROFS; 17398944Sobrien default: 17498944Sobrien break; 17598944Sobrien } 17698944Sobrien } 17798944Sobrien /* 17898944Sobrien * If there's shared text associated with 17998944Sobrien * the inode, try to free it up once. If 18098944Sobrien * we fail, we can't allow writing. 18198944Sobrien */ 18298944Sobrien if ((vp->v_vflag & VV_TEXT) != 0 && error == 0) 18398944Sobrien error = ETXTBSY; 18498944Sobrien } 18598944Sobrien if (error != 0) { 18698944Sobrien if (vpislocked == 0) 18798944Sobrien VOP_UNLOCK(vp, 0); 18898944Sobrien return (error); 18998944Sobrien } 19098944Sobrien 19198944Sobrien /* 19298944Sobrien * Should the override still be applied when ACLs are enabled? 19398944Sobrien */ 19498944Sobrien error = VOP_ACCESSX(vp, accmode, cred, p); 19598944Sobrien if (error != 0 && (accmode & (VDELETE | VDELETE_CHILD))) { 19698944Sobrien /* 19798944Sobrien * Try again with VEXPLICIT_DENY, to see if the test for 19898944Sobrien * deletion is supported. 19998944Sobrien */ 20098944Sobrien error = VOP_ACCESSX(vp, accmode | VEXPLICIT_DENY, cred, p); 20198944Sobrien if (error == 0) { 20298944Sobrien if (vp->v_type == VDIR) { 20398944Sobrien accmode &= ~(VDELETE | VDELETE_CHILD); 20498944Sobrien accmode |= VWRITE; 20598944Sobrien error = VOP_ACCESSX(vp, accmode, cred, p); 20698944Sobrien } else if (supportedtypep != NULL) { 20798944Sobrien *supportedtypep &= ~NFSACCESS_DELETE; 20898944Sobrien } 20998944Sobrien } 21098944Sobrien } 21198944Sobrien 21298944Sobrien /* 21398944Sobrien * Allow certain operations for the owner (reads and writes 21498944Sobrien * on files that are already open). 21598944Sobrien */ 21698944Sobrien if (override != NFSACCCHK_NOOVERRIDE && 21798944Sobrien (error == EPERM || error == EACCES)) { 21898944Sobrien if (cred->cr_uid == 0 && (override & NFSACCCHK_ALLOWROOT)) 21998944Sobrien error = 0; 22098944Sobrien else if (override & NFSACCCHK_ALLOWOWNER) { 22198944Sobrien getret = VOP_GETATTR(vp, &vattr, cred); 22298944Sobrien if (getret == 0 && cred->cr_uid == vattr.va_uid) 22398944Sobrien error = 0; 22498944Sobrien } 22598944Sobrien } 22698944Sobrien if (vpislocked == 0) 22798944Sobrien VOP_UNLOCK(vp, 0); 22898944Sobrien return (error); 22998944Sobrien} 23098944Sobrien 23198944Sobrien/* 23298944Sobrien * Set attribute(s) vnop. 23398944Sobrien */ 23498944Sobrienint 23598944Sobriennfsvno_setattr(struct vnode *vp, struct nfsvattr *nvap, struct ucred *cred, 23698944Sobrien struct thread *p, struct nfsexstuff *exp) 23798944Sobrien{ 23898944Sobrien int error; 23998944Sobrien 24098944Sobrien error = VOP_SETATTR(vp, &nvap->na_vattr, cred); 24198944Sobrien return (error); 24298944Sobrien} 24398944Sobrien 24498944Sobrien/* 24598944Sobrien * Set up nameidata for a lookup() call and do it 24698944Sobrien * For the cases where we are crossing mount points 24798944Sobrien * (looking up the public fh path or the v4 root path when 24898944Sobrien * not using a pseudo-root fs), set/release the Giant lock, 24998944Sobrien * as required. 25098944Sobrien */ 25198944Sobrienint 25298944Sobriennfsvno_namei(struct nfsrv_descript *nd, struct nameidata *ndp, 25398944Sobrien struct vnode *dp, int islocked, struct nfsexstuff *exp, struct thread *p, 25498944Sobrien struct vnode **retdirp) 25598944Sobrien{ 25698944Sobrien struct componentname *cnp = &ndp->ni_cnd; 25798944Sobrien int i; 25898944Sobrien struct iovec aiov; 25998944Sobrien struct uio auio; 26098944Sobrien int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0, linklen; 26198944Sobrien int error = 0, crossmnt; 26298944Sobrien char *cp; 26398944Sobrien 26498944Sobrien *retdirp = NULL; 26598944Sobrien cnp->cn_nameptr = cnp->cn_pnbuf; 26698944Sobrien /* 26798944Sobrien * Extract and set starting directory. 26898944Sobrien */ 26998944Sobrien if (dp->v_type != VDIR) { 27098944Sobrien if (islocked) 27198944Sobrien vput(dp); 27298944Sobrien else 27398944Sobrien vrele(dp); 27498944Sobrien nfsvno_relpathbuf(ndp); 27598944Sobrien return (ENOTDIR); 27698944Sobrien } 27798944Sobrien if (islocked) 27898944Sobrien NFSVOPUNLOCK(dp, 0, p); 27998944Sobrien VREF(dp); 28098944Sobrien *retdirp = dp; 28198944Sobrien if (NFSVNO_EXRDONLY(exp)) 28298944Sobrien cnp->cn_flags |= RDONLY; 28398944Sobrien ndp->ni_segflg = UIO_SYSSPACE; 28498944Sobrien crossmnt = 1; 28598944Sobrien 28698944Sobrien if (nd->nd_flag & ND_PUBLOOKUP) { 28798944Sobrien ndp->ni_loopcnt = 0; 28898944Sobrien if (cnp->cn_pnbuf[0] == '/') { 28998944Sobrien vrele(dp); 29098944Sobrien /* 29198944Sobrien * Check for degenerate pathnames here, since lookup() 29298944Sobrien * panics on them. 29398944Sobrien */ 29498944Sobrien for (i = 1; i < ndp->ni_pathlen; i++) 29598944Sobrien if (cnp->cn_pnbuf[i] != '/') 29698944Sobrien break; 29798944Sobrien if (i == ndp->ni_pathlen) { 29898944Sobrien error = NFSERR_ACCES; 29998944Sobrien goto out; 30098944Sobrien } 30198944Sobrien dp = rootvnode; 30298944Sobrien VREF(dp); 30398944Sobrien } 30498944Sobrien } else if ((enable_crossmntpt == 0 && NFSVNO_EXPORTED(exp)) || 30598944Sobrien (nd->nd_flag & ND_NFSV4) == 0) { 30698944Sobrien /* 30798944Sobrien * Only cross mount points for NFSv4 when doing a 30898944Sobrien * mount while traversing the file system above 30998944Sobrien * the mount point, unless enable_crossmntpt is set. 31098944Sobrien */ 31198944Sobrien cnp->cn_flags |= NOCROSSMOUNT; 31298944Sobrien crossmnt = 0; 31398944Sobrien } 31498944Sobrien 31598944Sobrien /* 31698944Sobrien * Initialize for scan, set ni_startdir and bump ref on dp again 31798944Sobrien * becuase lookup() will dereference ni_startdir. 31898944Sobrien */ 31998944Sobrien 32098944Sobrien cnp->cn_thread = p; 32198944Sobrien ndp->ni_startdir = dp; 32298944Sobrien ndp->ni_rootdir = rootvnode; 32398944Sobrien 32498944Sobrien if (!lockleaf) 32598944Sobrien cnp->cn_flags |= LOCKLEAF; 32698944Sobrien for (;;) { 32798944Sobrien cnp->cn_nameptr = cnp->cn_pnbuf; 32898944Sobrien /* 32998944Sobrien * Call lookup() to do the real work. If an error occurs, 33098944Sobrien * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 33198944Sobrien * we do not have to dereference anything before returning. 33298944Sobrien * In either case ni_startdir will be dereferenced and NULLed 33398944Sobrien * out. 33498944Sobrien */ 33598944Sobrien if (exp->nes_vfslocked) 33698944Sobrien ndp->ni_cnd.cn_flags |= GIANTHELD; 33798944Sobrien error = lookup(ndp); 33898944Sobrien /* 33998944Sobrien * The Giant lock should only change when 34098944Sobrien * crossing mount points. 34198944Sobrien */ 34298944Sobrien if (crossmnt) { 34398944Sobrien exp->nes_vfslocked = 34498944Sobrien (ndp->ni_cnd.cn_flags & GIANTHELD) != 0; 34598944Sobrien ndp->ni_cnd.cn_flags &= ~GIANTHELD; 34698944Sobrien } 34798944Sobrien if (error) 34898944Sobrien break; 34998944Sobrien 35098944Sobrien /* 35198944Sobrien * Check for encountering a symbolic link. Trivial 35298944Sobrien * termination occurs if no symlink encountered. 35398944Sobrien */ 35498944Sobrien if ((cnp->cn_flags & ISSYMLINK) == 0) { 35598944Sobrien if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) 35698944Sobrien nfsvno_relpathbuf(ndp); 35798944Sobrien if (ndp->ni_vp && !lockleaf) 35898944Sobrien NFSVOPUNLOCK(ndp->ni_vp, 0, p); 35998944Sobrien break; 36098944Sobrien } 36198944Sobrien 36298944Sobrien /* 36398944Sobrien * Validate symlink 36498944Sobrien */ 36598944Sobrien if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 36698944Sobrien NFSVOPUNLOCK(ndp->ni_dvp, 0, p); 36798944Sobrien if (!(nd->nd_flag & ND_PUBLOOKUP)) { 36898944Sobrien error = EINVAL; 36998944Sobrien goto badlink2; 37098944Sobrien } 37198944Sobrien 37298944Sobrien if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 37398944Sobrien error = ELOOP; 37498944Sobrien goto badlink2; 37598944Sobrien } 37698944Sobrien if (ndp->ni_pathlen > 1) 37798944Sobrien cp = uma_zalloc(namei_zone, M_WAITOK); 37898944Sobrien else 37998944Sobrien cp = cnp->cn_pnbuf; 38098944Sobrien aiov.iov_base = cp; 38198944Sobrien aiov.iov_len = MAXPATHLEN; 38298944Sobrien auio.uio_iov = &aiov; 38398944Sobrien auio.uio_iovcnt = 1; 38498944Sobrien auio.uio_offset = 0; 38598944Sobrien auio.uio_rw = UIO_READ; 38698944Sobrien auio.uio_segflg = UIO_SYSSPACE; 38798944Sobrien auio.uio_td = NULL; 38898944Sobrien auio.uio_resid = MAXPATHLEN; 38998944Sobrien error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 39098944Sobrien if (error) { 39198944Sobrien badlink1: 39298944Sobrien if (ndp->ni_pathlen > 1) 39398944Sobrien uma_zfree(namei_zone, cp); 39498944Sobrien badlink2: 39598944Sobrien vrele(ndp->ni_dvp); 39698944Sobrien vput(ndp->ni_vp); 39798944Sobrien break; 39898944Sobrien } 39998944Sobrien linklen = MAXPATHLEN - auio.uio_resid; 40098944Sobrien if (linklen == 0) { 40198944Sobrien error = ENOENT; 40298944Sobrien goto badlink1; 40398944Sobrien } 40498944Sobrien if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 40598944Sobrien error = ENAMETOOLONG; 40698944Sobrien goto badlink1; 40798944Sobrien } 40898944Sobrien 40998944Sobrien /* 41098944Sobrien * Adjust or replace path 41198944Sobrien */ 41298944Sobrien if (ndp->ni_pathlen > 1) { 41398944Sobrien NFSBCOPY(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 41498944Sobrien uma_zfree(namei_zone, cnp->cn_pnbuf); 41598944Sobrien cnp->cn_pnbuf = cp; 41698944Sobrien } else 41798944Sobrien cnp->cn_pnbuf[linklen] = '\0'; 41898944Sobrien ndp->ni_pathlen += linklen; 41998944Sobrien 42098944Sobrien /* 42198944Sobrien * Cleanup refs for next loop and check if root directory 42298944Sobrien * should replace current directory. Normally ni_dvp 42398944Sobrien * becomes the new base directory and is cleaned up when 42498944Sobrien * we loop. Explicitly null pointers after invalidation 42598944Sobrien * to clarify operation. 42698944Sobrien */ 42798944Sobrien vput(ndp->ni_vp); 42898944Sobrien ndp->ni_vp = NULL; 42998944Sobrien 43098944Sobrien if (cnp->cn_pnbuf[0] == '/') { 43198944Sobrien vrele(ndp->ni_dvp); 43298944Sobrien ndp->ni_dvp = ndp->ni_rootdir; 43398944Sobrien VREF(ndp->ni_dvp); 43498944Sobrien } 43598944Sobrien ndp->ni_startdir = ndp->ni_dvp; 43698944Sobrien ndp->ni_dvp = NULL; 43798944Sobrien } 43898944Sobrien if (!lockleaf) 43998944Sobrien cnp->cn_flags &= ~LOCKLEAF; 44098944Sobrien 44198944Sobrienout: 44298944Sobrien if (error) { 44398944Sobrien uma_zfree(namei_zone, cnp->cn_pnbuf); 44498944Sobrien ndp->ni_vp = NULL; 44598944Sobrien ndp->ni_dvp = NULL; 44698944Sobrien ndp->ni_startdir = NULL; 44798944Sobrien cnp->cn_flags &= ~HASBUF; 44898944Sobrien } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 44998944Sobrien ndp->ni_dvp = NULL; 45098944Sobrien } 45198944Sobrien return (error); 45298944Sobrien} 45398944Sobrien 45498944Sobrien/* 45598944Sobrien * Set up a pathname buffer and return a pointer to it and, optionally 45698944Sobrien * set a hash pointer. 45798944Sobrien */ 45898944Sobrienvoid 45998944Sobriennfsvno_setpathbuf(struct nameidata *ndp, char **bufpp, u_long **hashpp) 46098944Sobrien{ 46198944Sobrien struct componentname *cnp = &ndp->ni_cnd; 46298944Sobrien 46398944Sobrien cnp->cn_flags |= (NOMACCHECK | HASBUF); 46498944Sobrien cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 465 if (hashpp != NULL) 466 *hashpp = NULL; 467 *bufpp = cnp->cn_pnbuf; 468} 469 470/* 471 * Release the above path buffer, if not released by nfsvno_namei(). 472 */ 473void 474nfsvno_relpathbuf(struct nameidata *ndp) 475{ 476 477 if ((ndp->ni_cnd.cn_flags & HASBUF) == 0) 478 panic("nfsrelpath"); 479 uma_zfree(namei_zone, ndp->ni_cnd.cn_pnbuf); 480 ndp->ni_cnd.cn_flags &= ~HASBUF; 481} 482 483/* 484 * Readlink vnode op into an mbuf list. 485 */ 486int 487nfsvno_readlink(struct vnode *vp, struct ucred *cred, struct thread *p, 488 struct mbuf **mpp, struct mbuf **mpendp, int *lenp) 489{ 490 struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 491 struct iovec *ivp = iv; 492 struct uio io, *uiop = &io; 493 struct mbuf *mp, *mp2 = NULL, *mp3 = NULL; 494 int i, len, tlen, error; 495 496 len = 0; 497 i = 0; 498 while (len < NFS_MAXPATHLEN) { 499 NFSMGET(mp); 500 MCLGET(mp, M_WAIT); 501 mp->m_len = NFSMSIZ(mp); 502 if (len == 0) { 503 mp3 = mp2 = mp; 504 } else { 505 mp2->m_next = mp; 506 mp2 = mp; 507 } 508 if ((len + mp->m_len) > NFS_MAXPATHLEN) { 509 mp->m_len = NFS_MAXPATHLEN - len; 510 len = NFS_MAXPATHLEN; 511 } else { 512 len += mp->m_len; 513 } 514 ivp->iov_base = mtod(mp, caddr_t); 515 ivp->iov_len = mp->m_len; 516 i++; 517 ivp++; 518 } 519 uiop->uio_iov = iv; 520 uiop->uio_iovcnt = i; 521 uiop->uio_offset = 0; 522 uiop->uio_resid = len; 523 uiop->uio_rw = UIO_READ; 524 uiop->uio_segflg = UIO_SYSSPACE; 525 uiop->uio_td = NULL; 526 error = VOP_READLINK(vp, uiop, cred); 527 if (error) { 528 m_freem(mp3); 529 *lenp = 0; 530 return (error); 531 } 532 if (uiop->uio_resid > 0) { 533 len -= uiop->uio_resid; 534 tlen = NFSM_RNDUP(len); 535 nfsrv_adj(mp3, NFS_MAXPATHLEN - tlen, tlen - len); 536 } 537 *lenp = len; 538 *mpp = mp3; 539 *mpendp = mp; 540 return (0); 541} 542 543/* 544 * Read vnode op call into mbuf list. 545 */ 546int 547nfsvno_read(struct vnode *vp, off_t off, int cnt, struct ucred *cred, 548 struct thread *p, struct mbuf **mpp, struct mbuf **mpendp) 549{ 550 struct mbuf *m; 551 int i; 552 struct iovec *iv; 553 struct iovec *iv2; 554 int error = 0, len, left, siz, tlen, ioflag = 0, hi, try = 32; 555 struct mbuf *m2 = NULL, *m3; 556 struct uio io, *uiop = &io; 557 struct nfsheur *nh; 558 559 /* 560 * Calculate seqcount for heuristic 561 */ 562 /* 563 * Locate best candidate 564 */ 565 566 hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) % NUM_HEURISTIC; 567 nh = &nfsheur[hi]; 568 569 while (try--) { 570 if (nfsheur[hi].nh_vp == vp) { 571 nh = &nfsheur[hi]; 572 break; 573 } 574 if (nfsheur[hi].nh_use > 0) 575 --nfsheur[hi].nh_use; 576 hi = (hi + 1) % NUM_HEURISTIC; 577 if (nfsheur[hi].nh_use < nh->nh_use) 578 nh = &nfsheur[hi]; 579 } 580 581 if (nh->nh_vp != vp) { 582 nh->nh_vp = vp; 583 nh->nh_nextr = off; 584 nh->nh_use = NHUSE_INIT; 585 if (off == 0) 586 nh->nh_seqcount = 4; 587 else 588 nh->nh_seqcount = 1; 589 } 590 591 /* 592 * Calculate heuristic 593 */ 594 595 if ((off == 0 && nh->nh_seqcount > 0) || off == nh->nh_nextr) { 596 if (++nh->nh_seqcount > IO_SEQMAX) 597 nh->nh_seqcount = IO_SEQMAX; 598 } else if (nh->nh_seqcount > 1) { 599 nh->nh_seqcount = 1; 600 } else { 601 nh->nh_seqcount = 0; 602 } 603 nh->nh_use += NHUSE_INC; 604 if (nh->nh_use > NHUSE_MAX) 605 nh->nh_use = NHUSE_MAX; 606 ioflag |= nh->nh_seqcount << IO_SEQSHIFT; 607 608 len = left = NFSM_RNDUP(cnt); 609 m3 = NULL; 610 /* 611 * Generate the mbuf list with the uio_iov ref. to it. 612 */ 613 i = 0; 614 while (left > 0) { 615 NFSMGET(m); 616 MCLGET(m, M_WAIT); 617 m->m_len = 0; 618 siz = min(M_TRAILINGSPACE(m), left); 619 left -= siz; 620 i++; 621 if (m3) 622 m2->m_next = m; 623 else 624 m3 = m; 625 m2 = m; 626 } 627 MALLOC(iv, struct iovec *, i * sizeof (struct iovec), 628 M_TEMP, M_WAITOK); 629 uiop->uio_iov = iv2 = iv; 630 m = m3; 631 left = len; 632 i = 0; 633 while (left > 0) { 634 if (m == NULL) 635 panic("nfsvno_read iov"); 636 siz = min(M_TRAILINGSPACE(m), left); 637 if (siz > 0) { 638 iv->iov_base = mtod(m, caddr_t) + m->m_len; 639 iv->iov_len = siz; 640 m->m_len += siz; 641 left -= siz; 642 iv++; 643 i++; 644 } 645 m = m->m_next; 646 } 647 uiop->uio_iovcnt = i; 648 uiop->uio_offset = off; 649 uiop->uio_resid = len; 650 uiop->uio_rw = UIO_READ; 651 uiop->uio_segflg = UIO_SYSSPACE; 652 error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred); 653 FREE((caddr_t)iv2, M_TEMP); 654 if (error) { 655 m_freem(m3); 656 *mpp = NULL; 657 return (error); 658 } 659 tlen = len - uiop->uio_resid; 660 cnt = cnt < tlen ? cnt : tlen; 661 tlen = NFSM_RNDUP(cnt); 662 if (tlen == 0) { 663 m_freem(m3); 664 m3 = NULL; 665 } else if (len != tlen || tlen != cnt) 666 nfsrv_adj(m3, len - tlen, tlen - cnt); 667 *mpp = m3; 668 *mpendp = m2; 669 return (0); 670} 671 672/* 673 * Write vnode op from an mbuf list. 674 */ 675int 676nfsvno_write(struct vnode *vp, off_t off, int retlen, int cnt, int stable, 677 struct mbuf *mp, char *cp, struct ucred *cred, struct thread *p) 678{ 679 struct iovec *ivp; 680 int i, len; 681 struct iovec *iv; 682 int ioflags, error; 683 struct uio io, *uiop = &io; 684 685 MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP, 686 M_WAITOK); 687 uiop->uio_iov = iv = ivp; 688 uiop->uio_iovcnt = cnt; 689 i = mtod(mp, caddr_t) + mp->m_len - cp; 690 len = retlen; 691 while (len > 0) { 692 if (mp == NULL) 693 panic("nfsvno_write"); 694 if (i > 0) { 695 i = min(i, len); 696 ivp->iov_base = cp; 697 ivp->iov_len = i; 698 ivp++; 699 len -= i; 700 } 701 mp = mp->m_next; 702 if (mp) { 703 i = mp->m_len; 704 cp = mtod(mp, caddr_t); 705 } 706 } 707 708 if (stable == NFSWRITE_UNSTABLE) 709 ioflags = IO_NODELOCKED; 710 else 711 ioflags = (IO_SYNC | IO_NODELOCKED); 712 uiop->uio_resid = retlen; 713 uiop->uio_rw = UIO_WRITE; 714 uiop->uio_segflg = UIO_SYSSPACE; 715 NFSUIOPROC(uiop, p); 716 uiop->uio_offset = off; 717 error = VOP_WRITE(vp, uiop, ioflags, cred); 718 FREE((caddr_t)iv, M_TEMP); 719 return (error); 720} 721 722/* 723 * Common code for creating a regular file (plus special files for V2). 724 */ 725int 726nfsvno_createsub(struct nfsrv_descript *nd, struct nameidata *ndp, 727 struct vnode **vpp, struct nfsvattr *nvap, int *exclusive_flagp, 728 int32_t *cverf, NFSDEV_T rdev, struct thread *p, struct nfsexstuff *exp) 729{ 730 u_quad_t tempsize; 731 int error; 732 733 error = nd->nd_repstat; 734 if (!error && ndp->ni_vp == NULL) { 735 if (nvap->na_type == VREG || nvap->na_type == VSOCK) { 736 vrele(ndp->ni_startdir); 737 error = VOP_CREATE(ndp->ni_dvp, 738 &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr); 739 vput(ndp->ni_dvp); 740 nfsvno_relpathbuf(ndp); 741 if (!error) { 742 if (*exclusive_flagp) { 743 *exclusive_flagp = 0; 744 NFSVNO_ATTRINIT(nvap); 745 nvap->na_atime.tv_sec = cverf[0]; 746 nvap->na_atime.tv_nsec = cverf[1]; 747 error = VOP_SETATTR(ndp->ni_vp, 748 &nvap->na_vattr, nd->nd_cred); 749 } 750 } 751 /* 752 * NFS V2 Only. nfsrvd_mknod() does this for V3. 753 * (This implies, just get out on an error.) 754 */ 755 } else if (nvap->na_type == VCHR || nvap->na_type == VBLK || 756 nvap->na_type == VFIFO) { 757 if (nvap->na_type == VCHR && rdev == 0xffffffff) 758 nvap->na_type = VFIFO; 759 if (nvap->na_type != VFIFO && 760 (error = priv_check_cred(nd->nd_cred, 761 PRIV_VFS_MKNOD_DEV, 0))) { 762 vrele(ndp->ni_startdir); 763 nfsvno_relpathbuf(ndp); 764 vput(ndp->ni_dvp); 765 return (error); 766 } 767 nvap->na_rdev = rdev; 768 error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp, 769 &ndp->ni_cnd, &nvap->na_vattr); 770 vput(ndp->ni_dvp); 771 nfsvno_relpathbuf(ndp); 772 if (error) { 773 vrele(ndp->ni_startdir); 774 return (error); 775 } 776 } else { 777 vrele(ndp->ni_startdir); 778 nfsvno_relpathbuf(ndp); 779 vput(ndp->ni_dvp); 780 return (ENXIO); 781 } 782 *vpp = ndp->ni_vp; 783 } else { 784 /* 785 * Handle cases where error is already set and/or 786 * the file exists. 787 * 1 - clean up the lookup 788 * 2 - iff !error and na_size set, truncate it 789 */ 790 vrele(ndp->ni_startdir); 791 nfsvno_relpathbuf(ndp); 792 *vpp = ndp->ni_vp; 793 if (ndp->ni_dvp == *vpp) 794 vrele(ndp->ni_dvp); 795 else 796 vput(ndp->ni_dvp); 797 if (!error && nvap->na_size != VNOVAL) { 798 error = nfsvno_accchk(*vpp, VWRITE, 799 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, 800 NFSACCCHK_VPISLOCKED, NULL); 801 if (!error) { 802 tempsize = nvap->na_size; 803 NFSVNO_ATTRINIT(nvap); 804 nvap->na_size = tempsize; 805 error = VOP_SETATTR(*vpp, 806 &nvap->na_vattr, nd->nd_cred); 807 } 808 } 809 if (error) 810 vput(*vpp); 811 } 812 return (error); 813} 814 815/* 816 * Do a mknod vnode op. 817 */ 818int 819nfsvno_mknod(struct nameidata *ndp, struct nfsvattr *nvap, struct ucred *cred, 820 struct thread *p) 821{ 822 int error = 0; 823 enum vtype vtyp; 824 825 vtyp = nvap->na_type; 826 /* 827 * Iff doesn't exist, create it. 828 */ 829 if (ndp->ni_vp) { 830 vrele(ndp->ni_startdir); 831 nfsvno_relpathbuf(ndp); 832 vput(ndp->ni_dvp); 833 vrele(ndp->ni_vp); 834 return (EEXIST); 835 } 836 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { 837 vrele(ndp->ni_startdir); 838 nfsvno_relpathbuf(ndp); 839 vput(ndp->ni_dvp); 840 return (NFSERR_BADTYPE); 841 } 842 if (vtyp == VSOCK) { 843 vrele(ndp->ni_startdir); 844 error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, 845 &ndp->ni_cnd, &nvap->na_vattr); 846 vput(ndp->ni_dvp); 847 nfsvno_relpathbuf(ndp); 848 } else { 849 if (nvap->na_type != VFIFO && 850 (error = priv_check_cred(cred, PRIV_VFS_MKNOD_DEV, 0))) { 851 vrele(ndp->ni_startdir); 852 nfsvno_relpathbuf(ndp); 853 vput(ndp->ni_dvp); 854 return (error); 855 } 856 error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp, 857 &ndp->ni_cnd, &nvap->na_vattr); 858 vput(ndp->ni_dvp); 859 nfsvno_relpathbuf(ndp); 860 if (error) 861 vrele(ndp->ni_startdir); 862 /* 863 * Since VOP_MKNOD returns the ni_vp, I can't 864 * see any reason to do the lookup. 865 */ 866 } 867 return (error); 868} 869 870/* 871 * Mkdir vnode op. 872 */ 873int 874nfsvno_mkdir(struct nameidata *ndp, struct nfsvattr *nvap, uid_t saved_uid, 875 struct ucred *cred, struct thread *p, struct nfsexstuff *exp) 876{ 877 int error = 0; 878 879 if (ndp->ni_vp != NULL) { 880 if (ndp->ni_dvp == ndp->ni_vp) 881 vrele(ndp->ni_dvp); 882 else 883 vput(ndp->ni_dvp); 884 vrele(ndp->ni_vp); 885 nfsvno_relpathbuf(ndp); 886 return (EEXIST); 887 } 888 error = VOP_MKDIR(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, 889 &nvap->na_vattr); 890 vput(ndp->ni_dvp); 891 nfsvno_relpathbuf(ndp); 892 return (error); 893} 894 895/* 896 * symlink vnode op. 897 */ 898int 899nfsvno_symlink(struct nameidata *ndp, struct nfsvattr *nvap, char *pathcp, 900 int pathlen, int not_v2, uid_t saved_uid, struct ucred *cred, struct thread *p, 901 struct nfsexstuff *exp) 902{ 903 int error = 0; 904 905 if (ndp->ni_vp) { 906 vrele(ndp->ni_startdir); 907 nfsvno_relpathbuf(ndp); 908 if (ndp->ni_dvp == ndp->ni_vp) 909 vrele(ndp->ni_dvp); 910 else 911 vput(ndp->ni_dvp); 912 vrele(ndp->ni_vp); 913 return (EEXIST); 914 } 915 916 error = VOP_SYMLINK(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, 917 &nvap->na_vattr, pathcp); 918 vput(ndp->ni_dvp); 919 vrele(ndp->ni_startdir); 920 nfsvno_relpathbuf(ndp); 921 /* 922 * Although FreeBSD still had the lookup code in 923 * it for 7/current, there doesn't seem to be any 924 * point, since VOP_SYMLINK() returns the ni_vp. 925 * Just vput it for v2. 926 */ 927 if (!not_v2 && !error) 928 vput(ndp->ni_vp); 929 return (error); 930} 931 932/* 933 * Parse symbolic link arguments. 934 * This function has an ugly side effect. It will MALLOC() an area for 935 * the symlink and set iov_base to point to it, only if it succeeds. 936 * So, if it returns with uiop->uio_iov->iov_base != NULL, that must 937 * be FREE'd later. 938 */ 939int 940nfsvno_getsymlink(struct nfsrv_descript *nd, struct nfsvattr *nvap, 941 struct thread *p, char **pathcpp, int *lenp) 942{ 943 u_int32_t *tl; 944 char *pathcp = NULL; 945 int error = 0, len; 946 struct nfsv2_sattr *sp; 947 948 *pathcpp = NULL; 949 *lenp = 0; 950 if ((nd->nd_flag & ND_NFSV3) && 951 (error = nfsrv_sattr(nd, nvap, NULL, NULL, p))) 952 goto nfsmout; 953 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 954 len = fxdr_unsigned(int, *tl); 955 if (len > NFS_MAXPATHLEN || len <= 0) { 956 error = EBADRPC; 957 goto nfsmout; 958 } 959 MALLOC(pathcp, caddr_t, len + 1, M_TEMP, M_WAITOK); 960 error = nfsrv_mtostr(nd, pathcp, len); 961 if (error) 962 goto nfsmout; 963 if (nd->nd_flag & ND_NFSV2) { 964 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 965 nvap->na_mode = fxdr_unsigned(u_int16_t, sp->sa_mode); 966 } 967 *pathcpp = pathcp; 968 *lenp = len; 969 return (0); 970nfsmout: 971 if (pathcp) 972 free(pathcp, M_TEMP); 973 return (error); 974} 975 976/* 977 * Remove a non-directory object. 978 */ 979int 980nfsvno_removesub(struct nameidata *ndp, int is_v4, struct ucred *cred, 981 struct thread *p, struct nfsexstuff *exp) 982{ 983 struct vnode *vp; 984 int error = 0; 985 986 vp = ndp->ni_vp; 987 if (vp->v_type == VDIR) 988 error = NFSERR_ISDIR; 989 else if (is_v4) 990 error = nfsrv_checkremove(vp, 1, p); 991 if (!error) 992 error = VOP_REMOVE(ndp->ni_dvp, vp, &ndp->ni_cnd); 993 if (ndp->ni_dvp == vp) 994 vrele(ndp->ni_dvp); 995 else 996 vput(ndp->ni_dvp); 997 vput(vp); 998 return (error); 999} 1000 1001/* 1002 * Remove a directory. 1003 */ 1004int 1005nfsvno_rmdirsub(struct nameidata *ndp, int is_v4, struct ucred *cred, 1006 struct thread *p, struct nfsexstuff *exp) 1007{ 1008 struct vnode *vp; 1009 int error = 0; 1010 1011 vp = ndp->ni_vp; 1012 if (vp->v_type != VDIR) { 1013 error = ENOTDIR; 1014 goto out; 1015 } 1016 /* 1017 * No rmdir "." please. 1018 */ 1019 if (ndp->ni_dvp == vp) { 1020 error = EINVAL; 1021 goto out; 1022 } 1023 /* 1024 * The root of a mounted filesystem cannot be deleted. 1025 */ 1026 if (vp->v_vflag & VV_ROOT) 1027 error = EBUSY; 1028out: 1029 if (!error) 1030 error = VOP_RMDIR(ndp->ni_dvp, vp, &ndp->ni_cnd); 1031 if (ndp->ni_dvp == vp) 1032 vrele(ndp->ni_dvp); 1033 else 1034 vput(ndp->ni_dvp); 1035 vput(vp); 1036 return (error); 1037} 1038 1039/* 1040 * Rename vnode op. 1041 */ 1042int 1043nfsvno_rename(struct nameidata *fromndp, struct nameidata *tondp, 1044 u_int32_t ndstat, u_int32_t ndflag, struct ucred *cred, struct thread *p) 1045{ 1046 struct vnode *fvp, *tvp, *tdvp; 1047 int error = 0; 1048 1049 fvp = fromndp->ni_vp; 1050 if (ndstat) { 1051 vrele(fromndp->ni_dvp); 1052 vrele(fvp); 1053 error = ndstat; 1054 goto out1; 1055 } 1056 tdvp = tondp->ni_dvp; 1057 tvp = tondp->ni_vp; 1058 if (tvp != NULL) { 1059 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 1060 error = (ndflag & ND_NFSV2) ? EISDIR : EEXIST; 1061 goto out; 1062 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 1063 error = (ndflag & ND_NFSV2) ? ENOTDIR : EEXIST; 1064 goto out; 1065 } 1066 if (tvp->v_type == VDIR && tvp->v_mountedhere) { 1067 error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EXDEV; 1068 goto out; 1069 } 1070 1071 /* 1072 * A rename to '.' or '..' results in a prematurely 1073 * unlocked vnode on FreeBSD5, so I'm just going to fail that 1074 * here. 1075 */ 1076 if ((tondp->ni_cnd.cn_namelen == 1 && 1077 tondp->ni_cnd.cn_nameptr[0] == '.') || 1078 (tondp->ni_cnd.cn_namelen == 2 && 1079 tondp->ni_cnd.cn_nameptr[0] == '.' && 1080 tondp->ni_cnd.cn_nameptr[1] == '.')) { 1081 error = EINVAL; 1082 goto out; 1083 } 1084 } 1085 if (fvp->v_type == VDIR && fvp->v_mountedhere) { 1086 error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EXDEV; 1087 goto out; 1088 } 1089 if (fvp->v_mount != tdvp->v_mount) { 1090 error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EXDEV; 1091 goto out; 1092 } 1093 if (fvp == tdvp) { 1094 error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EINVAL; 1095 goto out; 1096 } 1097 if (fvp == tvp) { 1098 /* 1099 * If source and destination are the same, there is nothing to 1100 * do. Set error to -1 to indicate this. 1101 */ 1102 error = -1; 1103 goto out; 1104 } 1105 if (ndflag & ND_NFSV4) { 1106 if (vn_lock(fvp, LK_EXCLUSIVE) == 0) { 1107 error = nfsrv_checkremove(fvp, 0, p); 1108 VOP_UNLOCK(fvp, 0); 1109 } else 1110 error = EPERM; 1111 if (tvp && !error) 1112 error = nfsrv_checkremove(tvp, 1, p); 1113 } else { 1114 /* 1115 * For NFSv2 and NFSv3, try to get rid of the delegation, so 1116 * that the NFSv4 client won't be confused by the rename. 1117 * Since nfsd_recalldelegation() can only be called on an 1118 * unlocked vnode at this point and fvp is the file that will 1119 * still exist after the rename, just do fvp. 1120 */ 1121 nfsd_recalldelegation(fvp, p); 1122 } 1123out: 1124 if (!error) { 1125 error = VOP_RENAME(fromndp->ni_dvp, fromndp->ni_vp, 1126 &fromndp->ni_cnd, tondp->ni_dvp, tondp->ni_vp, 1127 &tondp->ni_cnd); 1128 } else { 1129 if (tdvp == tvp) 1130 vrele(tdvp); 1131 else 1132 vput(tdvp); 1133 if (tvp) 1134 vput(tvp); 1135 vrele(fromndp->ni_dvp); 1136 vrele(fvp); 1137 if (error == -1) 1138 error = 0; 1139 } 1140 vrele(tondp->ni_startdir); 1141 nfsvno_relpathbuf(tondp); 1142out1: 1143 vrele(fromndp->ni_startdir); 1144 nfsvno_relpathbuf(fromndp); 1145 return (error); 1146} 1147 1148/* 1149 * Link vnode op. 1150 */ 1151int 1152nfsvno_link(struct nameidata *ndp, struct vnode *vp, struct ucred *cred, 1153 struct thread *p, struct nfsexstuff *exp) 1154{ 1155 struct vnode *xp; 1156 int error = 0; 1157 1158 xp = ndp->ni_vp; 1159 if (xp != NULL) { 1160 error = EEXIST; 1161 } else { 1162 xp = ndp->ni_dvp; 1163 if (vp->v_mount != xp->v_mount) 1164 error = EXDEV; 1165 } 1166 if (!error) { 1167 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1168 if ((vp->v_iflag & VI_DOOMED) == 0) 1169 error = VOP_LINK(ndp->ni_dvp, vp, &ndp->ni_cnd); 1170 else 1171 error = EPERM; 1172 if (ndp->ni_dvp == vp) 1173 vrele(ndp->ni_dvp); 1174 else 1175 vput(ndp->ni_dvp); 1176 VOP_UNLOCK(vp, 0); 1177 } else { 1178 if (ndp->ni_dvp == ndp->ni_vp) 1179 vrele(ndp->ni_dvp); 1180 else 1181 vput(ndp->ni_dvp); 1182 if (ndp->ni_vp) 1183 vrele(ndp->ni_vp); 1184 } 1185 nfsvno_relpathbuf(ndp); 1186 return (error); 1187} 1188 1189/* 1190 * Do the fsync() appropriate for the commit. 1191 */ 1192int 1193nfsvno_fsync(struct vnode *vp, u_int64_t off, int cnt, struct ucred *cred, 1194 struct thread *td) 1195{ 1196 int error = 0; 1197 1198 if (cnt > MAX_COMMIT_COUNT) { 1199 /* 1200 * Give up and do the whole thing 1201 */ 1202 if (vp->v_object && 1203 (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) { 1204 VM_OBJECT_LOCK(vp->v_object); 1205 vm_object_page_clean(vp->v_object, 0, 0, OBJPC_SYNC); 1206 VM_OBJECT_UNLOCK(vp->v_object); 1207 } 1208 error = VOP_FSYNC(vp, MNT_WAIT, td); 1209 } else { 1210 /* 1211 * Locate and synchronously write any buffers that fall 1212 * into the requested range. Note: we are assuming that 1213 * f_iosize is a power of 2. 1214 */ 1215 int iosize = vp->v_mount->mnt_stat.f_iosize; 1216 int iomask = iosize - 1; 1217 struct bufobj *bo; 1218 daddr_t lblkno; 1219 1220 /* 1221 * Align to iosize boundry, super-align to page boundry. 1222 */ 1223 if (off & iomask) { 1224 cnt += off & iomask; 1225 off &= ~(u_quad_t)iomask; 1226 } 1227 if (off & PAGE_MASK) { 1228 cnt += off & PAGE_MASK; 1229 off &= ~(u_quad_t)PAGE_MASK; 1230 } 1231 lblkno = off / iosize; 1232 1233 if (vp->v_object && 1234 (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) { 1235 VM_OBJECT_LOCK(vp->v_object); 1236 vm_object_page_clean(vp->v_object, off / PAGE_SIZE, (cnt + PAGE_MASK) / PAGE_SIZE, OBJPC_SYNC); 1237 VM_OBJECT_UNLOCK(vp->v_object); 1238 } 1239 1240 bo = &vp->v_bufobj; 1241 BO_LOCK(bo); 1242 while (cnt > 0) { 1243 struct buf *bp; 1244 1245 /* 1246 * If we have a buffer and it is marked B_DELWRI we 1247 * have to lock and write it. Otherwise the prior 1248 * write is assumed to have already been committed. 1249 * 1250 * gbincore() can return invalid buffers now so we 1251 * have to check that bit as well (though B_DELWRI 1252 * should not be set if B_INVAL is set there could be 1253 * a race here since we haven't locked the buffer). 1254 */ 1255 if ((bp = gbincore(&vp->v_bufobj, lblkno)) != NULL) { 1256 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL | 1257 LK_INTERLOCK, BO_MTX(bo)) == ENOLCK) { 1258 BO_LOCK(bo); 1259 continue; /* retry */ 1260 } 1261 if ((bp->b_flags & (B_DELWRI|B_INVAL)) == 1262 B_DELWRI) { 1263 bremfree(bp); 1264 bp->b_flags &= ~B_ASYNC; 1265 bwrite(bp); 1266 ++nfs_commit_miss; 1267 } else 1268 BUF_UNLOCK(bp); 1269 BO_LOCK(bo); 1270 } 1271 ++nfs_commit_blks; 1272 if (cnt < iosize) 1273 break; 1274 cnt -= iosize; 1275 ++lblkno; 1276 } 1277 BO_UNLOCK(bo); 1278 } 1279 return (error); 1280} 1281 1282/* 1283 * Statfs vnode op. 1284 */ 1285int 1286nfsvno_statfs(struct vnode *vp, struct statfs *sf) 1287{ 1288 1289 return (VFS_STATFS(vp->v_mount, sf)); 1290} 1291 1292/* 1293 * Do the vnode op stuff for Open. Similar to nfsvno_createsub(), but 1294 * must handle nfsrv_opencheck() calls after any other access checks. 1295 */ 1296void 1297nfsvno_open(struct nfsrv_descript *nd, struct nameidata *ndp, 1298 nfsquad_t clientid, nfsv4stateid_t *stateidp, struct nfsstate *stp, 1299 int *exclusive_flagp, struct nfsvattr *nvap, int32_t *cverf, int create, 1300 NFSACL_T *aclp, nfsattrbit_t *attrbitp, struct ucred *cred, struct thread *p, 1301 struct nfsexstuff *exp, struct vnode **vpp) 1302{ 1303 struct vnode *vp = NULL; 1304 u_quad_t tempsize; 1305 struct nfsexstuff nes; 1306 1307 if (ndp->ni_vp == NULL) 1308 nd->nd_repstat = nfsrv_opencheck(clientid, 1309 stateidp, stp, NULL, nd, p, nd->nd_repstat); 1310 if (!nd->nd_repstat) { 1311 if (ndp->ni_vp == NULL) { 1312 vrele(ndp->ni_startdir); 1313 nd->nd_repstat = VOP_CREATE(ndp->ni_dvp, 1314 &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr); 1315 vput(ndp->ni_dvp); 1316 nfsvno_relpathbuf(ndp); 1317 if (!nd->nd_repstat) { 1318 if (*exclusive_flagp) { 1319 *exclusive_flagp = 0; 1320 NFSVNO_ATTRINIT(nvap); 1321 nvap->na_atime.tv_sec = cverf[0]; 1322 nvap->na_atime.tv_nsec = cverf[1]; 1323 nd->nd_repstat = VOP_SETATTR(ndp->ni_vp, 1324 &nvap->na_vattr, cred); 1325 } else { 1326 nfsrv_fixattr(nd, ndp->ni_vp, nvap, 1327 aclp, p, attrbitp, exp); 1328 } 1329 } 1330 vp = ndp->ni_vp; 1331 } else { 1332 if (ndp->ni_startdir) 1333 vrele(ndp->ni_startdir); 1334 nfsvno_relpathbuf(ndp); 1335 vp = ndp->ni_vp; 1336 if (create == NFSV4OPEN_CREATE) { 1337 if (ndp->ni_dvp == vp) 1338 vrele(ndp->ni_dvp); 1339 else 1340 vput(ndp->ni_dvp); 1341 } 1342 if (NFSVNO_ISSETSIZE(nvap) && vp->v_type == VREG) { 1343 if (ndp->ni_cnd.cn_flags & RDONLY) 1344 NFSVNO_SETEXRDONLY(&nes); 1345 else 1346 NFSVNO_EXINIT(&nes); 1347 nd->nd_repstat = nfsvno_accchk(vp, 1348 VWRITE, cred, &nes, p, 1349 NFSACCCHK_NOOVERRIDE, 1350 NFSACCCHK_VPISLOCKED, NULL); 1351 nd->nd_repstat = nfsrv_opencheck(clientid, 1352 stateidp, stp, vp, nd, p, nd->nd_repstat); 1353 if (!nd->nd_repstat) { 1354 tempsize = nvap->na_size; 1355 NFSVNO_ATTRINIT(nvap); 1356 nvap->na_size = tempsize; 1357 nd->nd_repstat = VOP_SETATTR(vp, 1358 &nvap->na_vattr, cred); 1359 } 1360 } else if (vp->v_type == VREG) { 1361 nd->nd_repstat = nfsrv_opencheck(clientid, 1362 stateidp, stp, vp, nd, p, nd->nd_repstat); 1363 } 1364 } 1365 } else { 1366 if (ndp->ni_cnd.cn_flags & HASBUF) 1367 nfsvno_relpathbuf(ndp); 1368 if (ndp->ni_startdir && create == NFSV4OPEN_CREATE) { 1369 vrele(ndp->ni_startdir); 1370 if (ndp->ni_dvp == ndp->ni_vp) 1371 vrele(ndp->ni_dvp); 1372 else 1373 vput(ndp->ni_dvp); 1374 if (ndp->ni_vp) 1375 vput(ndp->ni_vp); 1376 } 1377 } 1378 *vpp = vp; 1379} 1380 1381/* 1382 * Updates the file rev and sets the mtime and ctime 1383 * to the current clock time, returning the va_filerev and va_Xtime 1384 * values. 1385 */ 1386void 1387nfsvno_updfilerev(struct vnode *vp, struct nfsvattr *nvap, 1388 struct ucred *cred, struct thread *p) 1389{ 1390 struct vattr va; 1391 1392 VATTR_NULL(&va); 1393 getnanotime(&va.va_mtime); 1394 (void) VOP_SETATTR(vp, &va, cred); 1395 (void) nfsvno_getattr(vp, nvap, cred, p, 1); 1396} 1397 1398/* 1399 * Glue routine to nfsv4_fillattr(). 1400 */ 1401int 1402nfsvno_fillattr(struct nfsrv_descript *nd, struct vnode *vp, 1403 struct nfsvattr *nvap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp, 1404 struct ucred *cred, struct thread *p, int isdgram, int reterr) 1405{ 1406 int error; 1407 1408 error = nfsv4_fillattr(nd, vp, NULL, &nvap->na_vattr, fhp, rderror, 1409 attrbitp, cred, p, isdgram, reterr); 1410 return (error); 1411} 1412 1413/* Since the Readdir vnode ops vary, put the entire functions in here. */ 1414/* 1415 * nfs readdir service 1416 * - mallocs what it thinks is enough to read 1417 * count rounded up to a multiple of DIRBLKSIZ <= NFS_MAXREADDIR 1418 * - calls VOP_READDIR() 1419 * - loops around building the reply 1420 * if the output generated exceeds count break out of loop 1421 * The NFSM_CLGET macro is used here so that the reply will be packed 1422 * tightly in mbuf clusters. 1423 * - it trims out records with d_fileno == 0 1424 * this doesn't matter for Unix clients, but they might confuse clients 1425 * for other os'. 1426 * - it trims out records with d_type == DT_WHT 1427 * these cannot be seen through NFS (unless we extend the protocol) 1428 * The alternate call nfsrvd_readdirplus() does lookups as well. 1429 * PS: The NFS protocol spec. does not clarify what the "count" byte 1430 * argument is a count of.. just name strings and file id's or the 1431 * entire reply rpc or ... 1432 * I tried just file name and id sizes and it confused the Sun client, 1433 * so I am using the full rpc size now. The "paranoia.." comment refers 1434 * to including the status longwords that are not a part of the dir. 1435 * "entry" structures, but are in the rpc. 1436 */ 1437int 1438nfsrvd_readdir(struct nfsrv_descript *nd, int isdgram, 1439 struct vnode *vp, struct thread *p, struct nfsexstuff *exp) 1440{ 1441 struct dirent *dp; 1442 u_int32_t *tl; 1443 int dirlen; 1444 char *cpos, *cend, *rbuf; 1445 struct nfsvattr at; 1446 int nlen, error = 0, getret = 1; 1447 int siz, cnt, fullsiz, eofflag, ncookies; 1448 u_int64_t off, toff, verf; 1449 u_long *cookies = NULL, *cookiep; 1450 struct uio io; 1451 struct iovec iv; 1452 int not_zfs; 1453 1454 if (nd->nd_repstat) { 1455 nfsrv_postopattr(nd, getret, &at); 1456 return (0); 1457 } 1458 if (nd->nd_flag & ND_NFSV2) { 1459 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1460 off = fxdr_unsigned(u_quad_t, *tl++); 1461 } else { 1462 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1463 off = fxdr_hyper(tl); 1464 tl += 2; 1465 verf = fxdr_hyper(tl); 1466 tl += 2; 1467 } 1468 toff = off; 1469 cnt = fxdr_unsigned(int, *tl); 1470 if (cnt > NFS_SRVMAXDATA(nd) || cnt < 0) 1471 cnt = NFS_SRVMAXDATA(nd); 1472 siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); 1473 fullsiz = siz; 1474 if (nd->nd_flag & ND_NFSV3) { 1475 nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd->nd_cred, 1476 p, 1); 1477#if 0 1478 /* 1479 * va_filerev is not sufficient as a cookie verifier, 1480 * since it is not supposed to change when entries are 1481 * removed/added unless that offset cookies returned to 1482 * the client are no longer valid. 1483 */ 1484 if (!nd->nd_repstat && toff && verf != at.na_filerev) 1485 nd->nd_repstat = NFSERR_BAD_COOKIE; 1486#endif 1487 } 1488 if (nd->nd_repstat == 0 && cnt == 0) { 1489 if (nd->nd_flag & ND_NFSV2) 1490 /* NFSv2 does not have NFSERR_TOOSMALL */ 1491 nd->nd_repstat = EPERM; 1492 else 1493 nd->nd_repstat = NFSERR_TOOSMALL; 1494 } 1495 if (!nd->nd_repstat) 1496 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 1497 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, 1498 NFSACCCHK_VPISLOCKED, NULL); 1499 if (nd->nd_repstat) { 1500 vput(vp); 1501 if (nd->nd_flag & ND_NFSV3) 1502 nfsrv_postopattr(nd, getret, &at); 1503 return (0); 1504 } 1505 not_zfs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "zfs"); 1506 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 1507again: 1508 eofflag = 0; 1509 if (cookies) { 1510 free((caddr_t)cookies, M_TEMP); 1511 cookies = NULL; 1512 } 1513 1514 iv.iov_base = rbuf; 1515 iv.iov_len = siz; 1516 io.uio_iov = &iv; 1517 io.uio_iovcnt = 1; 1518 io.uio_offset = (off_t)off; 1519 io.uio_resid = siz; 1520 io.uio_segflg = UIO_SYSSPACE; 1521 io.uio_rw = UIO_READ; 1522 io.uio_td = NULL; 1523 nd->nd_repstat = VOP_READDIR(vp, &io, nd->nd_cred, &eofflag, &ncookies, 1524 &cookies); 1525 off = (u_int64_t)io.uio_offset; 1526 if (io.uio_resid) 1527 siz -= io.uio_resid; 1528 1529 if (!cookies && !nd->nd_repstat) 1530 nd->nd_repstat = NFSERR_PERM; 1531 if (nd->nd_flag & ND_NFSV3) { 1532 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 1533 if (!nd->nd_repstat) 1534 nd->nd_repstat = getret; 1535 } 1536 1537 /* 1538 * Handles the failed cases. nd->nd_repstat == 0 past here. 1539 */ 1540 if (nd->nd_repstat) { 1541 vput(vp); 1542 free((caddr_t)rbuf, M_TEMP); 1543 if (cookies) 1544 free((caddr_t)cookies, M_TEMP); 1545 if (nd->nd_flag & ND_NFSV3) 1546 nfsrv_postopattr(nd, getret, &at); 1547 return (0); 1548 } 1549 /* 1550 * If nothing read, return eof 1551 * rpc reply 1552 */ 1553 if (siz == 0) { 1554 vput(vp); 1555 if (nd->nd_flag & ND_NFSV2) { 1556 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1557 } else { 1558 nfsrv_postopattr(nd, getret, &at); 1559 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1560 txdr_hyper(at.na_filerev, tl); 1561 tl += 2; 1562 } 1563 *tl++ = newnfs_false; 1564 *tl = newnfs_true; 1565 FREE((caddr_t)rbuf, M_TEMP); 1566 FREE((caddr_t)cookies, M_TEMP); 1567 return (0); 1568 } 1569 1570 /* 1571 * Check for degenerate cases of nothing useful read. 1572 * If so go try again 1573 */ 1574 cpos = rbuf; 1575 cend = rbuf + siz; 1576 dp = (struct dirent *)cpos; 1577 cookiep = cookies; 1578 1579 /* 1580 * For some reason FreeBSD's ufs_readdir() chooses to back the 1581 * directory offset up to a block boundary, so it is necessary to 1582 * skip over the records that precede the requested offset. This 1583 * requires the assumption that file offset cookies monotonically 1584 * increase. 1585 * Since the offset cookies don't monotonically increase for ZFS, 1586 * this is not done when ZFS is the file system. 1587 */ 1588 while (cpos < cend && ncookies > 0 && 1589 (dp->d_fileno == 0 || dp->d_type == DT_WHT || 1590 (not_zfs != 0 && ((u_quad_t)(*cookiep)) <= toff))) { 1591 cpos += dp->d_reclen; 1592 dp = (struct dirent *)cpos; 1593 cookiep++; 1594 ncookies--; 1595 } 1596 if (cpos >= cend || ncookies == 0) { 1597 siz = fullsiz; 1598 toff = off; 1599 goto again; 1600 } 1601 vput(vp); 1602 1603 /* 1604 * dirlen is the size of the reply, including all XDR and must 1605 * not exceed cnt. For NFSv2, RFC1094 didn't clearly indicate 1606 * if the XDR should be included in "count", but to be safe, we do. 1607 * (Include the two booleans at the end of the reply in dirlen now.) 1608 */ 1609 if (nd->nd_flag & ND_NFSV3) { 1610 nfsrv_postopattr(nd, getret, &at); 1611 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1612 txdr_hyper(at.na_filerev, tl); 1613 dirlen = NFSX_V3POSTOPATTR + NFSX_VERF + 2 * NFSX_UNSIGNED; 1614 } else { 1615 dirlen = 2 * NFSX_UNSIGNED; 1616 } 1617 1618 /* Loop through the records and build reply */ 1619 while (cpos < cend && ncookies > 0) { 1620 nlen = dp->d_namlen; 1621 if (dp->d_fileno != 0 && dp->d_type != DT_WHT && 1622 nlen <= NFS_MAXNAMLEN) { 1623 if (nd->nd_flag & ND_NFSV3) 1624 dirlen += (6*NFSX_UNSIGNED + NFSM_RNDUP(nlen)); 1625 else 1626 dirlen += (4*NFSX_UNSIGNED + NFSM_RNDUP(nlen)); 1627 if (dirlen > cnt) { 1628 eofflag = 0; 1629 break; 1630 } 1631 1632 /* 1633 * Build the directory record xdr from 1634 * the dirent entry. 1635 */ 1636 if (nd->nd_flag & ND_NFSV3) { 1637 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1638 *tl++ = newnfs_true; 1639 *tl++ = 0; 1640 } else { 1641 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1642 *tl++ = newnfs_true; 1643 } 1644 *tl = txdr_unsigned(dp->d_fileno); 1645 (void) nfsm_strtom(nd, dp->d_name, nlen); 1646 if (nd->nd_flag & ND_NFSV3) { 1647 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1648 *tl++ = 0; 1649 } else 1650 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1651 *tl = txdr_unsigned(*cookiep); 1652 } 1653 cpos += dp->d_reclen; 1654 dp = (struct dirent *)cpos; 1655 cookiep++; 1656 ncookies--; 1657 } 1658 if (cpos < cend) 1659 eofflag = 0; 1660 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1661 *tl++ = newnfs_false; 1662 if (eofflag) 1663 *tl = newnfs_true; 1664 else 1665 *tl = newnfs_false; 1666 FREE((caddr_t)rbuf, M_TEMP); 1667 FREE((caddr_t)cookies, M_TEMP); 1668 return (0); 1669nfsmout: 1670 vput(vp); 1671 return (error); 1672} 1673 1674/* 1675 * Readdirplus for V3 and Readdir for V4. 1676 */ 1677int 1678nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram, 1679 struct vnode *vp, struct thread *p, struct nfsexstuff *exp) 1680{ 1681 struct dirent *dp; 1682 u_int32_t *tl; 1683 int dirlen; 1684 char *cpos, *cend, *rbuf; 1685 struct vnode *nvp; 1686 fhandle_t nfh; 1687 struct nfsvattr nva, at, *nvap = &nva; 1688 struct mbuf *mb0, *mb1; 1689 struct nfsreferral *refp; 1690 int nlen, r, error = 0, getret = 1, usevget = 1; 1691 int siz, cnt, fullsiz, eofflag, ncookies, entrycnt; 1692 caddr_t bpos0, bpos1; 1693 u_int64_t off, toff, verf; 1694 u_long *cookies = NULL, *cookiep; 1695 nfsattrbit_t attrbits, rderrbits, savbits; 1696 struct uio io; 1697 struct iovec iv; 1698 struct componentname cn; 1699 int not_zfs; 1700 1701 if (nd->nd_repstat) { 1702 nfsrv_postopattr(nd, getret, &at); 1703 return (0); 1704 } 1705 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 1706 off = fxdr_hyper(tl); 1707 toff = off; 1708 tl += 2; 1709 verf = fxdr_hyper(tl); 1710 tl += 2; 1711 siz = fxdr_unsigned(int, *tl++); 1712 cnt = fxdr_unsigned(int, *tl); 1713 1714 /* 1715 * Use the server's maximum data transfer size as the upper bound 1716 * on reply datalen. 1717 */ 1718 if (cnt > NFS_SRVMAXDATA(nd) || cnt < 0) 1719 cnt = NFS_SRVMAXDATA(nd); 1720 1721 /* 1722 * siz is a "hint" of how much directory information (name, fileid, 1723 * cookie) should be in the reply. At least one client "hints" 0, 1724 * so I set it to cnt for that case. I also round it up to the 1725 * next multiple of DIRBLKSIZ. 1726 */ 1727 if (siz <= 0) 1728 siz = cnt; 1729 siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); 1730 1731 if (nd->nd_flag & ND_NFSV4) { 1732 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1733 if (error) 1734 goto nfsmout; 1735 NFSSET_ATTRBIT(&savbits, &attrbits); 1736 NFSCLRNOTFILLABLE_ATTRBIT(&attrbits); 1737 NFSZERO_ATTRBIT(&rderrbits); 1738 NFSSETBIT_ATTRBIT(&rderrbits, NFSATTRBIT_RDATTRERROR); 1739 } else { 1740 NFSZERO_ATTRBIT(&attrbits); 1741 } 1742 fullsiz = siz; 1743 nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 1744 if (!nd->nd_repstat) { 1745 if (off && verf != at.na_filerev) { 1746 /* 1747 * va_filerev is not sufficient as a cookie verifier, 1748 * since it is not supposed to change when entries are 1749 * removed/added unless that offset cookies returned to 1750 * the client are no longer valid. 1751 */ 1752#if 0 1753 if (nd->nd_flag & ND_NFSV4) { 1754 nd->nd_repstat = NFSERR_NOTSAME; 1755 } else { 1756 nd->nd_repstat = NFSERR_BAD_COOKIE; 1757 } 1758#endif 1759 } else if ((nd->nd_flag & ND_NFSV4) && off == 0 && verf != 0) { 1760 nd->nd_repstat = NFSERR_BAD_COOKIE; 1761 } 1762 } 1763 if (!nd->nd_repstat && vp->v_type != VDIR) 1764 nd->nd_repstat = NFSERR_NOTDIR; 1765 if (!nd->nd_repstat && cnt == 0) 1766 nd->nd_repstat = NFSERR_TOOSMALL; 1767 if (!nd->nd_repstat) 1768 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 1769 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, 1770 NFSACCCHK_VPISLOCKED, NULL); 1771 if (nd->nd_repstat) { 1772 vput(vp); 1773 if (nd->nd_flag & ND_NFSV3) 1774 nfsrv_postopattr(nd, getret, &at); 1775 return (0); 1776 } 1777 not_zfs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "zfs"); 1778 1779 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 1780again: 1781 eofflag = 0; 1782 if (cookies) { 1783 free((caddr_t)cookies, M_TEMP); 1784 cookies = NULL; 1785 } 1786 1787 iv.iov_base = rbuf; 1788 iv.iov_len = siz; 1789 io.uio_iov = &iv; 1790 io.uio_iovcnt = 1; 1791 io.uio_offset = (off_t)off; 1792 io.uio_resid = siz; 1793 io.uio_segflg = UIO_SYSSPACE; 1794 io.uio_rw = UIO_READ; 1795 io.uio_td = NULL; 1796 nd->nd_repstat = VOP_READDIR(vp, &io, nd->nd_cred, &eofflag, &ncookies, 1797 &cookies); 1798 off = (u_int64_t)io.uio_offset; 1799 if (io.uio_resid) 1800 siz -= io.uio_resid; 1801 1802 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 1803 1804 if (!cookies && !nd->nd_repstat) 1805 nd->nd_repstat = NFSERR_PERM; 1806 if (!nd->nd_repstat) 1807 nd->nd_repstat = getret; 1808 if (nd->nd_repstat) { 1809 vput(vp); 1810 if (cookies) 1811 free((caddr_t)cookies, M_TEMP); 1812 free((caddr_t)rbuf, M_TEMP); 1813 if (nd->nd_flag & ND_NFSV3) 1814 nfsrv_postopattr(nd, getret, &at); 1815 return (0); 1816 } 1817 /* 1818 * If nothing read, return eof 1819 * rpc reply 1820 */ 1821 if (siz == 0) { 1822 vput(vp); 1823 if (nd->nd_flag & ND_NFSV3) 1824 nfsrv_postopattr(nd, getret, &at); 1825 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1826 txdr_hyper(at.na_filerev, tl); 1827 tl += 2; 1828 *tl++ = newnfs_false; 1829 *tl = newnfs_true; 1830 free((caddr_t)cookies, M_TEMP); 1831 free((caddr_t)rbuf, M_TEMP); 1832 return (0); 1833 } 1834 1835 /* 1836 * Check for degenerate cases of nothing useful read. 1837 * If so go try again 1838 */ 1839 cpos = rbuf; 1840 cend = rbuf + siz; 1841 dp = (struct dirent *)cpos; 1842 cookiep = cookies; 1843 1844 /* 1845 * For some reason FreeBSD's ufs_readdir() chooses to back the 1846 * directory offset up to a block boundary, so it is necessary to 1847 * skip over the records that precede the requested offset. This 1848 * requires the assumption that file offset cookies monotonically 1849 * increase. 1850 * Since the offset cookies don't monotonically increase for ZFS, 1851 * this is not done when ZFS is the file system. 1852 */ 1853 while (cpos < cend && ncookies > 0 && 1854 (dp->d_fileno == 0 || dp->d_type == DT_WHT || 1855 (not_zfs != 0 && ((u_quad_t)(*cookiep)) <= toff) || 1856 ((nd->nd_flag & ND_NFSV4) && 1857 ((dp->d_namlen == 1 && dp->d_name[0] == '.') || 1858 (dp->d_namlen==2 && dp->d_name[0]=='.' && dp->d_name[1]=='.'))))) { 1859 cpos += dp->d_reclen; 1860 dp = (struct dirent *)cpos; 1861 cookiep++; 1862 ncookies--; 1863 } 1864 if (cpos >= cend || ncookies == 0) { 1865 siz = fullsiz; 1866 toff = off; 1867 goto again; 1868 } 1869 VOP_UNLOCK(vp, 0); 1870 1871 /* 1872 * Save this position, in case there is an error before one entry 1873 * is created. 1874 */ 1875 mb0 = nd->nd_mb; 1876 bpos0 = nd->nd_bpos; 1877 1878 /* 1879 * Fill in the first part of the reply. 1880 * dirlen is the reply length in bytes and cannot exceed cnt. 1881 * (Include the two booleans at the end of the reply in dirlen now, 1882 * so we recognize when we have exceeded cnt.) 1883 */ 1884 if (nd->nd_flag & ND_NFSV3) { 1885 dirlen = NFSX_V3POSTOPATTR + NFSX_VERF + 2 * NFSX_UNSIGNED; 1886 nfsrv_postopattr(nd, getret, &at); 1887 } else { 1888 dirlen = NFSX_VERF + 2 * NFSX_UNSIGNED; 1889 } 1890 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 1891 txdr_hyper(at.na_filerev, tl); 1892 1893 /* 1894 * Save this position, in case there is an empty reply needed. 1895 */ 1896 mb1 = nd->nd_mb; 1897 bpos1 = nd->nd_bpos; 1898 1899 /* Loop through the records and build reply */ 1900 entrycnt = 0; 1901 while (cpos < cend && ncookies > 0 && dirlen < cnt) { 1902 nlen = dp->d_namlen; 1903 if (dp->d_fileno != 0 && dp->d_type != DT_WHT && 1904 nlen <= NFS_MAXNAMLEN && 1905 ((nd->nd_flag & ND_NFSV3) || nlen > 2 || 1906 (nlen==2 && (dp->d_name[0]!='.' || dp->d_name[1]!='.')) 1907 || (nlen == 1 && dp->d_name[0] != '.'))) { 1908 /* 1909 * Save the current position in the reply, in case 1910 * this entry exceeds cnt. 1911 */ 1912 mb1 = nd->nd_mb; 1913 bpos1 = nd->nd_bpos; 1914 1915 /* 1916 * For readdir_and_lookup get the vnode using 1917 * the file number. 1918 */ 1919 nvp = NULL; 1920 refp = NULL; 1921 r = 0; 1922 if ((nd->nd_flag & ND_NFSV3) || 1923 NFSNONZERO_ATTRBIT(&savbits)) { 1924 if (nd->nd_flag & ND_NFSV4) 1925 refp = nfsv4root_getreferral(NULL, 1926 vp, dp->d_fileno); 1927 if (refp == NULL) { 1928 if (usevget) 1929 r = VFS_VGET(vp->v_mount, 1930 dp->d_fileno, LK_SHARED, 1931 &nvp); 1932 else 1933 r = EOPNOTSUPP; 1934 if (r == EOPNOTSUPP) { 1935 if (usevget) { 1936 usevget = 0; 1937 cn.cn_nameiop = LOOKUP; 1938 cn.cn_lkflags = 1939 LK_SHARED | 1940 LK_RETRY; 1941 cn.cn_cred = 1942 nd->nd_cred; 1943 cn.cn_thread = p; 1944 } 1945 cn.cn_nameptr = dp->d_name; 1946 cn.cn_namelen = nlen; 1947 cn.cn_flags = ISLASTCN | 1948 NOFOLLOW | LOCKLEAF | 1949 MPSAFE; 1950 if (nlen == 2 && 1951 dp->d_name[0] == '.' && 1952 dp->d_name[1] == '.') 1953 cn.cn_flags |= 1954 ISDOTDOT; 1955 if (vn_lock(vp, LK_SHARED) 1956 != 0) { 1957 nd->nd_repstat = EPERM; 1958 break; 1959 } 1960 if ((vp->v_vflag & VV_ROOT) != 0 1961 && (cn.cn_flags & ISDOTDOT) 1962 != 0) { 1963 vref(vp); 1964 nvp = vp; 1965 r = 0; 1966 } else 1967 r = VOP_LOOKUP(vp, &nvp, 1968 &cn); 1969 } 1970 } 1971 if (!r) { 1972 if (refp == NULL && 1973 ((nd->nd_flag & ND_NFSV3) || 1974 NFSNONZERO_ATTRBIT(&attrbits))) { 1975 r = nfsvno_getfh(nvp, &nfh, p); 1976 if (!r) 1977 r = nfsvno_getattr(nvp, nvap, 1978 nd->nd_cred, p, 1); 1979 } 1980 } else { 1981 nvp = NULL; 1982 } 1983 if (r) { 1984 if (!NFSISSET_ATTRBIT(&attrbits, 1985 NFSATTRBIT_RDATTRERROR)) { 1986 if (nvp != NULL) 1987 vput(nvp); 1988 nd->nd_repstat = r; 1989 break; 1990 } 1991 } 1992 } 1993 1994 /* 1995 * Build the directory record xdr 1996 */ 1997 if (nd->nd_flag & ND_NFSV3) { 1998 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1999 *tl++ = newnfs_true; 2000 *tl++ = 0; 2001 *tl = txdr_unsigned(dp->d_fileno); 2002 dirlen += nfsm_strtom(nd, dp->d_name, nlen); 2003 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2004 *tl++ = 0; 2005 *tl = txdr_unsigned(*cookiep); 2006 nfsrv_postopattr(nd, 0, nvap); 2007 dirlen += nfsm_fhtom(nd,(u_int8_t *)&nfh,0,1); 2008 dirlen += (5*NFSX_UNSIGNED+NFSX_V3POSTOPATTR); 2009 if (nvp != NULL) 2010 vput(nvp); 2011 } else { 2012 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2013 *tl++ = newnfs_true; 2014 *tl++ = 0; 2015 *tl = txdr_unsigned(*cookiep); 2016 dirlen += nfsm_strtom(nd, dp->d_name, nlen); 2017 if (nvp != NULL) 2018 VOP_UNLOCK(nvp, 0); 2019 if (refp != NULL) { 2020 dirlen += nfsrv_putreferralattr(nd, 2021 &savbits, refp, 0, 2022 &nd->nd_repstat); 2023 if (nd->nd_repstat) { 2024 if (nvp != NULL) 2025 vrele(nvp); 2026 break; 2027 } 2028 } else if (r) { 2029 dirlen += nfsvno_fillattr(nd, nvp, nvap, 2030 &nfh, r, &rderrbits, nd->nd_cred, 2031 p, isdgram, 0); 2032 } else { 2033 dirlen += nfsvno_fillattr(nd, nvp, nvap, 2034 &nfh, r, &attrbits, nd->nd_cred, 2035 p, isdgram, 0); 2036 } 2037 if (nvp != NULL) 2038 vrele(nvp); 2039 dirlen += (3 * NFSX_UNSIGNED); 2040 } 2041 if (dirlen <= cnt) 2042 entrycnt++; 2043 } 2044 cpos += dp->d_reclen; 2045 dp = (struct dirent *)cpos; 2046 cookiep++; 2047 ncookies--; 2048 } 2049 vrele(vp); 2050 2051 /* 2052 * If dirlen > cnt, we must strip off the last entry. If that 2053 * results in an empty reply, report NFSERR_TOOSMALL. 2054 */ 2055 if (dirlen > cnt || nd->nd_repstat) { 2056 if (!nd->nd_repstat && entrycnt == 0) 2057 nd->nd_repstat = NFSERR_TOOSMALL; 2058 if (nd->nd_repstat) 2059 newnfs_trimtrailing(nd, mb0, bpos0); 2060 else 2061 newnfs_trimtrailing(nd, mb1, bpos1); 2062 eofflag = 0; 2063 } else if (cpos < cend) 2064 eofflag = 0; 2065 if (!nd->nd_repstat) { 2066 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2067 *tl++ = newnfs_false; 2068 if (eofflag) 2069 *tl = newnfs_true; 2070 else 2071 *tl = newnfs_false; 2072 } 2073 FREE((caddr_t)cookies, M_TEMP); 2074 FREE((caddr_t)rbuf, M_TEMP); 2075 return (0); 2076nfsmout: 2077 vput(vp); 2078 return (error); 2079} 2080 2081/* 2082 * Get the settable attributes out of the mbuf list. 2083 * (Return 0 or EBADRPC) 2084 */ 2085int 2086nfsrv_sattr(struct nfsrv_descript *nd, struct nfsvattr *nvap, 2087 nfsattrbit_t *attrbitp, NFSACL_T *aclp, struct thread *p) 2088{ 2089 u_int32_t *tl; 2090 struct nfsv2_sattr *sp; 2091 struct timeval curtime; 2092 int error = 0, toclient = 0; 2093 2094 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) { 2095 case ND_NFSV2: 2096 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 2097 /* 2098 * Some old clients didn't fill in the high order 16bits. 2099 * --> check the low order 2 bytes for 0xffff 2100 */ 2101 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 2102 nvap->na_mode = nfstov_mode(sp->sa_mode); 2103 if (sp->sa_uid != newnfs_xdrneg1) 2104 nvap->na_uid = fxdr_unsigned(uid_t, sp->sa_uid); 2105 if (sp->sa_gid != newnfs_xdrneg1) 2106 nvap->na_gid = fxdr_unsigned(gid_t, sp->sa_gid); 2107 if (sp->sa_size != newnfs_xdrneg1) 2108 nvap->na_size = fxdr_unsigned(u_quad_t, sp->sa_size); 2109 if (sp->sa_atime.nfsv2_sec != newnfs_xdrneg1) { 2110#ifdef notyet 2111 fxdr_nfsv2time(&sp->sa_atime, &nvap->na_atime); 2112#else 2113 nvap->na_atime.tv_sec = 2114 fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec); 2115 nvap->na_atime.tv_nsec = 0; 2116#endif 2117 } 2118 if (sp->sa_mtime.nfsv2_sec != newnfs_xdrneg1) 2119 fxdr_nfsv2time(&sp->sa_mtime, &nvap->na_mtime); 2120 break; 2121 case ND_NFSV3: 2122 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2123 if (*tl == newnfs_true) { 2124 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2125 nvap->na_mode = nfstov_mode(*tl); 2126 } 2127 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2128 if (*tl == newnfs_true) { 2129 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2130 nvap->na_uid = fxdr_unsigned(uid_t, *tl); 2131 } 2132 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2133 if (*tl == newnfs_true) { 2134 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2135 nvap->na_gid = fxdr_unsigned(gid_t, *tl); 2136 } 2137 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2138 if (*tl == newnfs_true) { 2139 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2140 nvap->na_size = fxdr_hyper(tl); 2141 } 2142 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2143 switch (fxdr_unsigned(int, *tl)) { 2144 case NFSV3SATTRTIME_TOCLIENT: 2145 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2146 fxdr_nfsv3time(tl, &nvap->na_atime); 2147 toclient = 1; 2148 break; 2149 case NFSV3SATTRTIME_TOSERVER: 2150 NFSGETTIME(&curtime); 2151 nvap->na_atime.tv_sec = curtime.tv_sec; 2152 nvap->na_atime.tv_nsec = curtime.tv_usec * 1000; 2153 nvap->na_vaflags |= VA_UTIMES_NULL; 2154 break; 2155 }; 2156 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2157 switch (fxdr_unsigned(int, *tl)) { 2158 case NFSV3SATTRTIME_TOCLIENT: 2159 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2160 fxdr_nfsv3time(tl, &nvap->na_mtime); 2161 nvap->na_vaflags &= ~VA_UTIMES_NULL; 2162 break; 2163 case NFSV3SATTRTIME_TOSERVER: 2164 NFSGETTIME(&curtime); 2165 nvap->na_mtime.tv_sec = curtime.tv_sec; 2166 nvap->na_mtime.tv_nsec = curtime.tv_usec * 1000; 2167 if (!toclient) 2168 nvap->na_vaflags |= VA_UTIMES_NULL; 2169 break; 2170 }; 2171 break; 2172 case ND_NFSV4: 2173 error = nfsv4_sattr(nd, nvap, attrbitp, aclp, p); 2174 }; 2175nfsmout: 2176 return (error); 2177} 2178 2179/* 2180 * Handle the setable attributes for V4. 2181 * Returns NFSERR_BADXDR if it can't be parsed, 0 otherwise. 2182 */ 2183int 2184nfsv4_sattr(struct nfsrv_descript *nd, struct nfsvattr *nvap, 2185 nfsattrbit_t *attrbitp, NFSACL_T *aclp, struct thread *p) 2186{ 2187 u_int32_t *tl; 2188 int attrsum = 0; 2189 int i, j; 2190 int error, attrsize, bitpos, aclsize, aceerr, retnotsup = 0; 2191 int toclient = 0; 2192 u_char *cp, namestr[NFSV4_SMALLSTR + 1]; 2193 uid_t uid; 2194 gid_t gid; 2195 struct timeval curtime; 2196 2197 error = nfsrv_getattrbits(nd, attrbitp, NULL, &retnotsup); 2198 if (error) 2199 return (error); 2200 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2201 attrsize = fxdr_unsigned(int, *tl); 2202 2203 /* 2204 * Loop around getting the setable attributes. If an unsupported 2205 * one is found, set nd_repstat == NFSERR_ATTRNOTSUPP and return. 2206 */ 2207 if (retnotsup) { 2208 nd->nd_repstat = NFSERR_ATTRNOTSUPP; 2209 bitpos = NFSATTRBIT_MAX; 2210 } else { 2211 bitpos = 0; 2212 } 2213 for (; bitpos < NFSATTRBIT_MAX; bitpos++) { 2214 if (attrsum > attrsize) { 2215 error = NFSERR_BADXDR; 2216 goto nfsmout; 2217 } 2218 if (NFSISSET_ATTRBIT(attrbitp, bitpos)) 2219 switch (bitpos) { 2220 case NFSATTRBIT_SIZE: 2221 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 2222 nvap->na_size = fxdr_hyper(tl); 2223 attrsum += NFSX_HYPER; 2224 break; 2225 case NFSATTRBIT_ACL: 2226 error = nfsrv_dissectacl(nd, aclp, &aceerr, &aclsize, 2227 p); 2228 if (error) 2229 goto nfsmout; 2230 if (aceerr && !nd->nd_repstat) 2231 nd->nd_repstat = NFSERR_ATTRNOTSUPP; 2232 attrsum += aclsize; 2233 break; 2234 case NFSATTRBIT_ARCHIVE: 2235 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2236 if (!nd->nd_repstat) 2237 nd->nd_repstat = NFSERR_ATTRNOTSUPP; 2238 attrsum += NFSX_UNSIGNED; 2239 break; 2240 case NFSATTRBIT_HIDDEN: 2241 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2242 if (!nd->nd_repstat) 2243 nd->nd_repstat = NFSERR_ATTRNOTSUPP; 2244 attrsum += NFSX_UNSIGNED; 2245 break; 2246 case NFSATTRBIT_MIMETYPE: 2247 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2248 i = fxdr_unsigned(int, *tl); 2249 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 2250 if (error) 2251 goto nfsmout; 2252 if (!nd->nd_repstat) 2253 nd->nd_repstat = NFSERR_ATTRNOTSUPP; 2254 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i)); 2255 break; 2256 case NFSATTRBIT_MODE: 2257 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2258 nvap->na_mode = nfstov_mode(*tl); 2259 attrsum += NFSX_UNSIGNED; 2260 break; 2261 case NFSATTRBIT_OWNER: 2262 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2263 j = fxdr_unsigned(int, *tl); 2264 if (j < 0) 2265 return (NFSERR_BADXDR); 2266 if (j > NFSV4_SMALLSTR) 2267 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 2268 else 2269 cp = namestr; 2270 error = nfsrv_mtostr(nd, cp, j); 2271 if (error) { 2272 if (j > NFSV4_SMALLSTR) 2273 free(cp, M_NFSSTRING); 2274 return (error); 2275 } 2276 if (!nd->nd_repstat) { 2277 nd->nd_repstat = nfsv4_strtouid(cp,j,&uid,p); 2278 if (!nd->nd_repstat) 2279 nvap->na_uid = uid; 2280 } 2281 if (j > NFSV4_SMALLSTR) 2282 free(cp, M_NFSSTRING); 2283 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 2284 break; 2285 case NFSATTRBIT_OWNERGROUP: 2286 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2287 j = fxdr_unsigned(int, *tl); 2288 if (j < 0) 2289 return (NFSERR_BADXDR); 2290 if (j > NFSV4_SMALLSTR) 2291 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 2292 else 2293 cp = namestr; 2294 error = nfsrv_mtostr(nd, cp, j); 2295 if (error) { 2296 if (j > NFSV4_SMALLSTR) 2297 free(cp, M_NFSSTRING); 2298 return (error); 2299 } 2300 if (!nd->nd_repstat) { 2301 nd->nd_repstat = nfsv4_strtogid(cp,j,&gid,p); 2302 if (!nd->nd_repstat) 2303 nvap->na_gid = gid; 2304 } 2305 if (j > NFSV4_SMALLSTR) 2306 free(cp, M_NFSSTRING); 2307 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 2308 break; 2309 case NFSATTRBIT_SYSTEM: 2310 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2311 if (!nd->nd_repstat) 2312 nd->nd_repstat = NFSERR_ATTRNOTSUPP; 2313 attrsum += NFSX_UNSIGNED; 2314 break; 2315 case NFSATTRBIT_TIMEACCESSSET: 2316 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2317 attrsum += NFSX_UNSIGNED; 2318 if (fxdr_unsigned(int, *tl)==NFSV4SATTRTIME_TOCLIENT) { 2319 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 2320 fxdr_nfsv4time(tl, &nvap->na_atime); 2321 toclient = 1; 2322 attrsum += NFSX_V4TIME; 2323 } else { 2324 NFSGETTIME(&curtime); 2325 nvap->na_atime.tv_sec = curtime.tv_sec; 2326 nvap->na_atime.tv_nsec = curtime.tv_usec * 1000; 2327 nvap->na_vaflags |= VA_UTIMES_NULL; 2328 } 2329 break; 2330 case NFSATTRBIT_TIMEBACKUP: 2331 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 2332 if (!nd->nd_repstat) 2333 nd->nd_repstat = NFSERR_ATTRNOTSUPP; 2334 attrsum += NFSX_V4TIME; 2335 break; 2336 case NFSATTRBIT_TIMECREATE: 2337 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 2338 if (!nd->nd_repstat) 2339 nd->nd_repstat = NFSERR_ATTRNOTSUPP; 2340 attrsum += NFSX_V4TIME; 2341 break; 2342 case NFSATTRBIT_TIMEMODIFYSET: 2343 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2344 attrsum += NFSX_UNSIGNED; 2345 if (fxdr_unsigned(int, *tl)==NFSV4SATTRTIME_TOCLIENT) { 2346 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 2347 fxdr_nfsv4time(tl, &nvap->na_mtime); 2348 nvap->na_vaflags &= ~VA_UTIMES_NULL; 2349 attrsum += NFSX_V4TIME; 2350 } else { 2351 NFSGETTIME(&curtime); 2352 nvap->na_mtime.tv_sec = curtime.tv_sec; 2353 nvap->na_mtime.tv_nsec = curtime.tv_usec * 1000; 2354 if (!toclient) 2355 nvap->na_vaflags |= VA_UTIMES_NULL; 2356 } 2357 break; 2358 default: 2359 nd->nd_repstat = NFSERR_ATTRNOTSUPP; 2360 /* 2361 * set bitpos so we drop out of the loop. 2362 */ 2363 bitpos = NFSATTRBIT_MAX; 2364 break; 2365 }; 2366 } 2367 2368 /* 2369 * some clients pad the attrlist, so we need to skip over the 2370 * padding. 2371 */ 2372 if (attrsum > attrsize) { 2373 error = NFSERR_BADXDR; 2374 } else { 2375 attrsize = NFSM_RNDUP(attrsize); 2376 if (attrsum < attrsize) 2377 error = nfsm_advance(nd, attrsize - attrsum, -1); 2378 } 2379nfsmout: 2380 return (error); 2381} 2382 2383/* 2384 * Check/setup export credentials. 2385 */ 2386int 2387nfsd_excred(struct nfsrv_descript *nd, struct nfsexstuff *exp, 2388 struct ucred *credanon) 2389{ 2390 int error = 0; 2391 2392 /* 2393 * Check/setup credentials. 2394 */ 2395 if (nd->nd_flag & ND_GSS) 2396 exp->nes_exflag &= ~MNT_EXPORTANON; 2397 2398 /* 2399 * Check to see if the operation is allowed for this security flavor. 2400 * RFC2623 suggests that the NFSv3 Fsinfo RPC be allowed to 2401 * AUTH_NONE or AUTH_SYS for file systems requiring RPCSEC_GSS. 2402 * Also, allow Secinfo, so that it can acquire the correct flavor(s). 2403 */ 2404 if (nfsvno_testexp(nd, exp) && 2405 nd->nd_procnum != NFSV4OP_SECINFO && 2406 nd->nd_procnum != NFSPROC_FSINFO) { 2407 if (nd->nd_flag & ND_NFSV4) 2408 error = NFSERR_WRONGSEC; 2409 else 2410 error = (NFSERR_AUTHERR | AUTH_TOOWEAK); 2411 return (error); 2412 } 2413 2414 /* 2415 * Check to see if the file system is exported V4 only. 2416 */ 2417 if (NFSVNO_EXV4ONLY(exp) && !(nd->nd_flag & ND_NFSV4)) 2418 return (NFSERR_PROGNOTV4); 2419 2420 /* 2421 * Now, map the user credentials. 2422 * (Note that ND_AUTHNONE will only be set for an NFSv3 2423 * Fsinfo RPC. If set for anything else, this code might need 2424 * to change.) 2425 */ 2426 if (NFSVNO_EXPORTED(exp) && 2427 ((!(nd->nd_flag & ND_GSS) && nd->nd_cred->cr_uid == 0) || 2428 NFSVNO_EXPORTANON(exp) || 2429 (nd->nd_flag & ND_AUTHNONE))) { 2430 nd->nd_cred->cr_uid = credanon->cr_uid; 2431 nd->nd_cred->cr_gid = credanon->cr_gid; 2432 crsetgroups(nd->nd_cred, credanon->cr_ngroups, 2433 credanon->cr_groups); 2434 } 2435 return (0); 2436} 2437 2438/* 2439 * Check exports. 2440 */ 2441int 2442nfsvno_checkexp(struct mount *mp, struct sockaddr *nam, struct nfsexstuff *exp, 2443 struct ucred **credp) 2444{ 2445 int i, error, *secflavors; 2446 2447 error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp, 2448 &exp->nes_numsecflavor, &secflavors); 2449 if (error) { 2450 if (nfs_rootfhset) { 2451 exp->nes_exflag = 0; 2452 exp->nes_numsecflavor = 0; 2453 error = 0; 2454 } 2455 } else { 2456 /* Copy the security flavors. */ 2457 for (i = 0; i < exp->nes_numsecflavor; i++) 2458 exp->nes_secflavors[i] = secflavors[i]; 2459 } 2460 return (error); 2461} 2462 2463/* 2464 * Get a vnode for a file handle and export stuff. 2465 */ 2466int 2467nfsvno_fhtovp(struct mount *mp, fhandle_t *fhp, struct sockaddr *nam, 2468 int lktype, struct vnode **vpp, struct nfsexstuff *exp, 2469 struct ucred **credp) 2470{ 2471 int i, error, *secflavors; 2472 2473 *credp = NULL; 2474 exp->nes_numsecflavor = 0; 2475 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 2476 if (error != 0) 2477 /* Make sure the server replies ESTALE to the client. */ 2478 error = ESTALE; 2479 if (nam && !error) { 2480 error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp, 2481 &exp->nes_numsecflavor, &secflavors); 2482 if (error) { 2483 if (nfs_rootfhset) { 2484 exp->nes_exflag = 0; 2485 exp->nes_numsecflavor = 0; 2486 error = 0; 2487 } else { 2488 vput(*vpp); 2489 } 2490 } else { 2491 /* Copy the security flavors. */ 2492 for (i = 0; i < exp->nes_numsecflavor; i++) 2493 exp->nes_secflavors[i] = secflavors[i]; 2494 } 2495 } 2496 if (error == 0 && lktype == LK_SHARED) 2497 /* 2498 * It would be much better to pass lktype to VFS_FHTOVP(), 2499 * but this will have to do until VFS_FHTOVP() has a lock 2500 * type argument like VFS_VGET(). 2501 */ 2502 vn_lock(*vpp, LK_DOWNGRADE | LK_RETRY); 2503 return (error); 2504} 2505 2506/* 2507 * Do the pathconf vnode op. 2508 */ 2509int 2510nfsvno_pathconf(struct vnode *vp, int flag, register_t *retf, 2511 struct ucred *cred, struct thread *p) 2512{ 2513 int error; 2514 2515 error = VOP_PATHCONF(vp, flag, retf); 2516 return (error); 2517} 2518 2519/* 2520 * nfsd_fhtovp() - convert a fh to a vnode ptr 2521 * - look up fsid in mount list (if not found ret error) 2522 * - get vp and export rights by calling nfsvno_fhtovp() 2523 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 2524 * for AUTH_SYS 2525 * Also handle getting the Giant lock for the file system, 2526 * as required: 2527 * - if same mount point as *mpp 2528 * do nothing 2529 * else if *mpp == NULL 2530 * if already locked 2531 * leave it locked 2532 * else 2533 * call VFS_LOCK_GIANT() 2534 * else 2535 * if already locked 2536 * unlock Giant 2537 * call VFS_LOCK_GIANT() 2538 */ 2539void 2540nfsd_fhtovp(struct nfsrv_descript *nd, struct nfsrvfh *nfp, int lktype, 2541 struct vnode **vpp, struct nfsexstuff *exp, 2542 struct mount **mpp, int startwrite, struct thread *p) 2543{ 2544 struct mount *mp; 2545 struct ucred *credanon; 2546 fhandle_t *fhp; 2547 2548 fhp = (fhandle_t *)nfp->nfsrvfh_data; 2549 /* 2550 * Check for the special case of the nfsv4root_fh. 2551 */ 2552 mp = vfs_getvfs(&fhp->fh_fsid); 2553 if (!mp) { 2554 *vpp = NULL; 2555 nd->nd_repstat = ESTALE; 2556 if (*mpp && exp->nes_vfslocked) 2557 VFS_UNLOCK_GIANT(*mpp); 2558 *mpp = NULL; 2559 exp->nes_vfslocked = 0; 2560 return; 2561 } 2562 2563 /* 2564 * Now, handle Giant for the file system. 2565 */ 2566 if (*mpp != NULL && *mpp != mp && exp->nes_vfslocked) { 2567 VFS_UNLOCK_GIANT(*mpp); 2568 exp->nes_vfslocked = 0; 2569 } 2570 if (!exp->nes_vfslocked && *mpp != mp) 2571 exp->nes_vfslocked = VFS_LOCK_GIANT(mp); 2572 2573 *mpp = mp; 2574 if (startwrite) 2575 vn_start_write(NULL, mpp, V_WAIT); 2576 2577 nd->nd_repstat = nfsvno_fhtovp(mp, fhp, nd->nd_nam, lktype, vpp, exp, 2578 &credanon); 2579 2580 /* 2581 * For NFSv4 without a pseudo root fs, unexported file handles 2582 * can be returned, so that Lookup works everywhere. 2583 */ 2584 if (!nd->nd_repstat && exp->nes_exflag == 0 && 2585 !(nd->nd_flag & ND_NFSV4)) { 2586 vput(*vpp); 2587 nd->nd_repstat = EACCES; 2588 } 2589 2590 /* 2591 * Personally, I've never seen any point in requiring a 2592 * reserved port#, since only in the rare case where the 2593 * clients are all boxes with secure system priviledges, 2594 * does it provide any enhanced security, but... some people 2595 * believe it to be useful and keep putting this code back in. 2596 * (There is also some "security checker" out there that 2597 * complains if the nfs server doesn't enforce this.) 2598 * However, note the following: 2599 * RFC3530 (NFSv4) specifies that a reserved port# not be 2600 * required. 2601 * RFC2623 recommends that, if a reserved port# is checked for, 2602 * that there be a way to turn that off--> ifdef'd. 2603 */ 2604#ifdef NFS_REQRSVPORT 2605 if (!nd->nd_repstat) { 2606 struct sockaddr_in *saddr; 2607 struct sockaddr_in6 *saddr6; 2608 2609 saddr = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *); 2610 saddr6 = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in6 *); 2611 if (!(nd->nd_flag & ND_NFSV4) && 2612 ((saddr->sin_family == AF_INET && 2613 ntohs(saddr->sin_port) >= IPPORT_RESERVED) || 2614 (saddr6->sin6_family == AF_INET6 && 2615 ntohs(saddr6->sin6_port) >= IPPORT_RESERVED))) { 2616 vput(*vpp); 2617 nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); 2618 } 2619 } 2620#endif /* NFS_REQRSVPORT */ 2621 2622 /* 2623 * Check/setup credentials. 2624 */ 2625 if (!nd->nd_repstat) { 2626 nd->nd_saveduid = nd->nd_cred->cr_uid; 2627 nd->nd_repstat = nfsd_excred(nd, exp, credanon); 2628 if (nd->nd_repstat) 2629 vput(*vpp); 2630 } 2631 if (credanon != NULL) 2632 crfree(credanon); 2633 if (nd->nd_repstat) { 2634 if (startwrite) 2635 vn_finished_write(mp); 2636 if (exp->nes_vfslocked) { 2637 VFS_UNLOCK_GIANT(mp); 2638 exp->nes_vfslocked = 0; 2639 } 2640 vfs_rel(mp); 2641 *vpp = NULL; 2642 *mpp = NULL; 2643 } else { 2644 vfs_rel(mp); 2645 } 2646} 2647 2648/* 2649 * glue for fp. 2650 */ 2651int 2652fp_getfvp(struct thread *p, int fd, struct file **fpp, struct vnode **vpp) 2653{ 2654 struct filedesc *fdp; 2655 struct file *fp; 2656 2657 fdp = p->td_proc->p_fd; 2658 if (fd >= fdp->fd_nfiles || 2659 (fp = fdp->fd_ofiles[fd]) == NULL) 2660 return (EBADF); 2661 *fpp = fp; 2662 return (0); 2663} 2664 2665/* 2666 * Called from nfssvc() to update the exports list. Just call 2667 * vfs_export(). This has to be done, since the v4 root fake fs isn't 2668 * in the mount list. 2669 */ 2670int 2671nfsrv_v4rootexport(void *argp, struct ucred *cred, struct thread *p) 2672{ 2673 struct nfsex_args *nfsexargp = (struct nfsex_args *)argp; 2674 int error; 2675 struct nameidata nd; 2676 fhandle_t fh; 2677 2678 error = vfs_export(&nfsv4root_mnt, &nfsexargp->export); 2679 if ((nfsexargp->export.ex_flags & MNT_DELEXPORT) != 0) 2680 nfs_rootfhset = 0; 2681 else if (error == 0) { 2682 if (nfsexargp->fspec == NULL) 2683 return (EPERM); 2684 /* 2685 * If fspec != NULL, this is the v4root path. 2686 */ 2687 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_USERSPACE, 2688 nfsexargp->fspec, p); 2689 if ((error = namei(&nd)) != 0) 2690 return (error); 2691 error = nfsvno_getfh(nd.ni_vp, &fh, p); 2692 vrele(nd.ni_vp); 2693 if (!error) { 2694 nfs_rootfh.nfsrvfh_len = NFSX_MYFH; 2695 NFSBCOPY((caddr_t)&fh, 2696 nfs_rootfh.nfsrvfh_data, 2697 sizeof (fhandle_t)); 2698 nfs_rootfhset = 1; 2699 } 2700 } 2701 return (error); 2702} 2703 2704/* 2705 * Get the tcp socket sequence numbers we need. 2706 * (Maybe this should be moved to the tcp sources?) 2707 */ 2708int 2709nfsrv_getsocksndseq(struct socket *so, tcp_seq *maxp, tcp_seq *unap) 2710{ 2711 struct inpcb *inp; 2712 struct tcpcb *tp; 2713 2714 inp = sotoinpcb(so); 2715 KASSERT(inp != NULL, ("nfsrv_getsocksndseq: inp == NULL")); 2716 INP_RLOCK(inp); 2717 if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 2718 INP_RUNLOCK(inp); 2719 return (EPIPE); 2720 } 2721 tp = intotcpcb(inp); 2722 if (tp->t_state != TCPS_ESTABLISHED) { 2723 INP_RUNLOCK(inp); 2724 return (EPIPE); 2725 } 2726 *maxp = tp->snd_max; 2727 *unap = tp->snd_una; 2728 INP_RUNLOCK(inp); 2729 return (0); 2730} 2731 2732/* 2733 * This function needs to test to see if the system is near its limit 2734 * for memory allocation via malloc() or mget() and return True iff 2735 * either of these resources are near their limit. 2736 * XXX (For now, this is just a stub.) 2737 */ 2738int nfsrv_testmalloclimit = 0; 2739int 2740nfsrv_mallocmget_limit(void) 2741{ 2742 static int printmesg = 0; 2743 static int testval = 1; 2744 2745 if (nfsrv_testmalloclimit && (testval++ % 1000) == 0) { 2746 if ((printmesg++ % 100) == 0) 2747 printf("nfsd: malloc/mget near limit\n"); 2748 return (1); 2749 } 2750 return (0); 2751} 2752 2753/* 2754 * BSD specific initialization of a mount point. 2755 */ 2756void 2757nfsd_mntinit(void) 2758{ 2759 static int inited = 0; 2760 2761 if (inited) 2762 return; 2763 inited = 1; 2764 nfsv4root_mnt.mnt_flag = (MNT_RDONLY | MNT_EXPORTED); 2765 TAILQ_INIT(&nfsv4root_mnt.mnt_nvnodelist); 2766 nfsv4root_mnt.mnt_export = NULL; 2767 TAILQ_INIT(&nfsv4root_opt); 2768 TAILQ_INIT(&nfsv4root_newopt); 2769 nfsv4root_mnt.mnt_opt = &nfsv4root_opt; 2770 nfsv4root_mnt.mnt_optnew = &nfsv4root_newopt; 2771 nfsv4root_mnt.mnt_nvnodelistsize = 0; 2772} 2773 2774/* 2775 * Get a vnode for a file handle, without checking exports, etc. 2776 */ 2777struct vnode * 2778nfsvno_getvp(fhandle_t *fhp) 2779{ 2780 struct mount *mp; 2781 struct vnode *vp; 2782 int error; 2783 2784 mp = vfs_getvfs(&fhp->fh_fsid); 2785 if (mp == NULL) 2786 return (NULL); 2787 error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp); 2788 if (error) 2789 return (NULL); 2790 return (vp); 2791} 2792 2793/* 2794 * Do a local VOP_ADVLOCK(). 2795 */ 2796int 2797nfsvno_advlock(struct vnode *vp, int ftype, u_int64_t first, 2798 u_int64_t end, struct thread *td) 2799{ 2800 int error; 2801 struct flock fl; 2802 u_int64_t tlen; 2803 2804 if (nfsrv_dolocallocks == 0) 2805 return (0); 2806 2807 /* Check for VI_DOOMED here, so that VOP_ADVLOCK() isn't performed. */ 2808 if ((vp->v_iflag & VI_DOOMED) != 0) 2809 return (EPERM); 2810 2811 fl.l_whence = SEEK_SET; 2812 fl.l_type = ftype; 2813 fl.l_start = (off_t)first; 2814 if (end == NFS64BITSSET) { 2815 fl.l_len = 0; 2816 } else { 2817 tlen = end - first; 2818 fl.l_len = (off_t)tlen; 2819 } 2820 /* 2821 * For FreeBSD8, the l_pid and l_sysid must be set to the same 2822 * values for all calls, so that all locks will be held by the 2823 * nfsd server. (The nfsd server handles conflicts between the 2824 * various clients.) 2825 * Since an NFSv4 lockowner is a ClientID plus an array of up to 1024 2826 * bytes, so it can't be put in l_sysid. 2827 */ 2828 if (nfsv4_sysid == 0) 2829 nfsv4_sysid = nlm_acquire_next_sysid(); 2830 fl.l_pid = (pid_t)0; 2831 fl.l_sysid = (int)nfsv4_sysid; 2832 2833 NFSVOPUNLOCK(vp, 0, td); 2834 if (ftype == F_UNLCK) 2835 error = VOP_ADVLOCK(vp, (caddr_t)td->td_proc, F_UNLCK, &fl, 2836 (F_POSIX | F_REMOTE)); 2837 else 2838 error = VOP_ADVLOCK(vp, (caddr_t)td->td_proc, F_SETLK, &fl, 2839 (F_POSIX | F_REMOTE)); 2840 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, td); 2841 return (error); 2842} 2843 2844/* 2845 * Unlock an underlying local file system. 2846 */ 2847void 2848nfsvno_unlockvfs(struct mount *mp) 2849{ 2850 2851 VFS_UNLOCK_GIANT(mp); 2852} 2853 2854/* 2855 * Lock an underlying file system, as required, and return 2856 * whether or not it is locked. 2857 */ 2858int 2859nfsvno_lockvfs(struct mount *mp) 2860{ 2861 int ret; 2862 2863 ret = VFS_LOCK_GIANT(mp); 2864 return (ret); 2865} 2866 2867/* 2868 * Check the nfsv4 root exports. 2869 */ 2870int 2871nfsvno_v4rootexport(struct nfsrv_descript *nd) 2872{ 2873 struct ucred *credanon; 2874 int exflags, error, numsecflavor, *secflavors, i; 2875 2876 error = vfs_stdcheckexp(&nfsv4root_mnt, nd->nd_nam, &exflags, 2877 &credanon, &numsecflavor, &secflavors); 2878 if (error) 2879 return (NFSERR_PROGUNAVAIL); 2880 if (credanon != NULL) 2881 crfree(credanon); 2882 for (i = 0; i < numsecflavor; i++) { 2883 if (secflavors[i] == AUTH_SYS) 2884 nd->nd_flag |= ND_EXAUTHSYS; 2885 else if (secflavors[i] == RPCSEC_GSS_KRB5) 2886 nd->nd_flag |= ND_EXGSS; 2887 else if (secflavors[i] == RPCSEC_GSS_KRB5I) 2888 nd->nd_flag |= ND_EXGSSINTEGRITY; 2889 else if (secflavors[i] == RPCSEC_GSS_KRB5P) 2890 nd->nd_flag |= ND_EXGSSPRIVACY; 2891 } 2892 return (0); 2893} 2894 2895/* 2896 * Nfs server psuedo system call for the nfsd's 2897 */ 2898/* 2899 * MPSAFE 2900 */ 2901static int 2902nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap) 2903{ 2904 struct file *fp; 2905 struct nfsd_addsock_args sockarg; 2906 struct nfsd_nfsd_args nfsdarg; 2907 int error; 2908 2909 if (uap->flag & NFSSVC_NFSDADDSOCK) { 2910 error = copyin(uap->argp, (caddr_t)&sockarg, sizeof (sockarg)); 2911 if (error) 2912 return (error); 2913 if ((error = fget(td, sockarg.sock, &fp)) != 0) { 2914 return (error); 2915 } 2916 if (fp->f_type != DTYPE_SOCKET) { 2917 fdrop(fp, td); 2918 return (EPERM); 2919 } 2920 error = nfsrvd_addsock(fp); 2921 fdrop(fp, td); 2922 } else if (uap->flag & NFSSVC_NFSDNFSD) { 2923 if (uap->argp == NULL) 2924 return (EINVAL); 2925 error = copyin(uap->argp, (caddr_t)&nfsdarg, 2926 sizeof (nfsdarg)); 2927 if (error) 2928 return (error); 2929 error = nfsrvd_nfsd(td, &nfsdarg); 2930 } else { 2931 error = nfssvc_srvcall(td, uap, td->td_ucred); 2932 } 2933 return (error); 2934} 2935 2936static int 2937nfssvc_srvcall(struct thread *p, struct nfssvc_args *uap, struct ucred *cred) 2938{ 2939 struct nfsex_args export; 2940 struct file *fp = NULL; 2941 int stablefd, len; 2942 struct nfsd_clid adminrevoke; 2943 struct nfsd_dumplist dumplist; 2944 struct nfsd_dumpclients *dumpclients; 2945 struct nfsd_dumplocklist dumplocklist; 2946 struct nfsd_dumplocks *dumplocks; 2947 struct nameidata nd; 2948 vnode_t vp; 2949 int error = EINVAL; 2950 2951 if (uap->flag & NFSSVC_PUBLICFH) { 2952 NFSBZERO((caddr_t)&nfs_pubfh.nfsrvfh_data, 2953 sizeof (fhandle_t)); 2954 error = copyin(uap->argp, 2955 &nfs_pubfh.nfsrvfh_data, sizeof (fhandle_t)); 2956 if (!error) 2957 nfs_pubfhset = 1; 2958 } else if (uap->flag & NFSSVC_V4ROOTEXPORT) { 2959 error = copyin(uap->argp,(caddr_t)&export, 2960 sizeof (struct nfsex_args)); 2961 if (!error) 2962 error = nfsrv_v4rootexport(&export, cred, p); 2963 } else if (uap->flag & NFSSVC_NOPUBLICFH) { 2964 nfs_pubfhset = 0; 2965 error = 0; 2966 } else if (uap->flag & NFSSVC_STABLERESTART) { 2967 error = copyin(uap->argp, (caddr_t)&stablefd, 2968 sizeof (int)); 2969 if (!error) 2970 error = fp_getfvp(p, stablefd, &fp, &vp); 2971 if (!error && (NFSFPFLAG(fp) & (FREAD | FWRITE)) != (FREAD | FWRITE)) 2972 error = EBADF; 2973 if (!error && newnfs_numnfsd != 0) 2974 error = EPERM; 2975 if (!error) { 2976 nfsrv_stablefirst.nsf_fp = fp; 2977 nfsrv_setupstable(p); 2978 } 2979 } else if (uap->flag & NFSSVC_ADMINREVOKE) { 2980 error = copyin(uap->argp, (caddr_t)&adminrevoke, 2981 sizeof (struct nfsd_clid)); 2982 if (!error) 2983 error = nfsrv_adminrevoke(&adminrevoke, p); 2984 } else if (uap->flag & NFSSVC_DUMPCLIENTS) { 2985 error = copyin(uap->argp, (caddr_t)&dumplist, 2986 sizeof (struct nfsd_dumplist)); 2987 if (!error && (dumplist.ndl_size < 1 || 2988 dumplist.ndl_size > NFSRV_MAXDUMPLIST)) 2989 error = EPERM; 2990 if (!error) { 2991 len = sizeof (struct nfsd_dumpclients) * dumplist.ndl_size; 2992 dumpclients = (struct nfsd_dumpclients *)malloc(len, 2993 M_TEMP, M_WAITOK); 2994 nfsrv_dumpclients(dumpclients, dumplist.ndl_size); 2995 error = copyout(dumpclients, 2996 CAST_USER_ADDR_T(dumplist.ndl_list), len); 2997 free((caddr_t)dumpclients, M_TEMP); 2998 } 2999 } else if (uap->flag & NFSSVC_DUMPLOCKS) { 3000 error = copyin(uap->argp, (caddr_t)&dumplocklist, 3001 sizeof (struct nfsd_dumplocklist)); 3002 if (!error && (dumplocklist.ndllck_size < 1 || 3003 dumplocklist.ndllck_size > NFSRV_MAXDUMPLIST)) 3004 error = EPERM; 3005 if (!error) 3006 error = nfsrv_lookupfilename(&nd, 3007 dumplocklist.ndllck_fname, p); 3008 if (!error) { 3009 len = sizeof (struct nfsd_dumplocks) * 3010 dumplocklist.ndllck_size; 3011 dumplocks = (struct nfsd_dumplocks *)malloc(len, 3012 M_TEMP, M_WAITOK); 3013 nfsrv_dumplocks(nd.ni_vp, dumplocks, 3014 dumplocklist.ndllck_size, p); 3015 vput(nd.ni_vp); 3016 error = copyout(dumplocks, 3017 CAST_USER_ADDR_T(dumplocklist.ndllck_list), len); 3018 free((caddr_t)dumplocks, M_TEMP); 3019 } 3020 } 3021 return (error); 3022} 3023 3024/* 3025 * Check exports. 3026 * Returns 0 if ok, 1 otherwise. 3027 */ 3028int 3029nfsvno_testexp(struct nfsrv_descript *nd, struct nfsexstuff *exp) 3030{ 3031 int i; 3032 3033 /* 3034 * This seems odd, but allow the case where the security flavor 3035 * list is empty. This happens when NFSv4 is traversing non-exported 3036 * file systems. Exported file systems should always have a non-empty 3037 * security flavor list. 3038 */ 3039 if (exp->nes_numsecflavor == 0) 3040 return (0); 3041 3042 for (i = 0; i < exp->nes_numsecflavor; i++) { 3043 /* 3044 * The tests for privacy and integrity must be first, 3045 * since ND_GSS is set for everything but AUTH_SYS. 3046 */ 3047 if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5P && 3048 (nd->nd_flag & ND_GSSPRIVACY)) 3049 return (0); 3050 if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5I && 3051 (nd->nd_flag & ND_GSSINTEGRITY)) 3052 return (0); 3053 if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5 && 3054 (nd->nd_flag & ND_GSS)) 3055 return (0); 3056 if (exp->nes_secflavors[i] == AUTH_SYS && 3057 (nd->nd_flag & ND_GSS) == 0) 3058 return (0); 3059 } 3060 return (1); 3061} 3062 3063/* 3064 * Calculate a hash value for the fid in a file handle. 3065 */ 3066uint32_t 3067nfsrv_hashfh(fhandle_t *fhp) 3068{ 3069 uint32_t hashval; 3070 3071 hashval = hash32_buf(&fhp->fh_fid, sizeof(struct fid), 0); 3072 return (hashval); 3073} 3074 3075extern int (*nfsd_call_nfsd)(struct thread *, struct nfssvc_args *); 3076 3077/* 3078 * Called once to initialize data structures... 3079 */ 3080static int 3081nfsd_modevent(module_t mod, int type, void *data) 3082{ 3083 int error = 0; 3084 static int loaded = 0; 3085 3086 switch (type) { 3087 case MOD_LOAD: 3088 if (loaded) 3089 return (0); 3090 newnfs_portinit(); 3091 mtx_init(&nfs_cache_mutex, "nfs_cache_mutex", NULL, MTX_DEF); 3092 mtx_init(&nfs_v4root_mutex, "nfs_v4root_mutex", NULL, MTX_DEF); 3093 mtx_init(&nfsv4root_mnt.mnt_mtx, "struct mount mtx", NULL, 3094 MTX_DEF); 3095 lockinit(&nfsv4root_mnt.mnt_explock, PVFS, "explock", 0, 0); 3096 nfsrvd_initcache(); 3097 nfsd_init(); 3098 NFSD_LOCK(); 3099 nfsrvd_init(0); 3100 NFSD_UNLOCK(); 3101 nfsd_mntinit(); 3102#ifdef VV_DISABLEDELEG 3103 vn_deleg_ops.vndeleg_recall = nfsd_recalldelegation; 3104 vn_deleg_ops.vndeleg_disable = nfsd_disabledelegation; 3105#endif 3106 nfsd_call_servertimer = nfsrv_servertimer; 3107 nfsd_call_nfsd = nfssvc_nfsd; 3108 loaded = 1; 3109 break; 3110 3111 case MOD_UNLOAD: 3112 if (newnfs_numnfsd != 0) { 3113 error = EBUSY; 3114 break; 3115 } 3116 3117#ifdef VV_DISABLEDELEG 3118 vn_deleg_ops.vndeleg_recall = NULL; 3119 vn_deleg_ops.vndeleg_disable = NULL; 3120#endif 3121 nfsd_call_servertimer = NULL; 3122 nfsd_call_nfsd = NULL; 3123 /* and get rid of the locks */ 3124 mtx_destroy(&nfs_cache_mutex); 3125 mtx_destroy(&nfs_v4root_mutex); 3126 mtx_destroy(&nfsv4root_mnt.mnt_mtx); 3127 lockdestroy(&nfsv4root_mnt.mnt_explock); 3128 loaded = 0; 3129 break; 3130 default: 3131 error = EOPNOTSUPP; 3132 break; 3133 } 3134 return error; 3135} 3136static moduledata_t nfsd_mod = { 3137 "nfsd", 3138 nfsd_modevent, 3139 NULL, 3140}; 3141DECLARE_MODULE(nfsd, nfsd_mod, SI_SUB_VFS, SI_ORDER_ANY); 3142 3143/* So that loader and kldload(2) can find us, wherever we are.. */ 3144MODULE_VERSION(nfsd, 1); 3145MODULE_DEPEND(nfsd, nfscommon, 1, 1, 1); 3146MODULE_DEPEND(nfsd, nfslockd, 1, 1, 1); 3147MODULE_DEPEND(nfsd, krpc, 1, 1, 1); 3148MODULE_DEPEND(nfsd, nfssvc, 1, 1, 1); 3149 3150