]>
git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_node.c
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
27 * Copyright (c) 1989, 1993
28 * The Regents of the University of California. All rights reserved.
30 * This code is derived from software contributed to Berkeley by
31 * Rick Macklem at The University of Guelph.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95
62 * FreeBSD-Id: nfs_node.c,v 1.22 1997/10/28 14:06:20 bde Exp $
66 #include <sys/param.h>
67 #include <sys/systm.h>
69 #include <sys/mount.h>
70 #include <sys/namei.h>
71 #include <sys/vnode.h>
72 #include <sys/malloc.h>
74 #include <nfs/rpcv2.h>
75 #include <nfs/nfsproto.h>
77 #include <nfs/nfsnode.h>
78 #include <nfs/nfsmount.h>
80 LIST_HEAD(nfsnodehashhead
, nfsnode
) *nfsnodehashtbl
;
87 * Initialize hash links for nfsnodes
88 * and build nfsnode free list.
93 nfsnodehashtbl
= hashinit(desiredvnodes
, M_NFSNODE
, &nfsnodehash
);
97 * Compute an entry in the NFS hash table structure
100 nfs_hash(fhp
, fhsize
)
101 register nfsfh_t
*fhp
;
104 register u_char
*fhpp
;
105 register u_long fhsum
;
108 fhpp
= &fhp
->fh_bytes
[0];
110 for (i
= 0; i
< fhsize
; i
++)
116 * Look up a vnode/nfsnode by file handle.
117 * Callers must check for mount points!!
118 * In all cases, a pointer to a
119 * nfsnode structure is returned.
121 int nfs_node_hash_lock
;
124 nfs_nget(mntp
, fhp
, fhsize
, npp
)
126 register nfsfh_t
*fhp
;
128 struct nfsnode
**npp
;
130 struct proc
*p
= current_proc(); /* XXX */
132 struct nfsnodehashhead
*nhpp
;
133 register struct vnode
*vp
;
138 /* Check for unmount in progress */
139 if (!mntp
|| (mntp
->mnt_kern_flag
& MNTK_UNMOUNT
)) {
141 return (!mntp
? ENXIO
: EPERM
);
144 nhpp
= NFSNOHASH(nfs_hash(fhp
, fhsize
));
146 for (np
= nhpp
->lh_first
; np
!= 0; np
= np
->n_hash
.le_next
) {
147 mp
= (np
->n_flag
& NINIT
) ? np
->n_mount
: NFSTOV(np
)->v_mount
;
148 if (mntp
!= mp
|| np
->n_fhsize
!= fhsize
||
149 bcmp((caddr_t
)fhp
, (caddr_t
)np
->n_fhp
, fhsize
))
151 /* if the node is still being initialized, sleep on it */
152 if (np
->n_flag
& NINIT
) {
153 np
->n_flag
|= NWINIT
;
154 tsleep(np
, PINOD
, "nfsngt", 0);
158 if (vget(vp
, LK_EXCLUSIVE
, p
))
164 * Obtain a lock to prevent a race condition if the getnewvnode()
165 * or MALLOC() below happens to block.
167 if (nfs_node_hash_lock
) {
168 while (nfs_node_hash_lock
) {
169 nfs_node_hash_lock
= -1;
170 tsleep(&nfs_node_hash_lock
, PVM
, "nfsngt", 0);
174 nfs_node_hash_lock
= 1;
177 * allocate and initialize nfsnode and stick it in the hash
178 * before calling getnewvnode(). Anyone finding it in the
179 * hash before initialization is complete will wait for it.
181 MALLOC_ZONE(np
, struct nfsnode
*, sizeof *np
, M_NFSNODE
, M_WAITOK
);
182 bzero((caddr_t
)np
, sizeof *np
);
185 lockinit(&np
->n_lock
, PINOD
, "nfsnode", 0, 0);
186 /* lock the new nfsnode */
187 lockmgr(&np
->n_lock
, LK_EXCLUSIVE
, NULL
, p
);
189 /* Insert the nfsnode in the hash queue for its new file handle */
190 if (fhsize
> NFS_SMALLFH
) {
191 MALLOC_ZONE(np
->n_fhp
, nfsfh_t
*,
192 fhsize
, M_NFSBIGFH
, M_WAITOK
);
194 np
->n_fhp
= &np
->n_fh
;
195 bcopy((caddr_t
)fhp
, (caddr_t
)np
->n_fhp
, fhsize
);
196 np
->n_fhsize
= fhsize
;
197 LIST_INSERT_HEAD(nhpp
, np
, n_hash
);
198 np
->n_flag
|= NHASHED
;
200 /* release lock on hash table */
201 if (nfs_node_hash_lock
< 0)
202 wakeup(&nfs_node_hash_lock
);
203 nfs_node_hash_lock
= 0;
205 /* now, attempt to get a new vnode */
206 error
= getnewvnode(VT_NFS
, mntp
, nfsv2_vnodeop_p
, &nvp
);
208 LIST_REMOVE(np
, n_hash
);
209 np
->n_flag
&= ~NHASHED
;
210 if (np
->n_fhsize
> NFS_SMALLFH
)
211 FREE_ZONE((caddr_t
)np
->n_fhp
, np
->n_fhsize
, M_NFSBIGFH
);
212 FREE_ZONE(np
, sizeof *np
, M_NFSNODE
);
221 /* node is now initialized, check if anyone's waiting for it */
222 np
->n_flag
&= ~NINIT
;
223 if (np
->n_flag
& NWINIT
) {
224 np
->n_flag
&= ~NWINIT
;
233 struct vop_inactive_args
/* {
238 register struct nfsnode
*np
;
239 register struct sillyrename
*sp
;
240 struct proc
*p
= current_proc(); /* XXX */
241 extern int prtactive
;
244 np
= VTONFS(ap
->a_vp
);
245 if (prtactive
&& ap
->a_vp
->v_usecount
!= 0)
246 vprint("nfs_inactive: pushing active", ap
->a_vp
);
247 if (ap
->a_vp
->v_type
!= VDIR
) {
248 sp
= np
->n_sillyrename
;
249 np
->n_sillyrename
= (struct sillyrename
*)0;
251 sp
= (struct sillyrename
*)0;
255 * Remove the silly file that was rename'd earlier
258 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
);
260 (void) nfs_vinvalbuf(ap
->a_vp
, 0, sp
->s_cred
, p
, 1);
262 ubc_setsize(ap
->a_vp
, (off_t
)0);
265 * remove nfsnode from hash now so we can't accidentally find it
266 * again if another object gets created with the same filehandle
267 * before this vnode gets reclaimed
269 LIST_REMOVE(np
, n_hash
);
270 np
->n_flag
&= ~NHASHED
;
272 if (cred
!= NOCRED
) {
277 FREE_ZONE((caddr_t
)sp
, sizeof (struct sillyrename
), M_NFSREQ
);
279 np
->n_flag
&= (NMODIFIED
| NFLUSHINPROG
| NFLUSHWANT
| NQNFSEVICTED
|
280 NQNFSNONCACHE
| NQNFSWRITE
| NHASHED
);
281 VOP_UNLOCK(ap
->a_vp
, 0, ap
->a_p
);
286 * Reclaim an nfsnode so that it can be used for other purposes.
290 struct vop_reclaim_args
/* {
294 register struct vnode
*vp
= ap
->a_vp
;
295 register struct nfsnode
*np
= VTONFS(vp
);
296 register struct nfsmount
*nmp
= VFSTONFS(vp
->v_mount
);
297 register struct nfsdmap
*dp
, *dp2
;
298 extern int prtactive
;
300 if (prtactive
&& vp
->v_usecount
!= 0)
301 vprint("nfs_reclaim: pushing active", vp
);
303 if (np
->n_flag
& NHASHED
) {
304 LIST_REMOVE(np
, n_hash
);
305 np
->n_flag
&= ~NHASHED
;
309 * In case we block during FREE_ZONEs below, get the entry out
310 * of tbe name cache now so subsequent lookups won't find it.
315 * For nqnfs, take it off the timer queue as required.
317 if ((nmp
->nm_flag
& NFSMNT_NQNFS
) && np
->n_timer
.cqe_next
!= 0) {
318 CIRCLEQ_REMOVE(&nmp
->nm_timerhead
, np
, n_timer
);
322 * Free up any directory cookie structures and
323 * large file handle structures that might be associated with
326 if (vp
->v_type
== VDIR
) {
327 dp
= np
->n_cookies
.lh_first
;
330 dp
= dp
->ndm_list
.le_next
;
331 FREE_ZONE((caddr_t
)dp2
,
332 sizeof (struct nfsdmap
), M_NFSDIROFF
);
335 if (np
->n_fhsize
> NFS_SMALLFH
) {
336 FREE_ZONE((caddr_t
)np
->n_fhp
, np
->n_fhsize
, M_NFSBIGFH
);
339 FREE_ZONE(vp
->v_data
, sizeof (struct nfsnode
), M_NFSNODE
);
340 vp
->v_data
= (void *)0;
349 struct vop_lock_args
/* {
355 register struct vnode
*vp
= ap
->a_vp
;
358 * Ugh, another place where interruptible mounts will get hung.
359 * If you make this call interruptible, then you have to fix all
360 * the VOP_LOCK() calls to expect interruptibility.
362 if (vp
->v_tag
== VT_NON
)
363 return (ENOENT
); /* ??? -- got to check something and error, but what? */
365 return(lockmgr(&VTONFS(vp
)->n_lock
, ap
->a_flags
, &vp
->v_interlock
,
375 struct vop_unlock_args
/* {
381 struct vnode
*vp
= ap
->a_vp
;
383 return (lockmgr(&VTONFS(vp
)->n_lock
, ap
->a_flags
| LK_RELEASE
,
384 &vp
->v_interlock
, ap
->a_p
));
388 * Check for a locked nfsnode
392 struct vop_islocked_args
/* {
396 return (lockstatus(&VTONFS(ap
->a_vp
)->n_lock
));