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