1/* 2 * Copyright (c) 2000-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ 29/* 30 * Copyright (c) 1989, 1993 31 * The Regents of the University of California. All rights reserved. 32 * 33 * This code is derived from software contributed to Berkeley by 34 * Rick Macklem at The University of Guelph. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by the University of 47 * California, Berkeley and its contributors. 48 * 4. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95 65 * FreeBSD-Id: nfs_node.c,v 1.22 1997/10/28 14:06:20 bde Exp $ 66 */ 67 68 69#include <sys/param.h> 70#include <sys/kernel.h> 71#include <sys/systm.h> 72#include <sys/proc.h> 73#include <sys/kauth.h> 74#include <sys/mount_internal.h> 75#include <sys/vnode_internal.h> 76#include <sys/vnode.h> 77#include <sys/ubc.h> 78#include <sys/malloc.h> 79#include <sys/fcntl.h> 80#include <sys/time.h> 81 82#include <nfs/rpcv2.h> 83#include <nfs/nfsproto.h> 84#include <nfs/nfs.h> 85#include <nfs/nfsnode.h> 86#include <nfs/nfs_gss.h> 87#include <nfs/nfsmount.h> 88 89#define NFSNOHASH(fhsum) \ 90 (&nfsnodehashtbl[(fhsum) & nfsnodehash]) 91static LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl; 92static u_long nfsnodehash; 93 94static lck_grp_t *nfs_node_hash_lck_grp; 95static lck_grp_t *nfs_node_lck_grp; 96static lck_grp_t *nfs_data_lck_grp; 97lck_mtx_t *nfs_node_hash_mutex; 98 99/* 100 * Initialize hash links for nfsnodes 101 * and build nfsnode free list. 102 */ 103void 104nfs_nhinit(void) 105{ 106 nfs_node_hash_lck_grp = lck_grp_alloc_init("nfs_node_hash", LCK_GRP_ATTR_NULL); 107 nfs_node_hash_mutex = lck_mtx_alloc_init(nfs_node_hash_lck_grp, LCK_ATTR_NULL); 108 nfs_node_lck_grp = lck_grp_alloc_init("nfs_node", LCK_GRP_ATTR_NULL); 109 nfs_data_lck_grp = lck_grp_alloc_init("nfs_data", LCK_GRP_ATTR_NULL); 110} 111 112void 113nfs_nhinit_finish(void) 114{ 115 lck_mtx_lock(nfs_node_hash_mutex); 116 if (!nfsnodehashtbl) 117 nfsnodehashtbl = hashinit(desiredvnodes, M_NFSNODE, &nfsnodehash); 118 lck_mtx_unlock(nfs_node_hash_mutex); 119} 120 121/* 122 * Compute an entry in the NFS hash table structure 123 */ 124u_long 125nfs_hash(u_char *fhp, int fhsize) 126{ 127 u_long fhsum; 128 int i; 129 130 fhsum = 0; 131 for (i = 0; i < fhsize; i++) 132 fhsum += *fhp++; 133 return (fhsum); 134} 135 136 137int nfs_case_insensitive(mount_t); 138 139int 140nfs_case_insensitive(mount_t mp) 141{ 142 struct nfsmount *nmp = VFSTONFS(mp); 143 int answer = 0; 144 int skip = 0; 145 146 if (nmp == NULL) { 147 return (0); 148 } 149 150 if (nmp->nm_vers == NFS_VER2) { 151 /* V2 has no way to know */ 152 return (0); 153 } 154 155 lck_mtx_lock(&nmp->nm_lock); 156 if (nmp->nm_vers == NFS_VER3) { 157 if (!(nmp->nm_state & NFSSTA_GOTPATHCONF)) { 158 /* We're holding the node lock so we just return 159 * with answer as case sensitive. Is very rare 160 * for file systems not to be homogenous w.r.t. pathconf 161 */ 162 skip = 1; 163 } 164 } else if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_HOMOGENEOUS)) { 165 /* no pathconf info cached */ 166 skip = 1; 167 } 168 169 if (!skip && NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_CASE_INSENSITIVE)) 170 answer = 1; 171 172 lck_mtx_unlock(&nmp->nm_lock); 173 174 return (answer); 175} 176 177 178/* 179 * Look up a vnode/nfsnode by file handle. 180 * Callers must check for mount points!! 181 * In all cases, a pointer to a 182 * nfsnode structure is returned. 183 */ 184int 185nfs_nget( 186 mount_t mp, 187 nfsnode_t dnp, 188 struct componentname *cnp, 189 u_char *fhp, 190 int fhsize, 191 struct nfs_vattr *nvap, 192 u_int64_t *xidp, 193 uint32_t auth, 194 int flags, 195 nfsnode_t *npp) 196{ 197 nfsnode_t np; 198 struct nfsnodehashhead *nhpp; 199 vnode_t vp; 200 int error, nfsvers; 201 mount_t mp2; 202 struct vnode_fsparam vfsp; 203 uint32_t vid; 204 205 FSDBG_TOP(263, mp, dnp, flags, npp); 206 207 /* Check for unmount in progress */ 208 if (!mp || (mp->mnt_kern_flag & MNTK_FRCUNMOUNT)) { 209 *npp = NULL; 210 error = ENXIO; 211 FSDBG_BOT(263, mp, dnp, 0xd1e, error); 212 return (error); 213 } 214 nfsvers = VFSTONFS(mp)->nm_vers; 215 216 nhpp = NFSNOHASH(nfs_hash(fhp, fhsize)); 217loop: 218 lck_mtx_lock(nfs_node_hash_mutex); 219 for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) { 220 mp2 = (np->n_hflag & NHINIT) ? np->n_mount : NFSTOMP(np); 221 if (mp != mp2 || np->n_fhsize != fhsize || 222 bcmp(fhp, np->n_fhp, fhsize)) 223 continue; 224 if (nvap && (nvap->nva_flags & NFS_FFLAG_TRIGGER_REFERRAL) && 225 cnp && (cnp->cn_namelen > (fhsize - (int)sizeof(dnp)))) { 226 /* The name was too long to fit in the file handle. Check it against the node's name. */ 227 int namecmp = 0; 228 const char *vname = vnode_getname(NFSTOV(np)); 229 if (vname) { 230 if (cnp->cn_namelen != (int)strlen(vname)) 231 namecmp = 1; 232 else 233 namecmp = strncmp(vname, cnp->cn_nameptr, cnp->cn_namelen); 234 vnode_putname(vname); 235 } 236 if (namecmp) /* full name didn't match */ 237 continue; 238 } 239 FSDBG(263, dnp, np, np->n_flag, 0xcace0000); 240 /* if the node is locked, sleep on it */ 241 if ((np->n_hflag & NHLOCKED) && !(flags & NG_NOCREATE)) { 242 np->n_hflag |= NHLOCKWANT; 243 FSDBG(263, dnp, np, np->n_flag, 0xcace2222); 244 msleep(np, nfs_node_hash_mutex, PDROP | PINOD, "nfs_nget", NULL); 245 FSDBG(263, dnp, np, np->n_flag, 0xcace3333); 246 goto loop; 247 } 248 vp = NFSTOV(np); 249 vid = vnode_vid(vp); 250 lck_mtx_unlock(nfs_node_hash_mutex); 251 if ((error = vnode_getwithvid(vp, vid))) { 252 /* 253 * If vnode is being reclaimed or has already 254 * changed identity, no need to wait. 255 */ 256 FSDBG_BOT(263, dnp, *npp, 0xcace0d1e, error); 257 return (error); 258 } 259 if ((error = nfs_node_lock(np))) { 260 /* this only fails if the node is now unhashed */ 261 /* so let's see if we can find/create it again */ 262 FSDBG(263, dnp, *npp, 0xcaced1e2, error); 263 vnode_put(vp); 264 if (flags & NG_NOCREATE) { 265 *npp = 0; 266 FSDBG_BOT(263, dnp, *npp, 0xcaced1e0, ENOENT); 267 return (ENOENT); 268 } 269 goto loop; 270 } 271 /* update attributes */ 272 if (nvap) 273 error = nfs_loadattrcache(np, nvap, xidp, 0); 274 if (error) { 275 nfs_node_unlock(np); 276 vnode_put(vp); 277 } else { 278 if (dnp && cnp && (flags & NG_MAKEENTRY)) 279 cache_enter(NFSTOV(dnp), vp, cnp); 280 /* 281 * Update the vnode if the name/and or the parent has 282 * changed. We need to do this so that if getattrlist is 283 * called asking for ATTR_CMN_NAME, that the "most" 284 * correct name is being returned if we're not making an 285 * entry. In addition for monitored vnodes we need to 286 * kick the vnode out of the name cache. We do this so 287 * that if there are hard links in the same directory 288 * the link will not be found and a lookup will get us 289 * here to return the name of the current link. In 290 * addition by removing the name from the name cache the 291 * old name will not be found after a rename done on 292 * another client or the server. The principle reason 293 * to do this is because Finder is asking for 294 * notifications on a directory. The directory changes, 295 * Finder gets notified, reads the directory (which we 296 * have purged) and for each entry returned calls 297 * getattrlist with the name returned from 298 * readdir. gettattrlist has to call namei/lookup to 299 * resolve the name, because its not in the cache we end 300 * up here. We need to update the name so Finder will 301 * get the name it called us with. 302 * 303 * We had an imperfect solution with respect to case 304 * sensitivity. There is a test that is run in 305 * FileBuster that does renames from some name to 306 * another name differing only in case. It then reads 307 * the directory looking for the new name, after it 308 * finds that new name, it ask gettattrlist to verify 309 * that the name is the new name. Usually that works, 310 * but renames generate fsevents and fseventsd will do a 311 * lookup on the name via lstat. Since that test renames 312 * old name to new name back and forth there is a race 313 * that an fsevent will be behind and will access the 314 * file by the old name, on a case insensitive file 315 * system that will work. Problem is if we do a case 316 * sensitive compare, we're going to change the name, 317 * which the test's getattrlist verification step is 318 * going to fail. So we will check the case sensitivity 319 * of the file system and do the appropriate compare. In 320 * a rare instance for non homogeneous file systems 321 * w.r.t. pathconf we will use case sensitive compares. 322 * That could break if the file system is actually case 323 * insensitive. 324 * 325 * Note that V2 does not know the case, so we just 326 * assume case sensitivity. 327 * 328 * This is clearly not perfect due to races, but this is 329 * as good as its going to get. You can defeat the 330 * handling of hard links simply by doing: 331 * 332 * while :; do ls -l > /dev/null; done 333 * 334 * in a terminal window. Even a single ls -l can cause a 335 * race. 336 * 337 * <rant>What we really need is for the caller, that 338 * knows the name being used is valid since it got it 339 * from a readdir to use that name and not ask for the 340 * ATTR_CMN_NAME</rant> 341 */ 342 if (dnp && cnp && (vp != NFSTOV(dnp))) { 343 int update_flags = vnode_ismonitored((NFSTOV(dnp))) ? VNODE_UPDATE_CACHE : 0; 344 int (*cmp)(const char *s1, const char *s2, size_t n); 345 346 cmp = nfs_case_insensitive(mp) ? strncasecmp : strncmp; 347 348 if (vp->v_name && cnp->cn_namelen && (*cmp)(cnp->cn_nameptr, vp->v_name, cnp->cn_namelen)) 349 update_flags |= VNODE_UPDATE_NAME; 350 if ((vp->v_name == NULL && cnp->cn_namelen != 0) || (vp->v_name != NULL && cnp->cn_namelen == 0)) 351 update_flags |= VNODE_UPDATE_NAME; 352 if (vnode_parent(vp) != NFSTOV(dnp)) 353 update_flags |= VNODE_UPDATE_PARENT; 354 if (update_flags) 355 vnode_update_identity(vp, NFSTOV(dnp), cnp->cn_nameptr, cnp->cn_namelen, 0, update_flags); 356 } 357 358 *npp = np; 359 } 360 FSDBG_BOT(263, dnp, *npp, 0xcace0000, error); 361 return(error); 362 } 363 364 FSDBG(263, mp, dnp, npp, 0xaaaaaaaa); 365 366 if (flags & NG_NOCREATE) { 367 lck_mtx_unlock(nfs_node_hash_mutex); 368 *npp = 0; 369 FSDBG_BOT(263, dnp, *npp, 0x80000001, ENOENT); 370 return (ENOENT); 371 } 372 373 /* 374 * allocate and initialize nfsnode and stick it in the hash 375 * before calling getnewvnode(). Anyone finding it in the 376 * hash before initialization is complete will wait for it. 377 */ 378 MALLOC_ZONE(np, nfsnode_t, sizeof *np, M_NFSNODE, M_WAITOK); 379 if (!np) { 380 lck_mtx_unlock(nfs_node_hash_mutex); 381 *npp = 0; 382 FSDBG_BOT(263, dnp, *npp, 0x80000001, ENOMEM); 383 return (ENOMEM); 384 } 385 bzero(np, sizeof *np); 386 np->n_hflag |= (NHINIT | NHLOCKED); 387 np->n_mount = mp; 388 np->n_auth = auth; 389 TAILQ_INIT(&np->n_opens); 390 TAILQ_INIT(&np->n_lock_owners); 391 TAILQ_INIT(&np->n_locks); 392 np->n_dlink.tqe_next = NFSNOLIST; 393 np->n_dreturn.tqe_next = NFSNOLIST; 394 np->n_monlink.le_next = NFSNOLIST; 395 396 /* ugh... need to keep track of ".zfs" directories to workaround server bugs */ 397 if ((nvap->nva_type == VDIR) && cnp && (cnp->cn_namelen == 4) && 398 (cnp->cn_nameptr[0] == '.') && (cnp->cn_nameptr[1] == 'z') && 399 (cnp->cn_nameptr[2] == 'f') && (cnp->cn_nameptr[3] == 's')) 400 np->n_flag |= NISDOTZFS; 401 if (dnp && (dnp->n_flag & NISDOTZFS)) 402 np->n_flag |= NISDOTZFSCHILD; 403 404 if (dnp && cnp && ((cnp->cn_namelen != 2) || 405 (cnp->cn_nameptr[0] != '.') || (cnp->cn_nameptr[1] != '.'))) { 406 vnode_t dvp = NFSTOV(dnp); 407 if (!vnode_get(dvp)) { 408 if (!vnode_ref(dvp)) 409 np->n_parent = dvp; 410 vnode_put(dvp); 411 } 412 } 413 414 /* setup node's file handle */ 415 if (fhsize > NFS_SMALLFH) { 416 MALLOC_ZONE(np->n_fhp, u_char *, 417 fhsize, M_NFSBIGFH, M_WAITOK); 418 if (!np->n_fhp) { 419 lck_mtx_unlock(nfs_node_hash_mutex); 420 FREE_ZONE(np, sizeof *np, M_NFSNODE); 421 *npp = 0; 422 FSDBG_BOT(263, dnp, *npp, 0x80000002, ENOMEM); 423 return (ENOMEM); 424 } 425 } else { 426 np->n_fhp = &np->n_fh[0]; 427 } 428 bcopy(fhp, np->n_fhp, fhsize); 429 np->n_fhsize = fhsize; 430 431 /* Insert the nfsnode in the hash queue for its new file handle */ 432 LIST_INSERT_HEAD(nhpp, np, n_hash); 433 np->n_hflag |= NHHASHED; 434 FSDBG(266, 0, np, np->n_flag, np->n_hflag); 435 436 /* lock the new nfsnode */ 437 lck_mtx_init(&np->n_lock, nfs_node_lck_grp, LCK_ATTR_NULL); 438 lck_rw_init(&np->n_datalock, nfs_data_lck_grp, LCK_ATTR_NULL); 439 lck_mtx_init(&np->n_openlock, nfs_open_grp, LCK_ATTR_NULL); 440 lck_mtx_lock(&np->n_lock); 441 442 /* release lock on hash table */ 443 lck_mtx_unlock(nfs_node_hash_mutex); 444 445 /* do initial loading of attributes */ 446 NACLINVALIDATE(np); 447 NACCESSINVALIDATE(np); 448 error = nfs_loadattrcache(np, nvap, xidp, 1); 449 if (error) { 450 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e); 451 nfs_node_unlock(np); 452 lck_mtx_lock(nfs_node_hash_mutex); 453 LIST_REMOVE(np, n_hash); 454 np->n_hflag &= ~(NHHASHED|NHINIT|NHLOCKED); 455 if (np->n_hflag & NHLOCKWANT) { 456 np->n_hflag &= ~NHLOCKWANT; 457 wakeup(np); 458 } 459 lck_mtx_unlock(nfs_node_hash_mutex); 460 if (np->n_parent) { 461 if (!vnode_get(np->n_parent)) { 462 vnode_rele(np->n_parent); 463 vnode_put(np->n_parent); 464 } 465 np->n_parent = NULL; 466 } 467 lck_mtx_destroy(&np->n_lock, nfs_node_lck_grp); 468 lck_rw_destroy(&np->n_datalock, nfs_data_lck_grp); 469 lck_mtx_destroy(&np->n_openlock, nfs_open_grp); 470 if (np->n_fhsize > NFS_SMALLFH) 471 FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH); 472 FREE_ZONE(np, sizeof *np, M_NFSNODE); 473 *npp = 0; 474 FSDBG_BOT(263, dnp, *npp, 0x80000003, error); 475 return (error); 476 } 477 NFS_CHANGED_UPDATE(nfsvers, np, nvap); 478 if (nvap->nva_type == VDIR) 479 NFS_CHANGED_UPDATE_NC(nfsvers, np, nvap); 480 481 /* now, attempt to get a new vnode */ 482 vfsp.vnfs_mp = mp; 483 vfsp.vnfs_vtype = nvap->nva_type; 484 vfsp.vnfs_str = "nfs"; 485 vfsp.vnfs_dvp = dnp ? NFSTOV(dnp) : NULL; 486 vfsp.vnfs_fsnode = np; 487 if (nfsvers == NFS_VER4) { 488#if FIFO 489 if (nvap->nva_type == VFIFO) 490 vfsp.vnfs_vops = fifo_nfsv4nodeop_p; 491 else 492#endif /* FIFO */ 493 if (nvap->nva_type == VBLK || nvap->nva_type == VCHR) 494 vfsp.vnfs_vops = spec_nfsv4nodeop_p; 495 else 496 vfsp.vnfs_vops = nfsv4_vnodeop_p; 497 } else { 498#if FIFO 499 if (nvap->nva_type == VFIFO) 500 vfsp.vnfs_vops = fifo_nfsv2nodeop_p; 501 else 502#endif /* FIFO */ 503 if (nvap->nva_type == VBLK || nvap->nva_type == VCHR) 504 vfsp.vnfs_vops = spec_nfsv2nodeop_p; 505 else 506 vfsp.vnfs_vops = nfsv2_vnodeop_p; 507 } 508 vfsp.vnfs_markroot = (flags & NG_MARKROOT) ? 1 : 0; 509 vfsp.vnfs_marksystem = 0; 510 vfsp.vnfs_rdev = 0; 511 vfsp.vnfs_filesize = nvap->nva_size; 512 vfsp.vnfs_cnp = cnp; 513 vfsp.vnfs_flags = VNFS_ADDFSREF; 514 if (!dnp || !cnp || !(flags & NG_MAKEENTRY)) 515 vfsp.vnfs_flags |= VNFS_NOCACHE; 516 517#if CONFIG_TRIGGERS 518 if ((nfsvers >= NFS_VER4) && (nvap->nva_type == VDIR) && (np->n_vattr.nva_flags & NFS_FFLAG_TRIGGER)) { 519 struct vnode_trigger_param vtp; 520 bzero(&vtp, sizeof(vtp)); 521 bcopy(&vfsp, &vtp.vnt_params, sizeof(vfsp)); 522 vtp.vnt_resolve_func = nfs_mirror_mount_trigger_resolve; 523 vtp.vnt_unresolve_func = nfs_mirror_mount_trigger_unresolve; 524 vtp.vnt_rearm_func = nfs_mirror_mount_trigger_rearm; 525 vtp.vnt_flags = VNT_AUTO_REARM; 526 error = vnode_create(VNCREATE_TRIGGER, VNCREATE_TRIGGER_SIZE, &vtp, &np->n_vnode); 527 } else 528#endif 529 { 530 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &np->n_vnode); 531 } 532 if (error) { 533 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e); 534 nfs_node_unlock(np); 535 lck_mtx_lock(nfs_node_hash_mutex); 536 LIST_REMOVE(np, n_hash); 537 np->n_hflag &= ~(NHHASHED|NHINIT|NHLOCKED); 538 if (np->n_hflag & NHLOCKWANT) { 539 np->n_hflag &= ~NHLOCKWANT; 540 wakeup(np); 541 } 542 lck_mtx_unlock(nfs_node_hash_mutex); 543 if (np->n_parent) { 544 if (!vnode_get(np->n_parent)) { 545 vnode_rele(np->n_parent); 546 vnode_put(np->n_parent); 547 } 548 np->n_parent = NULL; 549 } 550 lck_mtx_destroy(&np->n_lock, nfs_node_lck_grp); 551 lck_rw_destroy(&np->n_datalock, nfs_data_lck_grp); 552 lck_mtx_destroy(&np->n_openlock, nfs_open_grp); 553 if (np->n_fhsize > NFS_SMALLFH) 554 FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH); 555 FREE_ZONE(np, sizeof *np, M_NFSNODE); 556 *npp = 0; 557 FSDBG_BOT(263, dnp, *npp, 0x80000004, error); 558 return (error); 559 } 560 vp = np->n_vnode; 561 vnode_settag(vp, VT_NFS); 562 /* node is now initialized */ 563 564 /* check if anyone's waiting on this node */ 565 lck_mtx_lock(nfs_node_hash_mutex); 566 np->n_hflag &= ~(NHINIT|NHLOCKED); 567 if (np->n_hflag & NHLOCKWANT) { 568 np->n_hflag &= ~NHLOCKWANT; 569 wakeup(np); 570 } 571 lck_mtx_unlock(nfs_node_hash_mutex); 572 573 *npp = np; 574 575 FSDBG_BOT(263, dnp, vp, *npp, error); 576 return (error); 577} 578 579 580int 581nfs_vnop_inactive(ap) 582 struct vnop_inactive_args /* { 583 struct vnodeop_desc *a_desc; 584 vnode_t a_vp; 585 vfs_context_t a_context; 586 } */ *ap; 587{ 588 vnode_t vp = ap->a_vp; 589 vfs_context_t ctx = ap->a_context; 590 nfsnode_t np = VTONFS(ap->a_vp); 591 struct nfs_sillyrename *nsp; 592 struct nfs_vattr nvattr; 593 int unhash, attrerr, busyerror, error, inuse, busied, force; 594 struct nfs_open_file *nofp; 595 struct componentname cn; 596 struct nfsmount *nmp = NFSTONMP(np); 597 mount_t mp = vnode_mount(vp); 598 599restart: 600 force = (!mp || (mp->mnt_kern_flag & MNTK_FRCUNMOUNT)); 601 error = 0; 602 inuse = (nfs_mount_state_in_use_start(nmp, NULL) == 0); 603 604 /* There shouldn't be any open or lock state at this point */ 605 lck_mtx_lock(&np->n_openlock); 606 if (np->n_openrefcnt && !force) 607 NP(np, "nfs_vnop_inactive: still open: %d", np->n_openrefcnt); 608 TAILQ_FOREACH(nofp, &np->n_opens, nof_link) { 609 lck_mtx_lock(&nofp->nof_lock); 610 if (nofp->nof_flags & NFS_OPEN_FILE_BUSY) { 611 if (!force) 612 NP(np, "nfs_vnop_inactive: open file busy"); 613 busied = 0; 614 } else { 615 nofp->nof_flags |= NFS_OPEN_FILE_BUSY; 616 busied = 1; 617 } 618 lck_mtx_unlock(&nofp->nof_lock); 619 if ((np->n_flag & NREVOKE) || (nofp->nof_flags & NFS_OPEN_FILE_LOST)) { 620 if (busied) 621 nfs_open_file_clear_busy(nofp); 622 continue; 623 } 624 /* 625 * If we just created the file, we already had it open in 626 * anticipation of getting a subsequent open call. If the 627 * node has gone inactive without being open, we need to 628 * clean up (close) the open done in the create. 629 */ 630 if ((nofp->nof_flags & NFS_OPEN_FILE_CREATE) && nofp->nof_creator && !force) { 631 if (nofp->nof_flags & NFS_OPEN_FILE_REOPEN) { 632 lck_mtx_unlock(&np->n_openlock); 633 if (busied) 634 nfs_open_file_clear_busy(nofp); 635 if (inuse) 636 nfs_mount_state_in_use_end(nmp, 0); 637 if (!nfs4_reopen(nofp, NULL)) 638 goto restart; 639 } 640 nofp->nof_flags &= ~NFS_OPEN_FILE_CREATE; 641 lck_mtx_unlock(&np->n_openlock); 642 error = nfs_close(np, nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_NONE, ctx); 643 if (error) { 644 NP(np, "nfs_vnop_inactive: create close error: %d", error); 645 nofp->nof_flags |= NFS_OPEN_FILE_CREATE; 646 } 647 if (busied) 648 nfs_open_file_clear_busy(nofp); 649 if (inuse) 650 nfs_mount_state_in_use_end(nmp, error); 651 goto restart; 652 } 653 if (nofp->nof_flags & NFS_OPEN_FILE_NEEDCLOSE) { 654 /* 655 * If the file is marked as needing reopen, but this was the only 656 * open on the file, just drop the open. 657 */ 658 nofp->nof_flags &= ~NFS_OPEN_FILE_NEEDCLOSE; 659 if ((nofp->nof_flags & NFS_OPEN_FILE_REOPEN) && (nofp->nof_opencnt == 1)) { 660 nofp->nof_flags &= ~NFS_OPEN_FILE_REOPEN; 661 nofp->nof_r--; 662 nofp->nof_opencnt--; 663 nofp->nof_access = 0; 664 } else if (!force) { 665 lck_mtx_unlock(&np->n_openlock); 666 if (nofp->nof_flags & NFS_OPEN_FILE_REOPEN) { 667 if (busied) 668 nfs_open_file_clear_busy(nofp); 669 if (inuse) 670 nfs_mount_state_in_use_end(nmp, 0); 671 if (!nfs4_reopen(nofp, NULL)) 672 goto restart; 673 } 674 error = nfs_close(np, nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_NONE, ctx); 675 if (error) { 676 NP(np, "nfs_vnop_inactive: need close error: %d", error); 677 nofp->nof_flags |= NFS_OPEN_FILE_NEEDCLOSE; 678 } 679 if (busied) 680 nfs_open_file_clear_busy(nofp); 681 if (inuse) 682 nfs_mount_state_in_use_end(nmp, error); 683 goto restart; 684 } 685 } 686 if (nofp->nof_opencnt && !force) 687 NP(np, "nfs_vnop_inactive: file still open: %d", nofp->nof_opencnt); 688 if (!force && (nofp->nof_access || nofp->nof_deny || 689 nofp->nof_mmap_access || nofp->nof_mmap_deny || 690 nofp->nof_r || nofp->nof_w || nofp->nof_rw || 691 nofp->nof_r_dw || nofp->nof_w_dw || nofp->nof_rw_dw || 692 nofp->nof_r_drw || nofp->nof_w_drw || nofp->nof_rw_drw || 693 nofp->nof_d_r || nofp->nof_d_w || nofp->nof_d_rw || 694 nofp->nof_d_r_dw || nofp->nof_d_w_dw || nofp->nof_d_rw_dw || 695 nofp->nof_d_r_drw || nofp->nof_d_w_drw || nofp->nof_d_rw_drw)) { 696 NP(np, "nfs_vnop_inactive: non-zero access: %d %d %d %d # %u.%u %u.%u %u.%u dw %u.%u %u.%u %u.%u drw %u.%u %u.%u %u.%u", 697 nofp->nof_access, nofp->nof_deny, 698 nofp->nof_mmap_access, nofp->nof_mmap_deny, 699 nofp->nof_r, nofp->nof_d_r, 700 nofp->nof_w, nofp->nof_d_w, 701 nofp->nof_rw, nofp->nof_d_rw, 702 nofp->nof_r_dw, nofp->nof_d_r_dw, 703 nofp->nof_w_dw, nofp->nof_d_w_dw, 704 nofp->nof_rw_dw, nofp->nof_d_rw_dw, 705 nofp->nof_r_drw, nofp->nof_d_r_drw, 706 nofp->nof_w_drw, nofp->nof_d_w_drw, 707 nofp->nof_rw_drw, nofp->nof_d_rw_drw); 708 } 709 if (busied) 710 nfs_open_file_clear_busy(nofp); 711 } 712 lck_mtx_unlock(&np->n_openlock); 713 714 if (inuse && nfs_mount_state_in_use_end(nmp, error)) 715 goto restart; 716 717 nfs_node_lock_force(np); 718 719 if (vnode_vtype(vp) != VDIR) { 720 nsp = np->n_sillyrename; 721 np->n_sillyrename = NULL; 722 } else { 723 nsp = NULL; 724 } 725 726 FSDBG_TOP(264, vp, np, np->n_flag, nsp); 727 728 if (!nsp) { 729 /* no silly file to clean up... */ 730 /* clear all flags other than these */ 731 np->n_flag &= (NMODIFIED); 732 nfs_node_unlock(np); 733 FSDBG_BOT(264, vp, np, np->n_flag, 0); 734 return (0); 735 } 736 nfs_node_unlock(np); 737 738 /* Remove the silly file that was rename'd earlier */ 739 740 /* flush all the buffers */ 741 nfs_vinvalbuf2(vp, V_SAVE, vfs_context_thread(ctx), nsp->nsr_cred, 1); 742 743 /* try to get the latest attributes */ 744 attrerr = nfs_getattr(np, &nvattr, ctx, NGA_UNCACHED); 745 746 /* Check if we should remove it from the node hash. */ 747 /* Leave it if inuse or it has multiple hard links. */ 748 if (vnode_isinuse(vp, 0) || (!attrerr && (nvattr.nva_nlink > 1))) { 749 unhash = 0; 750 } else { 751 unhash = 1; 752 ubc_setsize(vp, 0); 753 } 754 755 /* mark this node and the directory busy while we do the remove */ 756 busyerror = nfs_node_set_busy2(nsp->nsr_dnp, np, vfs_context_thread(ctx)); 757 758 /* lock the node while we remove the silly file */ 759 lck_mtx_lock(nfs_node_hash_mutex); 760 while (np->n_hflag & NHLOCKED) { 761 np->n_hflag |= NHLOCKWANT; 762 msleep(np, nfs_node_hash_mutex, PINOD, "nfs_inactive", NULL); 763 } 764 np->n_hflag |= NHLOCKED; 765 lck_mtx_unlock(nfs_node_hash_mutex); 766 767 /* purge the name cache to deter others from finding it */ 768 bzero(&cn, sizeof(cn)); 769 cn.cn_nameptr = nsp->nsr_name; 770 cn.cn_namelen = nsp->nsr_namlen; 771 nfs_name_cache_purge(nsp->nsr_dnp, np, &cn, ctx); 772 773 FSDBG(264, np, np->n_size, np->n_vattr.nva_size, 0xf00d00f1); 774 775 /* now remove the silly file */ 776 nfs_removeit(nsp); 777 778 /* clear all flags other than these */ 779 nfs_node_lock_force(np); 780 np->n_flag &= (NMODIFIED); 781 nfs_node_unlock(np); 782 783 if (!busyerror) 784 nfs_node_clear_busy2(nsp->nsr_dnp, np); 785 786 if (unhash && vnode_isinuse(vp, 0)) { 787 /* vnode now inuse after silly remove? */ 788 unhash = 0; 789 ubc_setsize(vp, np->n_size); 790 } 791 792 lck_mtx_lock(nfs_node_hash_mutex); 793 if (unhash) { 794 /* 795 * remove nfsnode from hash now so we can't accidentally find it 796 * again if another object gets created with the same filehandle 797 * before this vnode gets reclaimed 798 */ 799 if (np->n_hflag & NHHASHED) { 800 LIST_REMOVE(np, n_hash); 801 np->n_hflag &= ~NHHASHED; 802 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e); 803 } 804 vnode_recycle(vp); 805 } 806 /* unlock the node */ 807 np->n_hflag &= ~NHLOCKED; 808 if (np->n_hflag & NHLOCKWANT) { 809 np->n_hflag &= ~NHLOCKWANT; 810 wakeup(np); 811 } 812 lck_mtx_unlock(nfs_node_hash_mutex); 813 814 /* cleanup sillyrename info */ 815 if (nsp->nsr_cred != NOCRED) 816 kauth_cred_unref(&nsp->nsr_cred); 817 vnode_rele(NFSTOV(nsp->nsr_dnp)); 818 FREE_ZONE(nsp, sizeof(*nsp), M_NFSREQ); 819 820 FSDBG_BOT(264, vp, np, np->n_flag, 0); 821 return (0); 822} 823 824/* 825 * Reclaim an nfsnode so that it can be used for other purposes. 826 */ 827int 828nfs_vnop_reclaim(ap) 829 struct vnop_reclaim_args /* { 830 struct vnodeop_desc *a_desc; 831 vnode_t a_vp; 832 vfs_context_t a_context; 833 } */ *ap; 834{ 835 vnode_t vp = ap->a_vp; 836 nfsnode_t np = VTONFS(vp); 837 vfs_context_t ctx = ap->a_context; 838 struct nfs_open_file *nofp, *nextnofp; 839 struct nfs_file_lock *nflp, *nextnflp; 840 struct nfs_lock_owner *nlop, *nextnlop; 841 struct nfsmount *nmp = np->n_mount ? VFSTONFS(np->n_mount) : NFSTONMP(np); 842 mount_t mp = vnode_mount(vp); 843 int force; 844 845 FSDBG_TOP(265, vp, np, np->n_flag, 0); 846 force = (!mp || (mp->mnt_kern_flag & MNTK_FRCUNMOUNT)); 847 848 /* There shouldn't be any open or lock state at this point */ 849 lck_mtx_lock(&np->n_openlock); 850 851 if (nmp && (nmp->nm_vers >= NFS_VER4)) { 852 /* need to drop a delegation */ 853 if (np->n_dreturn.tqe_next != NFSNOLIST) { 854 /* remove this node from the delegation return list */ 855 lck_mtx_lock(&nmp->nm_lock); 856 if (np->n_dreturn.tqe_next != NFSNOLIST) { 857 TAILQ_REMOVE(&nmp->nm_dreturnq, np, n_dreturn); 858 np->n_dreturn.tqe_next = NFSNOLIST; 859 } 860 lck_mtx_unlock(&nmp->nm_lock); 861 } 862 if (np->n_dlink.tqe_next != NFSNOLIST) { 863 /* remove this node from the delegation list */ 864 lck_mtx_lock(&nmp->nm_lock); 865 if (np->n_dlink.tqe_next != NFSNOLIST) { 866 TAILQ_REMOVE(&nmp->nm_delegations, np, n_dlink); 867 np->n_dlink.tqe_next = NFSNOLIST; 868 } 869 lck_mtx_unlock(&nmp->nm_lock); 870 } 871 if ((np->n_openflags & N_DELEG_MASK) && !force) { 872 /* try to return the delegation */ 873 np->n_openflags &= ~N_DELEG_MASK; 874 nfs4_delegreturn_rpc(nmp, np->n_fhp, np->n_fhsize, &np->n_dstateid, 875 R_RECOVER, vfs_context_thread(ctx), vfs_context_ucred(ctx)); 876 } 877 if (np->n_attrdirfh) { 878 FREE(np->n_attrdirfh, M_TEMP); 879 np->n_attrdirfh = NULL; 880 } 881 } 882 883 /* clean up file locks */ 884 TAILQ_FOREACH_SAFE(nflp, &np->n_locks, nfl_link, nextnflp) { 885 if (!(nflp->nfl_flags & NFS_FILE_LOCK_DEAD) && !force) { 886 NP(np, "nfs_vnop_reclaim: lock 0x%llx 0x%llx 0x%x (bc %d)", 887 nflp->nfl_start, nflp->nfl_end, nflp->nfl_flags, nflp->nfl_blockcnt); 888 } 889 if (!(nflp->nfl_flags & (NFS_FILE_LOCK_BLOCKED|NFS_FILE_LOCK_DEAD))) { 890 /* try sending an unlock RPC if it wasn't delegated */ 891 if (!(nflp->nfl_flags & NFS_FILE_LOCK_DELEGATED) && !force) 892 nmp->nm_funcs->nf_unlock_rpc(np, nflp->nfl_owner, F_WRLCK, nflp->nfl_start, nflp->nfl_end, R_RECOVER, 893 NULL, nflp->nfl_owner->nlo_open_owner->noo_cred); 894 lck_mtx_lock(&nflp->nfl_owner->nlo_lock); 895 TAILQ_REMOVE(&nflp->nfl_owner->nlo_locks, nflp, nfl_lolink); 896 lck_mtx_unlock(&nflp->nfl_owner->nlo_lock); 897 } 898 TAILQ_REMOVE(&np->n_locks, nflp, nfl_link); 899 nfs_file_lock_destroy(nflp); 900 } 901 /* clean up lock owners */ 902 TAILQ_FOREACH_SAFE(nlop, &np->n_lock_owners, nlo_link, nextnlop) { 903 if (!TAILQ_EMPTY(&nlop->nlo_locks) && !force) 904 NP(np, "nfs_vnop_reclaim: lock owner with locks"); 905 TAILQ_REMOVE(&np->n_lock_owners, nlop, nlo_link); 906 nfs_lock_owner_destroy(nlop); 907 } 908 /* clean up open state */ 909 if (np->n_openrefcnt && !force) 910 NP(np, "nfs_vnop_reclaim: still open: %d", np->n_openrefcnt); 911 TAILQ_FOREACH_SAFE(nofp, &np->n_opens, nof_link, nextnofp) { 912 if (nofp->nof_flags & NFS_OPEN_FILE_BUSY) 913 NP(np, "nfs_vnop_reclaim: open file busy"); 914 if (!(np->n_flag & NREVOKE) && !(nofp->nof_flags & NFS_OPEN_FILE_LOST)) { 915 if (nofp->nof_opencnt && !force) 916 NP(np, "nfs_vnop_reclaim: file still open: %d", nofp->nof_opencnt); 917 if (!force && (nofp->nof_access || nofp->nof_deny || 918 nofp->nof_mmap_access || nofp->nof_mmap_deny || 919 nofp->nof_r || nofp->nof_w || nofp->nof_rw || 920 nofp->nof_r_dw || nofp->nof_w_dw || nofp->nof_rw_dw || 921 nofp->nof_r_drw || nofp->nof_w_drw || nofp->nof_rw_drw || 922 nofp->nof_d_r || nofp->nof_d_w || nofp->nof_d_rw || 923 nofp->nof_d_r_dw || nofp->nof_d_w_dw || nofp->nof_d_rw_dw || 924 nofp->nof_d_r_drw || nofp->nof_d_w_drw || nofp->nof_d_rw_drw)) { 925 NP(np, "nfs_vnop_reclaim: non-zero access: %d %d %d %d # %u.%u %u.%u %u.%u dw %u.%u %u.%u %u.%u drw %u.%u %u.%u %u.%u", 926 nofp->nof_access, nofp->nof_deny, 927 nofp->nof_mmap_access, nofp->nof_mmap_deny, 928 nofp->nof_r, nofp->nof_d_r, 929 nofp->nof_w, nofp->nof_d_w, 930 nofp->nof_rw, nofp->nof_d_rw, 931 nofp->nof_r_dw, nofp->nof_d_r_dw, 932 nofp->nof_w_dw, nofp->nof_d_w_dw, 933 nofp->nof_rw_dw, nofp->nof_d_rw_dw, 934 nofp->nof_r_drw, nofp->nof_d_r_drw, 935 nofp->nof_w_drw, nofp->nof_d_w_drw, 936 nofp->nof_rw_drw, nofp->nof_d_rw_drw); 937 /* try sending a close RPC if it wasn't delegated */ 938 if (nofp->nof_r || nofp->nof_w || nofp->nof_rw || 939 nofp->nof_r_dw || nofp->nof_w_dw || nofp->nof_rw_dw || 940 nofp->nof_r_drw || nofp->nof_w_drw || nofp->nof_rw_drw) 941 nfs4_close_rpc(np, nofp, NULL, nofp->nof_owner->noo_cred, R_RECOVER); 942 } 943 } 944 TAILQ_REMOVE(&np->n_opens, nofp, nof_link); 945 nfs_open_file_destroy(nofp); 946 } 947 lck_mtx_unlock(&np->n_openlock); 948 949 if (np->n_monlink.le_next != NFSNOLIST) { 950 /* Wait for any in-progress getattr to complete, */ 951 /* then remove this node from the monitored node list. */ 952 lck_mtx_lock(&nmp->nm_lock); 953 while (np->n_mflag & NMMONSCANINPROG) { 954 struct timespec ts = { 1, 0 }; 955 np->n_mflag |= NMMONSCANWANT; 956 msleep(&np->n_mflag, &nmp->nm_lock, PZERO-1, "nfswaitmonscan", &ts); 957 } 958 if (np->n_monlink.le_next != NFSNOLIST) { 959 LIST_REMOVE(np, n_monlink); 960 np->n_monlink.le_next = NFSNOLIST; 961 } 962 lck_mtx_unlock(&nmp->nm_lock); 963 } 964 965 lck_mtx_lock(nfs_buf_mutex); 966 if (!force && (!LIST_EMPTY(&np->n_dirtyblkhd) || !LIST_EMPTY(&np->n_cleanblkhd))) 967 NP(np, "nfs_reclaim: dropping %s buffers", (!LIST_EMPTY(&np->n_dirtyblkhd) ? "dirty" : "clean")); 968 lck_mtx_unlock(nfs_buf_mutex); 969 nfs_vinvalbuf(vp, V_IGNORE_WRITEERR, ap->a_context, 0); 970 971 lck_mtx_lock(nfs_node_hash_mutex); 972 973 if ((vnode_vtype(vp) != VDIR) && np->n_sillyrename) { 974 if (!force) 975 NP(np, "nfs_reclaim: leaving unlinked file %s", np->n_sillyrename->nsr_name); 976 if (np->n_sillyrename->nsr_cred != NOCRED) 977 kauth_cred_unref(&np->n_sillyrename->nsr_cred); 978 vnode_rele(NFSTOV(np->n_sillyrename->nsr_dnp)); 979 FREE_ZONE(np->n_sillyrename, sizeof(*np->n_sillyrename), M_NFSREQ); 980 } 981 982 vnode_removefsref(vp); 983 984 if (np->n_hflag & NHHASHED) { 985 LIST_REMOVE(np, n_hash); 986 np->n_hflag &= ~NHHASHED; 987 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e); 988 } 989 lck_mtx_unlock(nfs_node_hash_mutex); 990 991 /* 992 * Free up any directory cookie structures and large file handle 993 * structures that might be associated with this nfs node. 994 */ 995 nfs_node_lock_force(np); 996 if ((vnode_vtype(vp) == VDIR) && np->n_cookiecache) 997 FREE_ZONE(np->n_cookiecache, sizeof(struct nfsdmap), M_NFSDIROFF); 998 if (np->n_fhsize > NFS_SMALLFH) 999 FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH); 1000 if (np->n_vattr.nva_acl) 1001 kauth_acl_free(np->n_vattr.nva_acl); 1002 nfs_node_unlock(np); 1003 vnode_clearfsnode(vp); 1004 1005 if (np->n_parent) { 1006 if (!vnode_get(np->n_parent)) { 1007 vnode_rele(np->n_parent); 1008 vnode_put(np->n_parent); 1009 } 1010 np->n_parent = NULL; 1011 } 1012 1013 lck_mtx_destroy(&np->n_lock, nfs_node_lck_grp); 1014 lck_rw_destroy(&np->n_datalock, nfs_data_lck_grp); 1015 lck_mtx_destroy(&np->n_openlock, nfs_open_grp); 1016 1017 FSDBG_BOT(265, vp, np, np->n_flag, 0xd1ed1e); 1018 FREE_ZONE(np, sizeof(struct nfsnode), M_NFSNODE); 1019 return (0); 1020} 1021 1022/* 1023 * Acquire an NFS node lock 1024 */ 1025 1026int 1027nfs_node_lock_internal(nfsnode_t np, int force) 1028{ 1029 FSDBG_TOP(268, np, force, 0, 0); 1030 lck_mtx_lock(&np->n_lock); 1031 if (!force && !(np->n_hflag && NHHASHED)) { 1032 FSDBG_BOT(268, np, 0xdead, 0, 0); 1033 lck_mtx_unlock(&np->n_lock); 1034 return (ENOENT); 1035 } 1036 FSDBG_BOT(268, np, force, 0, 0); 1037 return (0); 1038} 1039 1040int 1041nfs_node_lock(nfsnode_t np) 1042{ 1043 return nfs_node_lock_internal(np, 0); 1044} 1045 1046void 1047nfs_node_lock_force(nfsnode_t np) 1048{ 1049 nfs_node_lock_internal(np, 1); 1050} 1051 1052/* 1053 * Release an NFS node lock 1054 */ 1055void 1056nfs_node_unlock(nfsnode_t np) 1057{ 1058 FSDBG(269, np, current_thread(), 0, 0); 1059 lck_mtx_unlock(&np->n_lock); 1060} 1061 1062/* 1063 * Acquire 2 NFS node locks 1064 * - locks taken in reverse address order 1065 * - both or neither of the locks are taken 1066 * - only one lock taken per node (dup nodes are skipped) 1067 */ 1068int 1069nfs_node_lock2(nfsnode_t np1, nfsnode_t np2) 1070{ 1071 nfsnode_t first, second; 1072 int error; 1073 1074 first = (np1 > np2) ? np1 : np2; 1075 second = (np1 > np2) ? np2 : np1; 1076 if ((error = nfs_node_lock(first))) 1077 return (error); 1078 if (np1 == np2) 1079 return (error); 1080 if ((error = nfs_node_lock(second))) 1081 nfs_node_unlock(first); 1082 return (error); 1083} 1084 1085void 1086nfs_node_unlock2(nfsnode_t np1, nfsnode_t np2) 1087{ 1088 nfs_node_unlock(np1); 1089 if (np1 != np2) 1090 nfs_node_unlock(np2); 1091} 1092 1093/* 1094 * Manage NFS node busy state. 1095 * (Similar to NFS node locks above) 1096 */ 1097int 1098nfs_node_set_busy(nfsnode_t np, thread_t thd) 1099{ 1100 struct timespec ts = { 2, 0 }; 1101 int error; 1102 1103 if ((error = nfs_node_lock(np))) 1104 return (error); 1105 while (ISSET(np->n_flag, NBUSY)) { 1106 SET(np->n_flag, NBUSYWANT); 1107 msleep(np, &np->n_lock, PZERO-1, "nfsbusywant", &ts); 1108 if ((error = nfs_sigintr(NFSTONMP(np), NULL, thd, 0))) 1109 break; 1110 } 1111 if (!error) 1112 SET(np->n_flag, NBUSY); 1113 nfs_node_unlock(np); 1114 return (error); 1115} 1116 1117void 1118nfs_node_clear_busy(nfsnode_t np) 1119{ 1120 int wanted; 1121 1122 nfs_node_lock_force(np); 1123 wanted = ISSET(np->n_flag, NBUSYWANT); 1124 CLR(np->n_flag, NBUSY|NBUSYWANT); 1125 nfs_node_unlock(np); 1126 if (wanted) 1127 wakeup(np); 1128} 1129 1130int 1131nfs_node_set_busy2(nfsnode_t np1, nfsnode_t np2, thread_t thd) 1132{ 1133 nfsnode_t first, second; 1134 int error; 1135 1136 first = (np1 > np2) ? np1 : np2; 1137 second = (np1 > np2) ? np2 : np1; 1138 if ((error = nfs_node_set_busy(first, thd))) 1139 return (error); 1140 if (np1 == np2) 1141 return (error); 1142 if ((error = nfs_node_set_busy(second, thd))) 1143 nfs_node_clear_busy(first); 1144 return (error); 1145} 1146 1147void 1148nfs_node_clear_busy2(nfsnode_t np1, nfsnode_t np2) 1149{ 1150 nfs_node_clear_busy(np1); 1151 if (np1 != np2) 1152 nfs_node_clear_busy(np2); 1153} 1154 1155/* helper function to sort four nodes in reverse address order (no dupes) */ 1156static void 1157nfs_node_sort4(nfsnode_t np1, nfsnode_t np2, nfsnode_t np3, nfsnode_t np4, nfsnode_t *list, int *lcntp) 1158{ 1159 nfsnode_t na[2], nb[2]; 1160 int a, b, i, lcnt; 1161 1162 /* sort pairs then merge */ 1163 na[0] = (np1 > np2) ? np1 : np2; 1164 na[1] = (np1 > np2) ? np2 : np1; 1165 nb[0] = (np3 > np4) ? np3 : np4; 1166 nb[1] = (np3 > np4) ? np4 : np3; 1167 for (a = b = i = lcnt = 0; i < 4; i++) { 1168 if (a >= 2) 1169 list[lcnt] = nb[b++]; 1170 else if ((b >= 2) || (na[a] >= nb[b])) 1171 list[lcnt] = na[a++]; 1172 else 1173 list[lcnt] = nb[b++]; 1174 if ((lcnt <= 0) || (list[lcnt] != list[lcnt-1])) 1175 lcnt++; /* omit dups */ 1176 } 1177 if (list[lcnt-1] == NULL) 1178 lcnt--; 1179 *lcntp = lcnt; 1180} 1181 1182int 1183nfs_node_set_busy4(nfsnode_t np1, nfsnode_t np2, nfsnode_t np3, nfsnode_t np4, thread_t thd) 1184{ 1185 nfsnode_t list[4]; 1186 int i, lcnt, error; 1187 1188 nfs_node_sort4(np1, np2, np3, np4, list, &lcnt); 1189 1190 /* Now we can lock using list[0 - lcnt-1] */ 1191 for (i = 0; i < lcnt; ++i) 1192 if ((error = nfs_node_set_busy(list[i], thd))) { 1193 /* Drop any locks we acquired. */ 1194 while (--i >= 0) 1195 nfs_node_clear_busy(list[i]); 1196 return (error); 1197 } 1198 return (0); 1199} 1200 1201void 1202nfs_node_clear_busy4(nfsnode_t np1, nfsnode_t np2, nfsnode_t np3, nfsnode_t np4) 1203{ 1204 nfsnode_t list[4]; 1205 int lcnt; 1206 1207 nfs_node_sort4(np1, np2, np3, np4, list, &lcnt); 1208 while (--lcnt >= 0) 1209 nfs_node_clear_busy(list[lcnt]); 1210} 1211 1212/* 1213 * Acquire an NFS node data lock 1214 */ 1215void 1216nfs_data_lock(nfsnode_t np, int locktype) 1217{ 1218 nfs_data_lock_internal(np, locktype, 1); 1219} 1220void 1221nfs_data_lock_noupdate(nfsnode_t np, int locktype) 1222{ 1223 nfs_data_lock_internal(np, locktype, 0); 1224} 1225void 1226nfs_data_lock_internal(nfsnode_t np, int locktype, int updatesize) 1227{ 1228 FSDBG_TOP(270, np, locktype, np->n_datalockowner, 0); 1229 if (locktype == NFS_DATA_LOCK_SHARED) { 1230 if (updatesize && ISSET(np->n_flag, NUPDATESIZE)) 1231 nfs_data_update_size(np, 0); 1232 lck_rw_lock_shared(&np->n_datalock); 1233 } else { 1234 lck_rw_lock_exclusive(&np->n_datalock); 1235 np->n_datalockowner = current_thread(); 1236 if (updatesize && ISSET(np->n_flag, NUPDATESIZE)) 1237 nfs_data_update_size(np, 1); 1238 } 1239 FSDBG_BOT(270, np, locktype, np->n_datalockowner, 0); 1240} 1241 1242/* 1243 * Release an NFS node data lock 1244 */ 1245void 1246nfs_data_unlock(nfsnode_t np) 1247{ 1248 nfs_data_unlock_internal(np, 1); 1249} 1250void 1251nfs_data_unlock_noupdate(nfsnode_t np) 1252{ 1253 nfs_data_unlock_internal(np, 0); 1254} 1255void 1256nfs_data_unlock_internal(nfsnode_t np, int updatesize) 1257{ 1258 int mine = (np->n_datalockowner == current_thread()); 1259 FSDBG_TOP(271, np, np->n_datalockowner, current_thread(), 0); 1260 if (updatesize && mine && ISSET(np->n_flag, NUPDATESIZE)) 1261 nfs_data_update_size(np, 1); 1262 np->n_datalockowner = NULL; 1263 lck_rw_done(&np->n_datalock); 1264 if (updatesize && !mine && ISSET(np->n_flag, NUPDATESIZE)) 1265 nfs_data_update_size(np, 0); 1266 FSDBG_BOT(271, np, np->n_datalockowner, current_thread(), 0); 1267} 1268 1269 1270/* 1271 * update an NFS node's size 1272 */ 1273void 1274nfs_data_update_size(nfsnode_t np, int datalocked) 1275{ 1276 int error; 1277 1278 FSDBG_TOP(272, np, np->n_flag, np->n_size, np->n_newsize); 1279 if (!datalocked) { 1280 nfs_data_lock(np, NFS_DATA_LOCK_EXCLUSIVE); 1281 /* grabbing data lock will automatically update size */ 1282 nfs_data_unlock(np); 1283 FSDBG_BOT(272, np, np->n_flag, np->n_size, np->n_newsize); 1284 return; 1285 } 1286 error = nfs_node_lock(np); 1287 if (error || !ISSET(np->n_flag, NUPDATESIZE)) { 1288 if (!error) 1289 nfs_node_unlock(np); 1290 FSDBG_BOT(272, np, np->n_flag, np->n_size, np->n_newsize); 1291 return; 1292 } 1293 CLR(np->n_flag, NUPDATESIZE); 1294 np->n_size = np->n_newsize; 1295 /* make sure we invalidate buffers the next chance we get */ 1296 SET(np->n_flag, NNEEDINVALIDATE); 1297 nfs_node_unlock(np); 1298 ubc_setsize(NFSTOV(np), (off_t)np->n_size); /* XXX error? */ 1299 FSDBG_BOT(272, np, np->n_flag, np->n_size, np->n_newsize); 1300} 1301 1302#define DODEBUG 1 1303int 1304nfs_mount_is_dirty(mount_t mp) 1305{ 1306 u_long i; 1307 nfsnode_t np; 1308#ifdef DODEBUG 1309 struct timeval now, then, diff; 1310 u_long ncnt = 0; 1311 microuptime(&now); 1312#endif 1313 lck_mtx_lock(nfs_node_hash_mutex); 1314 for (i = 0; i <= nfsnodehash; i++) { 1315 LIST_FOREACH(np, &nfsnodehashtbl[i], n_hash) { 1316#ifdef DODEBUG 1317 ncnt++; 1318#endif 1319 if (np->n_mount == mp && !LIST_EMPTY(&np->n_dirtyblkhd)) 1320 goto out; 1321 } 1322 } 1323out: 1324 lck_mtx_unlock(nfs_node_hash_mutex); 1325#ifdef DODEBUG 1326 microuptime(&then); 1327 timersub(&then, &now, &diff); 1328 1329 printf("nfs_mount_is_dirty took %lld mics for %ld slots and %ld nodes return %d\n", 1330 (uint64_t)diff.tv_sec * 1000000LL + diff.tv_usec, i, ncnt, (i <= nfsnodehash)); 1331#endif 1332 1333 return (i <= nfsnodehash); 1334} 1335