]> git.saurik.com Git - apple/xnu.git/blame - bsd/nfs/nfs_node.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_node.c
CommitLineData
1c79356b 1/*
b0d623f7 2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 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.
8f6c56a5 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.
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
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.
8f6c56a5 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>
1c79356b 75#include <sys/vnode.h>
91447636 76#include <sys/ubc.h>
1c79356b
A
77#include <sys/malloc.h>
78
79#include <nfs/rpcv2.h>
80#include <nfs/nfsproto.h>
81#include <nfs/nfs.h>
82#include <nfs/nfsnode.h>
2d21ac55 83#include <nfs/nfs_gss.h>
1c79356b
A
84#include <nfs/nfsmount.h>
85
2d21ac55
A
86#define NFSNOHASH(fhsum) \
87 (&nfsnodehashtbl[(fhsum) & nfsnodehash])
88static LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl;
89static u_long nfsnodehash;
1c79356b 90
2d21ac55
A
91static lck_grp_t *nfs_node_hash_lck_grp;
92static lck_grp_t *nfs_node_lck_grp;
b0d623f7 93static lck_grp_t *nfs_data_lck_grp;
91447636 94lck_mtx_t *nfs_node_hash_mutex;
1c79356b
A
95
96/*
97 * Initialize hash links for nfsnodes
98 * and build nfsnode free list.
99 */
100void
e5568f75 101nfs_nhinit(void)
1c79356b 102{
2d21ac55
A
103 nfs_node_hash_lck_grp = lck_grp_alloc_init("nfs_node_hash", LCK_GRP_ATTR_NULL);
104 nfs_node_hash_mutex = lck_mtx_alloc_init(nfs_node_hash_lck_grp, LCK_ATTR_NULL);
105 nfs_node_lck_grp = lck_grp_alloc_init("nfs_node", LCK_GRP_ATTR_NULL);
b0d623f7 106 nfs_data_lck_grp = lck_grp_alloc_init("nfs_data", LCK_GRP_ATTR_NULL);
2d21ac55 107}
91447636 108
2d21ac55
A
109void
110nfs_nhinit_finish(void)
111{
112 lck_mtx_lock(nfs_node_hash_mutex);
113 if (!nfsnodehashtbl)
114 nfsnodehashtbl = hashinit(desiredvnodes, M_NFSNODE, &nfsnodehash);
115 lck_mtx_unlock(nfs_node_hash_mutex);
1c79356b
A
116}
117
118/*
119 * Compute an entry in the NFS hash table structure
120 */
121u_long
91447636 122nfs_hash(u_char *fhp, int fhsize)
1c79356b 123{
91447636
A
124 u_long fhsum;
125 int i;
1c79356b 126
1c79356b
A
127 fhsum = 0;
128 for (i = 0; i < fhsize; i++)
91447636 129 fhsum += *fhp++;
1c79356b
A
130 return (fhsum);
131}
132
133/*
134 * Look up a vnode/nfsnode by file handle.
135 * Callers must check for mount points!!
136 * In all cases, a pointer to a
137 * nfsnode structure is returned.
138 */
1c79356b 139int
91447636 140nfs_nget(
2d21ac55
A
141 mount_t mp,
142 nfsnode_t dnp,
91447636
A
143 struct componentname *cnp,
144 u_char *fhp,
145 int fhsize,
146 struct nfs_vattr *nvap,
147 u_int64_t *xidp,
148 int flags,
2d21ac55 149 nfsnode_t *npp)
1c79356b 150{
2d21ac55 151 nfsnode_t np;
1c79356b 152 struct nfsnodehashhead *nhpp;
2d21ac55
A
153 vnode_t vp;
154 int error, nfsvers;
155 mount_t mp2;
91447636
A
156 struct vnode_fsparam vfsp;
157 uint32_t vid;
1c79356b 158
2d21ac55
A
159 FSDBG_TOP(263, mp, dnp, flags, npp);
160
1c79356b 161 /* Check for unmount in progress */
2d21ac55
A
162 if (!mp || (mp->mnt_kern_flag & MNTK_FRCUNMOUNT)) {
163 *npp = NULL;
164 error = ENXIO;
165 FSDBG_BOT(263, mp, dnp, 0xd1e, error);
166 return (error);
1c79356b 167 }
2d21ac55 168 nfsvers = VFSTONFS(mp)->nm_vers;
1c79356b
A
169
170 nhpp = NFSNOHASH(nfs_hash(fhp, fhsize));
171loop:
91447636 172 lck_mtx_lock(nfs_node_hash_mutex);
1c79356b 173 for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
2d21ac55
A
174 mp2 = (np->n_hflag & NHINIT) ? np->n_mount : NFSTOMP(np);
175 if (mp != mp2 || np->n_fhsize != fhsize ||
91447636 176 bcmp(fhp, np->n_fhp, fhsize))
1c79356b 177 continue;
2d21ac55
A
178 FSDBG(263, dnp, np, np->n_flag, 0xcace0000);
179 /* if the node is locked, sleep on it */
b0d623f7 180 if ((np->n_hflag & NHLOCKED) && !(flags & NG_NOCREATE)) {
2d21ac55
A
181 np->n_hflag |= NHLOCKWANT;
182 FSDBG(263, dnp, np, np->n_flag, 0xcace2222);
183 msleep(np, nfs_node_hash_mutex, PDROP | PINOD, "nfs_nget", NULL);
184 FSDBG(263, dnp, np, np->n_flag, 0xcace3333);
55e303ae
A
185 goto loop;
186 }
1c79356b 187 vp = NFSTOV(np);
91447636
A
188 vid = vnode_vid(vp);
189 lck_mtx_unlock(nfs_node_hash_mutex);
190 if ((error = vnode_getwithvid(vp, vid))) {
191 /*
192 * If vnode is being reclaimed or has already
193 * changed identity, no need to wait.
194 */
2d21ac55 195 FSDBG_BOT(263, dnp, *npp, 0xcace0d1e, error);
91447636 196 return (error);
2d21ac55 197 }
b0d623f7 198 if ((error = nfs_node_lock(np))) {
2d21ac55
A
199 /* this only fails if the node is now unhashed */
200 /* so let's see if we can find/create it again */
201 FSDBG(263, dnp, *npp, 0xcaced1e2, error);
202 vnode_put(vp);
b0d623f7
A
203 if (flags & NG_NOCREATE) {
204 *npp = 0;
205 FSDBG_BOT(263, dnp, *npp, 0xcaced1e0, ENOENT);
206 return (ENOENT);
207 }
2d21ac55
A
208 goto loop;
209 }
91447636 210 /* update attributes */
b0d623f7
A
211 if (nvap)
212 error = nfs_loadattrcache(np, nvap, xidp, 0);
91447636 213 if (error) {
b0d623f7 214 nfs_node_unlock(np);
91447636
A
215 vnode_put(vp);
216 } else {
2d21ac55
A
217 if (dnp && cnp && (flags & NG_MAKEENTRY))
218 cache_enter(NFSTOV(dnp), vp, cnp);
91447636 219 *npp = np;
1c79356b 220 }
2d21ac55 221 FSDBG_BOT(263, dnp, *npp, 0xcace0000, error);
91447636 222 return(error);
1c79356b 223 }
1c79356b 224
2d21ac55
A
225 FSDBG(263, mp, dnp, npp, 0xaaaaaaaa);
226
b0d623f7
A
227 if (flags & NG_NOCREATE) {
228 lck_mtx_unlock(nfs_node_hash_mutex);
229 *npp = 0;
230 FSDBG_BOT(263, dnp, *npp, 0x80000001, ENOENT);
231 return (ENOENT);
232 }
233
1c79356b 234 /*
55e303ae
A
235 * allocate and initialize nfsnode and stick it in the hash
236 * before calling getnewvnode(). Anyone finding it in the
237 * hash before initialization is complete will wait for it.
1c79356b 238 */
2d21ac55 239 MALLOC_ZONE(np, nfsnode_t, sizeof *np, M_NFSNODE, M_WAITOK);
91447636
A
240 if (!np) {
241 lck_mtx_unlock(nfs_node_hash_mutex);
242 *npp = 0;
2d21ac55 243 FSDBG_BOT(263, dnp, *npp, 0x80000001, ENOMEM);
91447636
A
244 return (ENOMEM);
245 }
2d21ac55
A
246 bzero(np, sizeof *np);
247 np->n_hflag |= (NHINIT | NHLOCKED);
248 np->n_mount = mp;
b0d623f7
A
249 TAILQ_INIT(&np->n_opens);
250 TAILQ_INIT(&np->n_lock_owners);
251 TAILQ_INIT(&np->n_locks);
252 np->n_dlink.tqe_next = NFSNOLIST;
2d21ac55
A
253
254 if (dnp && cnp && ((cnp->cn_namelen != 2) ||
255 (cnp->cn_nameptr[0] != '.') || (cnp->cn_nameptr[1] != '.'))) {
256 vnode_t dvp = NFSTOV(dnp);
257 if (!vnode_get(dvp)) {
258 if (!vnode_ref(dvp))
259 np->n_parent = dvp;
260 vnode_put(dvp);
261 }
262 }
55e303ae 263
91447636 264 /* setup node's file handle */
1c79356b 265 if (fhsize > NFS_SMALLFH) {
91447636 266 MALLOC_ZONE(np->n_fhp, u_char *,
1c79356b 267 fhsize, M_NFSBIGFH, M_WAITOK);
91447636
A
268 if (!np->n_fhp) {
269 lck_mtx_unlock(nfs_node_hash_mutex);
270 FREE_ZONE(np, sizeof *np, M_NFSNODE);
271 *npp = 0;
2d21ac55 272 FSDBG_BOT(263, dnp, *npp, 0x80000002, ENOMEM);
91447636
A
273 return (ENOMEM);
274 }
275 } else {
276 np->n_fhp = &np->n_fh[0];
277 }
278 bcopy(fhp, np->n_fhp, fhsize);
1c79356b 279 np->n_fhsize = fhsize;
91447636
A
280
281 /* Insert the nfsnode in the hash queue for its new file handle */
91447636 282 LIST_INSERT_HEAD(nhpp, np, n_hash);
2d21ac55
A
283 np->n_hflag |= NHHASHED;
284 FSDBG(266, 0, np, np->n_flag, np->n_hflag);
285
286 /* lock the new nfsnode */
b0d623f7
A
287 lck_mtx_init(&np->n_lock, nfs_node_lck_grp, LCK_ATTR_NULL);
288 lck_rw_init(&np->n_datalock, nfs_data_lck_grp, LCK_ATTR_NULL);
289 lck_mtx_init(&np->n_openlock, nfs_open_grp, LCK_ATTR_NULL);
290 lck_mtx_lock(&np->n_lock);
1c79356b 291
55e303ae 292 /* release lock on hash table */
91447636
A
293 lck_mtx_unlock(nfs_node_hash_mutex);
294
295 /* do initial loading of attributes */
296 error = nfs_loadattrcache(np, nvap, xidp, 1);
297 if (error) {
2d21ac55 298 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e);
b0d623f7 299 nfs_node_unlock(np);
91447636
A
300 lck_mtx_lock(nfs_node_hash_mutex);
301 LIST_REMOVE(np, n_hash);
2d21ac55
A
302 np->n_hflag &= ~(NHHASHED|NHINIT|NHLOCKED);
303 if (np->n_hflag & NHLOCKWANT) {
304 np->n_hflag &= ~NHLOCKWANT;
305 wakeup(np);
91447636
A
306 }
307 lck_mtx_unlock(nfs_node_hash_mutex);
2d21ac55
A
308 if (np->n_parent) {
309 if (!vnode_get(np->n_parent)) {
310 vnode_rele(np->n_parent);
311 vnode_put(np->n_parent);
312 }
313 np->n_parent = NULL;
314 }
b0d623f7
A
315 lck_mtx_destroy(&np->n_lock, nfs_node_lck_grp);
316 lck_rw_destroy(&np->n_datalock, nfs_data_lck_grp);
317 lck_mtx_destroy(&np->n_openlock, nfs_open_grp);
91447636
A
318 if (np->n_fhsize > NFS_SMALLFH)
319 FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH);
320 FREE_ZONE(np, sizeof *np, M_NFSNODE);
321 *npp = 0;
2d21ac55 322 FSDBG_BOT(263, dnp, *npp, 0x80000003, error);
91447636
A
323 return (error);
324 }
2d21ac55 325 NFS_CHANGED_UPDATE(nfsvers, np, nvap);
91447636 326 if (nvap->nva_type == VDIR)
2d21ac55 327 NFS_CHANGED_UPDATE_NC(nfsvers, np, nvap);
91447636 328 NMODEINVALIDATE(np);
1c79356b 329
55e303ae 330 /* now, attempt to get a new vnode */
2d21ac55 331 vfsp.vnfs_mp = mp;
91447636
A
332 vfsp.vnfs_vtype = nvap->nva_type;
333 vfsp.vnfs_str = "nfs";
2d21ac55 334 vfsp.vnfs_dvp = dnp ? NFSTOV(dnp) : NULL;
91447636 335 vfsp.vnfs_fsnode = np;
2d21ac55
A
336 if (nfsvers == NFS_VER4) {
337#if FIFO
338 if (nvap->nva_type == VFIFO)
339 vfsp.vnfs_vops = fifo_nfsv4nodeop_p;
340 else
341#endif /* FIFO */
342 if (nvap->nva_type == VBLK || nvap->nva_type == VCHR)
343 vfsp.vnfs_vops = spec_nfsv4nodeop_p;
344 else
345 vfsp.vnfs_vops = nfsv4_vnodeop_p;
346 } else {
347#if FIFO
348 if (nvap->nva_type == VFIFO)
349 vfsp.vnfs_vops = fifo_nfsv2nodeop_p;
350 else
351#endif /* FIFO */
352 if (nvap->nva_type == VBLK || nvap->nva_type == VCHR)
353 vfsp.vnfs_vops = spec_nfsv2nodeop_p;
354 else
355 vfsp.vnfs_vops = nfsv2_vnodeop_p;
356 }
91447636
A
357 vfsp.vnfs_markroot = (flags & NG_MARKROOT) ? 1 : 0;
358 vfsp.vnfs_marksystem = 0;
359 vfsp.vnfs_rdev = 0;
360 vfsp.vnfs_filesize = nvap->nva_size;
361 vfsp.vnfs_cnp = cnp;
2d21ac55
A
362 vfsp.vnfs_flags = VNFS_ADDFSREF;
363 if (!dnp || !cnp || !(flags & NG_MAKEENTRY))
364 vfsp.vnfs_flags |= VNFS_NOCACHE;
365
366 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &np->n_vnode);
55e303ae 367 if (error) {
2d21ac55 368 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e);
b0d623f7 369 nfs_node_unlock(np);
91447636 370 lck_mtx_lock(nfs_node_hash_mutex);
55e303ae 371 LIST_REMOVE(np, n_hash);
2d21ac55
A
372 np->n_hflag &= ~(NHHASHED|NHINIT|NHLOCKED);
373 if (np->n_hflag & NHLOCKWANT) {
374 np->n_hflag &= ~NHLOCKWANT;
375 wakeup(np);
91447636
A
376 }
377 lck_mtx_unlock(nfs_node_hash_mutex);
2d21ac55
A
378 if (np->n_parent) {
379 if (!vnode_get(np->n_parent)) {
380 vnode_rele(np->n_parent);
381 vnode_put(np->n_parent);
382 }
383 np->n_parent = NULL;
384 }
b0d623f7
A
385 lck_mtx_destroy(&np->n_lock, nfs_node_lck_grp);
386 lck_rw_destroy(&np->n_datalock, nfs_data_lck_grp);
387 lck_mtx_destroy(&np->n_openlock, nfs_open_grp);
55e303ae 388 if (np->n_fhsize > NFS_SMALLFH)
91447636 389 FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH);
55e303ae
A
390 FREE_ZONE(np, sizeof *np, M_NFSNODE);
391 *npp = 0;
2d21ac55 392 FSDBG_BOT(263, dnp, *npp, 0x80000004, error);
55e303ae
A
393 return (error);
394 }
2d21ac55
A
395 vp = np->n_vnode;
396 vnode_settag(vp, VT_NFS);
91447636 397 /* node is now initialized */
55e303ae 398
91447636
A
399 /* check if anyone's waiting on this node */
400 lck_mtx_lock(nfs_node_hash_mutex);
2d21ac55
A
401 np->n_hflag &= ~(NHINIT|NHLOCKED);
402 if (np->n_hflag & NHLOCKWANT) {
403 np->n_hflag &= ~NHLOCKWANT;
404 wakeup(np);
55e303ae 405 }
91447636 406 lck_mtx_unlock(nfs_node_hash_mutex);
1c79356b 407
2d21ac55
A
408 *npp = np;
409
410 FSDBG_BOT(263, dnp, vp, *npp, error);
fa4905b1 411 return (error);
1c79356b
A
412}
413
91447636 414
1c79356b 415int
2d21ac55 416nfs_vnop_inactive(ap)
91447636
A
417 struct vnop_inactive_args /* {
418 struct vnodeop_desc *a_desc;
419 vnode_t a_vp;
420 vfs_context_t a_context;
1c79356b
A
421 } */ *ap;
422{
b0d623f7
A
423 vnode_t vp = ap->a_vp;
424 vfs_context_t ctx = ap->a_context;
425 nfsnode_t np = VTONFS(ap->a_vp);
2d21ac55
A
426 struct nfs_sillyrename *nsp;
427 struct nfs_vattr nvattr;
b0d623f7
A
428 int unhash, attrerr, busyerror, error, inuse, busied;
429 struct nfs_open_file *nofp;
430 const char *vname = NULL;
431 struct componentname cn;
432 struct nfsmount *nmp = NFSTONMP(np);
433
434restart:
435 error = 0;
436 inuse = ((nmp->nm_vers >= NFS_VER4) && (nfs_mount_state_in_use_start(nmp) == 0));
437
438 /* There shouldn't be any open or lock state at this point */
439 lck_mtx_lock(&np->n_openlock);
440 if (np->n_openrefcnt) {
441 vname = vnode_getname(vp);
442 printf("nfs_vnop_inactive: still open: %d %s\n", np->n_openrefcnt, vname ? vname : "//");
443 }
444 TAILQ_FOREACH(nofp, &np->n_opens, nof_link) {
445 lck_mtx_lock(&nofp->nof_lock);
446 if (nofp->nof_flags & NFS_OPEN_FILE_BUSY) {
447 if (!vname)
448 vname = vnode_getname(vp);
449 printf("nfs_vnop_inactive: open file busy: %s\n", vname ? vname : "//");
450 busied = 0;
451 } else {
452 nofp->nof_flags |= NFS_OPEN_FILE_BUSY;
453 busied = 1;
454 }
455 lck_mtx_unlock(&nofp->nof_lock);
456 /*
457 * If we just created the file, we already had it open in
458 * anticipation of getting a subsequent open call. If the
459 * node has gone inactive without being open, we need to
460 * clean up (close) the open done in the create.
461 */
462 if ((nofp->nof_flags & NFS_OPEN_FILE_CREATE) && nofp->nof_creator) {
463 if (nofp->nof_flags & NFS_OPEN_FILE_REOPEN) {
464 lck_mtx_unlock(&np->n_openlock);
465 if (busied)
466 nfs_open_file_clear_busy(nofp);
467 if (inuse)
468 nfs_mount_state_in_use_end(nmp, 0);
469 nfs4_reopen(nofp, vfs_context_thread(ctx));
470 goto restart;
471 }
472 nofp->nof_flags &= ~NFS_OPEN_FILE_CREATE;
473 lck_mtx_unlock(&np->n_openlock);
474 error = nfs4_close(np, nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_NONE, ctx);
475 if (error) {
476 if (!vname)
477 vname = vnode_getname(vp);
478 printf("nfs_vnop_inactive: create close error: %d, %s\n", error, vname);
479 nofp->nof_flags |= NFS_OPEN_FILE_CREATE;
480 }
481 if (busied)
482 nfs_open_file_clear_busy(nofp);
483 if (inuse)
484 nfs_mount_state_in_use_end(nmp, error);
485 goto restart;
486 }
487 if (nofp->nof_flags & NFS_OPEN_FILE_NEEDCLOSE) {
488 /*
489 * If the file is marked as needing reopen, but this was the only
490 * open on the file, just drop the open.
491 */
492 nofp->nof_flags &= ~NFS_OPEN_FILE_NEEDCLOSE;
493 if ((nofp->nof_flags & NFS_OPEN_FILE_REOPEN) && (nofp->nof_opencnt == 1)) {
494 nofp->nof_flags &= ~NFS_OPEN_FILE_REOPEN;
495 nofp->nof_r--;
496 nofp->nof_opencnt--;
497 nofp->nof_access = 0;
498 } else {
499 lck_mtx_unlock(&np->n_openlock);
500 if (nofp->nof_flags & NFS_OPEN_FILE_REOPEN) {
501 if (busied)
502 nfs_open_file_clear_busy(nofp);
503 if (inuse)
504 nfs_mount_state_in_use_end(nmp, 0);
505 nfs4_reopen(nofp, vfs_context_thread(ctx));
506 goto restart;
507 }
508 error = nfs4_close(np, nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_NONE, ctx);
509 if (error) {
510 if (!vname)
511 vname = vnode_getname(vp);
512 printf("nfs_vnop_inactive: need close error: %d, %s\n", error, vname);
513 nofp->nof_flags |= NFS_OPEN_FILE_NEEDCLOSE;
514 }
515 if (busied)
516 nfs_open_file_clear_busy(nofp);
517 if (inuse)
518 nfs_mount_state_in_use_end(nmp, error);
519 goto restart;
520 }
521 }
522 if (nofp->nof_opencnt) {
523 if (!vname)
524 vname = vnode_getname(vp);
525 printf("nfs_vnop_inactive: file still open: %d %s\n", nofp->nof_opencnt, vname ? vname : "//");
526 }
527 if (nofp->nof_access || nofp->nof_deny ||
528 nofp->nof_mmap_access || nofp->nof_mmap_deny ||
529 nofp->nof_r || nofp->nof_w || nofp->nof_rw ||
530 nofp->nof_r_dw || nofp->nof_w_dw || nofp->nof_rw_dw ||
531 nofp->nof_r_drw || nofp->nof_w_drw || nofp->nof_rw_drw) {
532 if (!vname)
533 vname = vnode_getname(vp);
534 printf("nfs_vnop_inactive: non-zero access: %d %d %d %d # %u %u %u dw %u %u %u drw %u %u %u %s\n",
535 nofp->nof_access, nofp->nof_deny,
536 nofp->nof_mmap_access, nofp->nof_mmap_deny,
537 nofp->nof_r, nofp->nof_w, nofp->nof_rw,
538 nofp->nof_r_dw, nofp->nof_w_dw, nofp->nof_rw_dw,
539 nofp->nof_r_drw, nofp->nof_w_drw, nofp->nof_rw_drw,
540 vname ? vname : "//");
541 }
542 if (busied)
543 nfs_open_file_clear_busy(nofp);
544 }
545 lck_mtx_unlock(&np->n_openlock);
546 if (vname)
547 vnode_putname(vname);
1c79356b 548
b0d623f7
A
549 if (inuse && nfs_mount_state_in_use_end(nmp, error))
550 goto restart;
2d21ac55 551
b0d623f7 552 nfs_node_lock_force(np);
2d21ac55
A
553
554 if (vnode_vtype(vp) != VDIR) {
b0d623f7 555 nsp = np->n_sillyrename;
2d21ac55 556 np->n_sillyrename = NULL;
b0d623f7 557 } else {
2d21ac55 558 nsp = NULL;
b0d623f7 559 }
1c79356b 560
2d21ac55
A
561 FSDBG_TOP(264, vp, np, np->n_flag, nsp);
562
563 if (!nsp) {
564 /* no silly file to clean up... */
565 /* clear all flags other than these */
566 np->n_flag &= (NMODIFIED);
b0d623f7 567 nfs_node_unlock(np);
2d21ac55
A
568 FSDBG_BOT(264, vp, np, np->n_flag, 0);
569 return (0);
570 }
b0d623f7 571 nfs_node_unlock(np);
2d21ac55
A
572
573 /* Remove the silly file that was rename'd earlier */
574
575 /* flush all the buffers */
b0d623f7 576 nfs_vinvalbuf2(vp, V_SAVE, vfs_context_thread(ctx), nsp->nsr_cred, 1);
2d21ac55
A
577
578 /* try to get the latest attributes */
b0d623f7 579 attrerr = nfs_getattr(np, &nvattr, ctx, NGA_UNCACHED);
2d21ac55
A
580
581 /* Check if we should remove it from the node hash. */
582 /* Leave it if inuse or it has multiple hard links. */
583 if (vnode_isinuse(vp, 0) || (!attrerr && (nvattr.nva_nlink > 1))) {
584 unhash = 0;
585 } else {
586 unhash = 1;
587 ubc_setsize(vp, 0);
588 }
589
b0d623f7
A
590 /* mark this node and the directory busy while we do the remove */
591 busyerror = nfs_node_set_busy2(nsp->nsr_dnp, np, vfs_context_thread(ctx));
2d21ac55
A
592
593 /* lock the node while we remove the silly file */
594 lck_mtx_lock(nfs_node_hash_mutex);
595 while (np->n_hflag & NHLOCKED) {
596 np->n_hflag |= NHLOCKWANT;
597 msleep(np, nfs_node_hash_mutex, PINOD, "nfs_inactive", NULL);
598 }
599 np->n_hflag |= NHLOCKED;
600 lck_mtx_unlock(nfs_node_hash_mutex);
601
b0d623f7
A
602 /* purge the name cache to deter others from finding it */
603 bzero(&cn, sizeof(cn));
604 cn.cn_nameptr = nsp->nsr_name;
605 cn.cn_namelen = nsp->nsr_namlen;
606 nfs_name_cache_purge(nsp->nsr_dnp, np, &cn, ctx);
2d21ac55
A
607
608 FSDBG(264, np, np->n_size, np->n_vattr.nva_size, 0xf00d00f1);
609
610 /* now remove the silly file */
611 nfs_removeit(nsp);
612
613 /* clear all flags other than these */
b0d623f7 614 nfs_node_lock_force(np);
2d21ac55 615 np->n_flag &= (NMODIFIED);
b0d623f7
A
616 nfs_node_unlock(np);
617
618 if (!busyerror)
619 nfs_node_clear_busy2(nsp->nsr_dnp, np);
2d21ac55
A
620
621 if (unhash && vnode_isinuse(vp, 0)) {
622 /* vnode now inuse after silly remove? */
623 unhash = 0;
624 ubc_setsize(vp, np->n_size);
625 }
626
627 lck_mtx_lock(nfs_node_hash_mutex);
628 if (unhash) {
55e303ae
A
629 /*
630 * remove nfsnode from hash now so we can't accidentally find it
631 * again if another object gets created with the same filehandle
632 * before this vnode gets reclaimed
633 */
2d21ac55
A
634 if (np->n_hflag & NHHASHED) {
635 LIST_REMOVE(np, n_hash);
636 np->n_hflag &= ~NHHASHED;
637 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e);
1c79356b 638 }
2d21ac55 639 vnode_recycle(vp);
1c79356b 640 }
2d21ac55
A
641 /* unlock the node */
642 np->n_hflag &= ~NHLOCKED;
643 if (np->n_hflag & NHLOCKWANT) {
644 np->n_hflag &= ~NHLOCKWANT;
645 wakeup(np);
646 }
647 lck_mtx_unlock(nfs_node_hash_mutex);
648
649 /* cleanup sillyrename info */
650 if (nsp->nsr_cred != NOCRED)
651 kauth_cred_unref(&nsp->nsr_cred);
652 vnode_rele(NFSTOV(nsp->nsr_dnp));
653 FREE_ZONE(nsp, sizeof(*nsp), M_NFSREQ);
654
655 FSDBG_BOT(264, vp, np, np->n_flag, 0);
1c79356b
A
656 return (0);
657}
658
659/*
660 * Reclaim an nfsnode so that it can be used for other purposes.
661 */
662int
2d21ac55 663nfs_vnop_reclaim(ap)
91447636
A
664 struct vnop_reclaim_args /* {
665 struct vnodeop_desc *a_desc;
666 vnode_t a_vp;
667 vfs_context_t a_context;
1c79356b
A
668 } */ *ap;
669{
91447636 670 vnode_t vp = ap->a_vp;
2d21ac55 671 nfsnode_t np = VTONFS(vp);
b0d623f7
A
672 vfs_context_t ctx = ap->a_context;
673 struct nfs_open_file *nofp, *nextnofp;
674 struct nfs_file_lock *nflp, *nextnflp;
675 struct nfs_lock_owner *nlop, *nextnlop;
676 const char *vname = NULL;
677 struct nfsmount *nmp = np->n_mount ? VFSTONFS(np->n_mount) : NFSTONMP(np);
1c79356b 678
2d21ac55
A
679 FSDBG_TOP(265, vp, np, np->n_flag, 0);
680
b0d623f7
A
681 /* There shouldn't be any open or lock state at this point */
682 lck_mtx_lock(&np->n_openlock);
683
684 if (nmp && (nmp->nm_vers >= NFS_VER4)) {
685 /* need to drop a delegation */
686 if (np->n_dlink.tqe_next != NFSNOLIST) {
687 /* remove this node from the recall list */
688 lck_mtx_lock(&nmp->nm_lock);
689 if (np->n_dlink.tqe_next != NFSNOLIST) {
690 TAILQ_REMOVE(&nmp->nm_recallq, np, n_dlink);
691 np->n_dlink.tqe_next = NFSNOLIST;
692 }
693 lck_mtx_unlock(&nmp->nm_lock);
694 }
695 if (np->n_openflags & N_DELEG_MASK) {
696 np->n_openflags &= ~N_DELEG_MASK;
697 nfs4_delegreturn_rpc(nmp, np->n_fhp, np->n_fhsize, &np->n_dstateid,
698 vfs_context_thread(ctx), vfs_context_ucred(ctx));
699 }
700 }
701
702 /* clean up file locks */
703 TAILQ_FOREACH_SAFE(nflp, &np->n_locks, nfl_link, nextnflp) {
704 if (!(nflp->nfl_flags & NFS_FILE_LOCK_DEAD)) {
705 if (!vname)
706 vname = vnode_getname(vp);
707 printf("nfs_vnop_reclaim: lock 0x%llx 0x%llx 0x%x (bc %d) %s\n",
708 nflp->nfl_start, nflp->nfl_end, nflp->nfl_flags,
709 nflp->nfl_blockcnt, vname ? vname : "//");
710 }
711 if (!(nflp->nfl_flags & NFS_FILE_LOCK_BLOCKED)) {
712 lck_mtx_lock(&nflp->nfl_owner->nlo_lock);
713 TAILQ_REMOVE(&nflp->nfl_owner->nlo_locks, nflp, nfl_lolink);
714 lck_mtx_unlock(&nflp->nfl_owner->nlo_lock);
715 }
716 TAILQ_REMOVE(&np->n_locks, nflp, nfl_link);
717 nfs_file_lock_destroy(nflp);
718 }
719 /* clean up lock owners */
720 TAILQ_FOREACH_SAFE(nlop, &np->n_lock_owners, nlo_link, nextnlop) {
721 if (!TAILQ_EMPTY(&nlop->nlo_locks)) {
722 if (!vname)
723 vname = vnode_getname(vp);
724 printf("nfs_vnop_reclaim: lock owner with locks %s\n",
725 vname ? vname : "//");
726 }
727 TAILQ_REMOVE(&np->n_lock_owners, nlop, nlo_link);
728 nfs_lock_owner_destroy(nlop);
729 }
730 /* clean up open state */
731 if (np->n_openrefcnt) {
732 if (!vname)
733 vname = vnode_getname(vp);
734 printf("nfs_vnop_reclaim: still open: %d %s\n",
735 np->n_openrefcnt, vname ? vname : "//");
736 }
737 TAILQ_FOREACH_SAFE(nofp, &np->n_opens, nof_link, nextnofp) {
738 if (nofp->nof_flags & NFS_OPEN_FILE_BUSY) {
739 if (!vname)
740 vname = vnode_getname(vp);
741 printf("nfs_vnop_reclaim: open file busy: %s\n",
742 vname ? vname : "//");
743 }
744 if (nofp->nof_opencnt) {
745 if (!vname)
746 vname = vnode_getname(vp);
747 printf("nfs_vnop_reclaim: file still open: %d %s\n",
748 nofp->nof_opencnt, vname ? vname : "//");
749 }
750 if (nofp->nof_access || nofp->nof_deny ||
751 nofp->nof_mmap_access || nofp->nof_mmap_deny ||
752 nofp->nof_r || nofp->nof_w || nofp->nof_rw ||
753 nofp->nof_r_dw || nofp->nof_w_dw || nofp->nof_rw_dw ||
754 nofp->nof_r_drw || nofp->nof_w_drw || nofp->nof_rw_drw) {
755 if (!vname)
756 vname = vnode_getname(vp);
757 printf("nfs_vnop_reclaim: non-zero access: %d %d %d %d # %u %u %u dw %u %u %u drw %u %u %u %s\n",
758 nofp->nof_access, nofp->nof_deny,
759 nofp->nof_mmap_access, nofp->nof_mmap_deny,
760 nofp->nof_r, nofp->nof_w, nofp->nof_rw,
761 nofp->nof_r_dw, nofp->nof_w_dw, nofp->nof_rw_dw,
762 nofp->nof_r_drw, nofp->nof_w_drw, nofp->nof_rw_drw,
763 vname ? vname : "//");
764 }
765 TAILQ_REMOVE(&np->n_opens, nofp, nof_link);
766 nfs_open_file_destroy(nofp);
767 }
768 lck_mtx_unlock(&np->n_openlock);
769
770 lck_mtx_lock(nfs_buf_mutex);
771 if (!LIST_EMPTY(&np->n_dirtyblkhd) || !LIST_EMPTY(&np->n_cleanblkhd)) {
772 if (!vname)
773 vname = vnode_getname(vp);
774 printf("nfs_reclaim: dropping %s buffers for file %s\n",
775 (!LIST_EMPTY(&np->n_dirtyblkhd) ? "dirty" : "clean"),
776 (vname ? vname : "//"));
777 }
778 lck_mtx_unlock(nfs_buf_mutex);
779 if (vname)
780 vnode_putname(vname);
781 nfs_vinvalbuf(vp, V_IGNORE_WRITEERR, ap->a_context, 0);
782
2d21ac55
A
783 lck_mtx_lock(nfs_node_hash_mutex);
784
b0d623f7 785 if ((vnode_vtype(vp) != VDIR) && np->n_sillyrename) {
2d21ac55 786 printf("nfs_reclaim: leaving unlinked file %s\n", np->n_sillyrename->nsr_name);
b0d623f7
A
787 if (np->n_sillyrename->nsr_cred != NOCRED)
788 kauth_cred_unref(&np->n_sillyrename->nsr_cred);
789 vnode_rele(NFSTOV(np->n_sillyrename->nsr_dnp));
790 FREE_ZONE(np->n_sillyrename, sizeof(*np->n_sillyrename), M_NFSREQ);
791 }
2d21ac55 792
91447636 793 vnode_removefsref(vp);
1c79356b 794
2d21ac55 795 if (np->n_hflag & NHHASHED) {
55e303ae 796 LIST_REMOVE(np, n_hash);
2d21ac55
A
797 np->n_hflag &= ~NHHASHED;
798 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e);
1c79356b 799 }
2d21ac55 800 lck_mtx_unlock(nfs_node_hash_mutex);
1c79356b
A
801
802 /*
b0d623f7
A
803 * Free up any directory cookie structures and large file handle
804 * structures that might be associated with this nfs node.
1c79356b 805 */
b0d623f7
A
806 nfs_node_lock_force(np);
807 if ((vnode_vtype(vp) == VDIR) && np->n_cookiecache)
808 FREE_ZONE(np->n_cookiecache, sizeof(struct nfsdmap), M_NFSDIROFF);
809 if (np->n_fhsize > NFS_SMALLFH)
91447636 810 FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH);
b0d623f7 811 nfs_node_unlock(np);
91447636 812 vnode_clearfsnode(vp);
1c79356b 813
2d21ac55
A
814 if (np->n_parent) {
815 if (!vnode_get(np->n_parent)) {
816 vnode_rele(np->n_parent);
817 vnode_put(np->n_parent);
818 }
819 np->n_parent = NULL;
820 }
821
b0d623f7
A
822 lck_mtx_destroy(&np->n_lock, nfs_node_lck_grp);
823 lck_rw_destroy(&np->n_datalock, nfs_data_lck_grp);
824 lck_mtx_destroy(&np->n_openlock, nfs_open_grp);
2d21ac55
A
825
826 FSDBG_BOT(265, vp, np, np->n_flag, 0xd1ed1e);
91447636 827 FREE_ZONE(np, sizeof(struct nfsnode), M_NFSNODE);
1c79356b
A
828 return (0);
829}
830
2d21ac55
A
831/*
832 * Acquire an NFS node lock
833 */
b0d623f7 834
2d21ac55 835int
b0d623f7 836nfs_node_lock_internal(nfsnode_t np, int force)
2d21ac55 837{
b0d623f7
A
838 FSDBG_TOP(268, np, force, 0, 0);
839 lck_mtx_lock(&np->n_lock);
840 if (!force && !(np->n_hflag && NHHASHED)) {
841 FSDBG_BOT(268, np, 0xdead, 0, 0);
842 lck_mtx_unlock(&np->n_lock);
2d21ac55
A
843 return (ENOENT);
844 }
b0d623f7 845 FSDBG_BOT(268, np, force, 0, 0);
2d21ac55
A
846 return (0);
847}
848
b0d623f7
A
849int
850nfs_node_lock(nfsnode_t np)
851{
852 return nfs_node_lock_internal(np, 0);
853}
854
855void
856nfs_node_lock_force(nfsnode_t np)
857{
858 nfs_node_lock_internal(np, 1);
859}
860
2d21ac55
A
861/*
862 * Release an NFS node lock
863 */
864void
b0d623f7 865nfs_node_unlock(nfsnode_t np)
2d21ac55 866{
b0d623f7
A
867 FSDBG(269, np, current_thread(), 0, 0);
868 lck_mtx_unlock(&np->n_lock);
2d21ac55
A
869}
870
871/*
872 * Acquire 2 NFS node locks
b0d623f7 873 * - locks taken in reverse address order
2d21ac55
A
874 * - both or neither of the locks are taken
875 * - only one lock taken per node (dup nodes are skipped)
876 */
877int
b0d623f7 878nfs_node_lock2(nfsnode_t np1, nfsnode_t np2)
2d21ac55 879{
b0d623f7 880 nfsnode_t first, second;
2d21ac55
A
881 int error;
882
b0d623f7
A
883 first = (np1 > np2) ? np1 : np2;
884 second = (np1 > np2) ? np2 : np1;
885 if ((error = nfs_node_lock(first)))
2d21ac55
A
886 return (error);
887 if (np1 == np2)
888 return (error);
b0d623f7
A
889 if ((error = nfs_node_lock(second)))
890 nfs_node_unlock(first);
2d21ac55
A
891 return (error);
892}
893
2d21ac55 894void
b0d623f7 895nfs_node_unlock2(nfsnode_t np1, nfsnode_t np2)
2d21ac55 896{
b0d623f7 897 nfs_node_unlock(np1);
2d21ac55 898 if (np1 != np2)
b0d623f7 899 nfs_node_unlock(np2);
2d21ac55
A
900}
901
902/*
b0d623f7
A
903 * Manage NFS node busy state.
904 * (Similar to NFS node locks above)
2d21ac55
A
905 */
906int
b0d623f7 907nfs_node_set_busy(nfsnode_t np, thread_t thd)
2d21ac55 908{
b0d623f7
A
909 struct timespec ts = { 2, 0 };
910 int error;
911
912 if ((error = nfs_node_lock(np)))
913 return (error);
914 while (ISSET(np->n_flag, NBUSY)) {
915 SET(np->n_flag, NBUSYWANT);
916 msleep(np, &np->n_lock, PZERO-1, "nfsbusywant", &ts);
917 if ((error = nfs_sigintr(NFSTONMP(np), NULL, thd, 0)))
918 break;
2d21ac55 919 }
b0d623f7
A
920 if (!error)
921 SET(np->n_flag, NBUSY);
922 nfs_node_unlock(np);
923 return (error);
924}
2d21ac55 925
b0d623f7
A
926void
927nfs_node_clear_busy(nfsnode_t np)
928{
929 int wanted;
930
931 nfs_node_lock_force(np);
932 wanted = ISSET(np->n_flag, NBUSYWANT);
933 CLR(np->n_flag, NBUSY|NBUSYWANT);
934 nfs_node_unlock(np);
935 if (wanted)
936 wakeup(np);
937}
938
939int
940nfs_node_set_busy2(nfsnode_t np1, nfsnode_t np2, thread_t thd)
941{
942 nfsnode_t first, second;
943 int error;
944
945 first = (np1 > np2) ? np1 : np2;
946 second = (np1 > np2) ? np2 : np1;
947 if ((error = nfs_node_set_busy(first, thd)))
948 return (error);
949 if (np1 == np2)
950 return (error);
951 if ((error = nfs_node_set_busy(second, thd)))
952 nfs_node_clear_busy(first);
953 return (error);
954}
955
956void
957nfs_node_clear_busy2(nfsnode_t np1, nfsnode_t np2)
958{
959 nfs_node_clear_busy(np1);
960 if (np1 != np2)
961 nfs_node_clear_busy(np2);
962}
963
964/* helper function to sort four nodes in reverse address order (no dupes) */
965static void
966nfs_node_sort4(nfsnode_t np1, nfsnode_t np2, nfsnode_t np3, nfsnode_t np4, nfsnode_t *list, int *lcntp)
967{
968 nfsnode_t na[2], nb[2];
969 int a, b, i, lcnt;
970
971 /* sort pairs then merge */
972 na[0] = (np1 > np2) ? np1 : np2;
973 na[1] = (np1 > np2) ? np2 : np1;
974 nb[0] = (np3 > np4) ? np3 : np4;
975 nb[1] = (np3 > np4) ? np4 : np3;
976 for (a = b = i = lcnt = 0; i < 4; i++) {
977 if (a >= 2)
978 list[lcnt] = nb[b++];
979 else if ((b >= 2) || (na[a] >= nb[b]))
980 list[lcnt] = na[a++];
981 else
982 list[lcnt] = nb[b++];
983 if ((lcnt <= 0) || (list[lcnt] != list[lcnt-1]))
984 lcnt++; /* omit dups */
2d21ac55 985 }
b0d623f7
A
986 if (list[lcnt-1] == NULL)
987 lcnt--;
988 *lcntp = lcnt;
989}
990
991int
992nfs_node_set_busy4(nfsnode_t np1, nfsnode_t np2, nfsnode_t np3, nfsnode_t np4, thread_t thd)
993{
994 nfsnode_t list[4];
995 int i, lcnt, error;
996
997 nfs_node_sort4(np1, np2, np3, np4, list, &lcnt);
2d21ac55
A
998
999 /* Now we can lock using list[0 - lcnt-1] */
b0d623f7
A
1000 for (i = 0; i < lcnt; ++i)
1001 if ((error = nfs_node_set_busy(list[i], thd))) {
1002 /* Drop any locks we acquired. */
1003 while (--i >= 0)
1004 nfs_node_clear_busy(list[i]);
1005 return (error);
1006 }
2d21ac55
A
1007 return (0);
1008}
1009
2d21ac55 1010void
b0d623f7 1011nfs_node_clear_busy4(nfsnode_t np1, nfsnode_t np2, nfsnode_t np3, nfsnode_t np4)
2d21ac55
A
1012{
1013 nfsnode_t list[4];
b0d623f7
A
1014 int lcnt;
1015
1016 nfs_node_sort4(np1, np2, np3, np4, list, &lcnt);
1017 while (--lcnt >= 0)
1018 nfs_node_clear_busy(list[lcnt]);
2d21ac55
A
1019}
1020
1021/*
1022 * Acquire an NFS node data lock
1023 */
1024void
1025nfs_data_lock(nfsnode_t np, int locktype)
1026{
b0d623f7
A
1027 nfs_data_lock_internal(np, locktype, 1);
1028}
1029void
1030nfs_data_lock_noupdate(nfsnode_t np, int locktype)
1031{
1032 nfs_data_lock_internal(np, locktype, 0);
2d21ac55
A
1033}
1034void
b0d623f7 1035nfs_data_lock_internal(nfsnode_t np, int locktype, int updatesize)
2d21ac55
A
1036{
1037 FSDBG_TOP(270, np, locktype, np->n_datalockowner, 0);
b0d623f7 1038 if (locktype == NFS_DATA_LOCK_SHARED) {
2d21ac55
A
1039 if (updatesize && ISSET(np->n_flag, NUPDATESIZE))
1040 nfs_data_update_size(np, 0);
1041 lck_rw_lock_shared(&np->n_datalock);
1042 } else {
1043 lck_rw_lock_exclusive(&np->n_datalock);
1044 np->n_datalockowner = current_thread();
1045 if (updatesize && ISSET(np->n_flag, NUPDATESIZE))
1046 nfs_data_update_size(np, 1);
1047 }
1048 FSDBG_BOT(270, np, locktype, np->n_datalockowner, 0);
1049}
1050
1051/*
1052 * Release an NFS node data lock
1053 */
1054void
1055nfs_data_unlock(nfsnode_t np)
1056{
b0d623f7
A
1057 nfs_data_unlock_internal(np, 1);
1058}
1059void
1060nfs_data_unlock_noupdate(nfsnode_t np)
1061{
1062 nfs_data_unlock_internal(np, 0);
2d21ac55
A
1063}
1064void
b0d623f7 1065nfs_data_unlock_internal(nfsnode_t np, int updatesize)
2d21ac55
A
1066{
1067 int mine = (np->n_datalockowner == current_thread());
1068 FSDBG_TOP(271, np, np->n_datalockowner, current_thread(), 0);
1069 if (updatesize && mine && ISSET(np->n_flag, NUPDATESIZE))
1070 nfs_data_update_size(np, 1);
1071 np->n_datalockowner = NULL;
1072 lck_rw_done(&np->n_datalock);
1073 if (updatesize && !mine && ISSET(np->n_flag, NUPDATESIZE))
1074 nfs_data_update_size(np, 0);
1075 FSDBG_BOT(271, np, np->n_datalockowner, current_thread(), 0);
1076}
1077
1078
1079/*
1080 * update an NFS node's size
1081 */
1082void
1083nfs_data_update_size(nfsnode_t np, int datalocked)
1084{
1085 int error;
1086
1087 FSDBG_TOP(272, np, np->n_flag, np->n_size, np->n_newsize);
1088 if (!datalocked) {
b0d623f7 1089 nfs_data_lock(np, NFS_DATA_LOCK_EXCLUSIVE);
2d21ac55
A
1090 /* grabbing data lock will automatically update size */
1091 nfs_data_unlock(np);
1092 FSDBG_BOT(272, np, np->n_flag, np->n_size, np->n_newsize);
1093 return;
1094 }
b0d623f7 1095 error = nfs_node_lock(np);
2d21ac55
A
1096 if (error || !ISSET(np->n_flag, NUPDATESIZE)) {
1097 if (!error)
b0d623f7 1098 nfs_node_unlock(np);
2d21ac55
A
1099 FSDBG_BOT(272, np, np->n_flag, np->n_size, np->n_newsize);
1100 return;
1101 }
1102 CLR(np->n_flag, NUPDATESIZE);
1103 np->n_size = np->n_newsize;
1104 /* make sure we invalidate buffers the next chance we get */
1105 SET(np->n_flag, NNEEDINVALIDATE);
b0d623f7 1106 nfs_node_unlock(np);
2d21ac55
A
1107 ubc_setsize(NFSTOV(np), (off_t)np->n_size); /* XXX error? */
1108 FSDBG_BOT(272, np, np->n_flag, np->n_size, np->n_newsize);
1109}
1110