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