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