]>
git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_node.c
383428171e7937d522f16f462ea30270819e2078
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
27 * This code is derived from software contributed to Berkeley by
28 * Rick Macklem at The University of Guelph.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95
59 * FreeBSD-Id: nfs_node.c,v 1.22 1997/10/28 14:06:20 bde Exp $
63 #include <sys/param.h>
64 #include <sys/systm.h>
66 #include <sys/mount.h>
67 #include <sys/namei.h>
68 #include <sys/vnode.h>
69 #include <sys/malloc.h>
71 #include <nfs/rpcv2.h>
72 #include <nfs/nfsproto.h>
74 #include <nfs/nfsnode.h>
75 #include <nfs/nfsmount.h>
78 static MALLOC_DEFINE(M_NFSNODE
, "NFS node", "NFS vnode private part");
81 LIST_HEAD(nfsnodehashhead
, nfsnode
) *nfsnodehashtbl
;
88 * Initialize hash links for nfsnodes
89 * and build nfsnode free list.
94 nfsnodehashtbl
= hashinit(desiredvnodes
, M_NFSNODE
, &nfsnodehash
);
98 * Compute an entry in the NFS hash table structure
101 nfs_hash(fhp
, fhsize
)
102 register nfsfh_t
*fhp
;
105 register u_char
*fhpp
;
106 register u_long fhsum
;
109 fhpp
= &fhp
->fh_bytes
[0];
111 for (i
= 0; i
< fhsize
; i
++)
117 * Look up a vnode/nfsnode by file handle.
118 * Callers must check for mount points!!
119 * In all cases, a pointer to a
120 * nfsnode structure is returned.
122 int nfs_node_hash_lock
;
125 nfs_nget(mntp
, fhp
, fhsize
, npp
)
127 register nfsfh_t
*fhp
;
129 struct nfsnode
**npp
;
131 struct proc
*p
= current_proc(); /* XXX */
133 struct nfsnodehashhead
*nhpp
;
134 register struct vnode
*vp
;
138 /* Check for unmount in progress */
139 if (mntp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
144 nhpp
= NFSNOHASH(nfs_hash(fhp
, fhsize
));
146 for (np
= nhpp
->lh_first
; np
!= 0; np
= np
->n_hash
.le_next
) {
147 if (mntp
!= NFSTOV(np
)->v_mount
|| np
->n_fhsize
!= fhsize
||
148 bcmp((caddr_t
)fhp
, (caddr_t
)np
->n_fhp
, fhsize
))
151 if (vget(vp
, LK_EXCLUSIVE
, p
))
157 * Obtain a lock to prevent a race condition if the getnewvnode()
158 * or MALLOC() below happens to block.
160 if (nfs_node_hash_lock
) {
161 while (nfs_node_hash_lock
) {
162 nfs_node_hash_lock
= -1;
163 tsleep(&nfs_node_hash_lock
, PVM
, "nfsngt", 0);
167 nfs_node_hash_lock
= 1;
170 * Do the MALLOC before the getnewvnode since doing so afterward
171 * might cause a bogus v_data pointer to get dereferenced
172 * elsewhere if MALLOC should block.
174 MALLOC_ZONE(np
, struct nfsnode
*, sizeof *np
, M_NFSNODE
, M_WAITOK
);
176 error
= getnewvnode(VT_NFS
, mntp
, nfsv2_vnodeop_p
, &nvp
);
178 if (nfs_node_hash_lock
< 0)
179 wakeup(&nfs_node_hash_lock
);
180 nfs_node_hash_lock
= 0;
182 FREE_ZONE(np
, sizeof *np
, M_NFSNODE
);
186 bzero((caddr_t
)np
, sizeof *np
);
190 * Insert the nfsnode in the hash queue for its new file handle
192 LIST_INSERT_HEAD(nhpp
, np
, n_hash
);
193 if (fhsize
> NFS_SMALLFH
) {
194 MALLOC_ZONE(np
->n_fhp
, nfsfh_t
*,
195 fhsize
, M_NFSBIGFH
, M_WAITOK
);
197 np
->n_fhp
= &np
->n_fh
;
198 bcopy((caddr_t
)fhp
, (caddr_t
)np
->n_fhp
, fhsize
);
199 np
->n_fhsize
= fhsize
;
202 if (nfs_node_hash_lock
< 0)
203 wakeup(&nfs_node_hash_lock
);
204 nfs_node_hash_lock
= 0;
207 * Lock the new nfsnode.
209 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
216 struct vop_inactive_args
/* {
221 register struct nfsnode
*np
;
222 register struct sillyrename
*sp
;
223 struct proc
*p
= current_proc(); /* XXX */
224 extern int prtactive
;
227 np
= VTONFS(ap
->a_vp
);
228 if (prtactive
&& ap
->a_vp
->v_usecount
!= 0)
229 vprint("nfs_inactive: pushing active", ap
->a_vp
);
230 if (ap
->a_vp
->v_type
!= VDIR
) {
231 sp
= np
->n_sillyrename
;
232 np
->n_sillyrename
= (struct sillyrename
*)0;
234 sp
= (struct sillyrename
*)0;
238 * Remove the silly file that was rename'd earlier
241 kprintf("nfs_inactive removing %s, dvp=%x, a_vp=%x, ap=%x, np=%x, sp=%x\n", &sp
->s_name
[0], (unsigned)sp
->s_dvp
, (unsigned)ap
->a_vp
, (unsigned)ap
, (unsigned)np
, (unsigned)sp
);
244 * We get a reference (vget) to ensure getnewvnode()
245 * doesn't recycle vp while we're asleep awaiting I/O.
246 * Note we don't need the reference unless usecount is
247 * already zero. In the case of a forcible unmount it
248 * wont be zero and doing a vget would fail because
249 * vclean holds VXLOCK.
251 if (ap
->a_vp
->v_usecount
> 0) {
253 } else if (vget(ap
->a_vp
, 0, ap
->a_p
))
254 panic("nfs_inactive: vget failed");
255 (void) nfs_vinvalbuf(ap
->a_vp
, 0, sp
->s_cred
, p
, 1);
256 ubc_setsize(ap
->a_vp
, (off_t
)0);
258 /* We have a problem. The dvp could have gone away on us
259 * while in the unmount path. Thus it appears as VBAD and we
260 * cannot use it. If we tried locking the parent (future), for silly
261 * rename files, it is unclear where we would lock. The unmount
262 * code just pulls unlocked vnodes as it goes thru its list and
263 * yanks them. Could unmount be smarter to see if a busy reg vnode has
264 * a parent, and not yank it yet? Put in more passes at unmount
265 * time? In the meantime, just check if it went away on us. Could
266 * have gone away during the nfs_vinvalbuf or ubc_setsize which block.
267 * Or perhaps even before nfs_inactive got called.
269 if ((sp
->s_dvp
)->v_type
!= VBAD
)
270 nfs_removeit(sp
); /* uses the dvp */
272 if (cred
!= NOCRED
) {
277 FREE_ZONE((caddr_t
)sp
, sizeof (struct sillyrename
), M_NFSREQ
);
280 np
->n_flag
&= (NMODIFIED
| NFLUSHINPROG
| NFLUSHWANT
| NQNFSEVICTED
|
281 NQNFSNONCACHE
| NQNFSWRITE
);
282 VOP_UNLOCK(ap
->a_vp
, 0, ap
->a_p
);
287 * Reclaim an nfsnode so that it can be used for other purposes.
291 struct vop_reclaim_args
/* {
295 register struct vnode
*vp
= ap
->a_vp
;
296 register struct nfsnode
*np
= VTONFS(vp
);
297 register struct nfsmount
*nmp
= VFSTONFS(vp
->v_mount
);
298 register struct nfsdmap
*dp
, *dp2
;
299 extern int prtactive
;
301 if (prtactive
&& vp
->v_usecount
!= 0)
302 vprint("nfs_reclaim: pushing active", vp
);
304 LIST_REMOVE(np
, n_hash
);
307 * In case we block during FREE_ZONEs below, get the entry out
308 * of tbe name cache now so subsequent lookups won't find it.
313 * For nqnfs, take it off the timer queue as required.
315 if ((nmp
->nm_flag
& NFSMNT_NQNFS
) && np
->n_timer
.cqe_next
!= 0) {
316 CIRCLEQ_REMOVE(&nmp
->nm_timerhead
, np
, n_timer
);
320 * Free up any directory cookie structures and
321 * large file handle structures that might be associated with
324 if (vp
->v_type
== VDIR
) {
325 dp
= np
->n_cookies
.lh_first
;
328 dp
= dp
->ndm_list
.le_next
;
329 FREE_ZONE((caddr_t
)dp2
,
330 sizeof (struct nfsdmap
), M_NFSDIROFF
);
333 if (np
->n_fhsize
> NFS_SMALLFH
) {
334 FREE_ZONE((caddr_t
)np
->n_fhp
, np
->n_fhsize
, M_NFSBIGFH
);
337 FREE_ZONE(vp
->v_data
, sizeof (struct nfsnode
), M_NFSNODE
);
338 vp
->v_data
= (void *)0;
348 struct vop_lock_args
/* {
352 register struct vnode
*vp
= ap
->a_vp
;
355 * Ugh, another place where interruptible mounts will get hung.
356 * If you make this sleep interruptible, then you have to fix all
357 * the VOP_LOCK() calls to expect interruptibility.
359 while (vp
->v_flag
& VXLOCK
) {
360 vp
->v_flag
|= VXWANT
;
361 (void) tsleep((caddr_t
)vp
, PINOD
, "nfslck", 0);
363 if (vp
->v_tag
== VT_NON
)
368 * Only lock regular files. If a server crashed while we were
369 * holding a directory lock, we could easily end up sleeping
370 * until the server rebooted while holding a lock on the root.
371 * Locks are only needed for protecting critical sections in
372 * VMIO at the moment.
373 * New vnodes will have type VNON but they should be locked
374 * since they may become VREG. This is checked in loadattrcache
375 * and unwanted locks are released there.
377 if (vp
->v_type
== VREG
|| vp
->v_type
== VNON
) {
378 while (np
->n_flag
& NLOCKED
) {
379 np
->n_flag
|= NWANTED
;
380 (void) tsleep((caddr_t
) np
, PINOD
, "nfslck2", 0);
382 * If the vnode has transmuted into a VDIR while we
383 * were asleep, then skip the lock.
385 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VNON
)
388 np
->n_flag
|= NLOCKED
;
400 struct vop_unlock_args
/* {
405 struct vnode
* vp
= ap
->a_vp
;
406 struct nfsnode
* np
= VTONFS(vp
);
408 if (vp
->v_type
== VREG
|| vp
->v_type
== VNON
) {
409 if (!(np
->n_flag
& NLOCKED
))
410 panic("nfs_unlock: nfsnode not locked");
411 np
->n_flag
&= ~NLOCKED
;
412 if (np
->n_flag
& NWANTED
) {
413 np
->n_flag
&= ~NWANTED
;
414 wakeup((caddr_t
) np
);
423 * Check for a locked nfsnode
427 struct vop_islocked_args
/* {
431 return VTONFS(ap
->a_vp
)->n_flag
& NLOCKED
? 1 : 0;
436 * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
437 * done. Currently nothing to do.
442 struct vop_abortop_args
/* {
444 struct componentname *a_cnp;
448 if ((ap
->a_cnp
->cn_flags
& (HASBUF
| SAVESTART
)) == HASBUF
)
449 FREE_ZONE(ap
->a_cnp
->cn_pnbuf
, ap
->a_cnp
->cn_pnlen
, M_NAMEI
);