1 /* $NetBSD: nfs_node.c,v 1.109 2009/03/14 15:36:24 dsl Exp $ */
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: nfs_node.c,v 1.109 2009/03/14 15:36:24 dsl Exp $");
44 #include <sys/param.h>
45 #include <sys/systm.h>
47 #include <sys/mount.h>
48 #include <sys/namei.h>
49 #include <sys/vnode.h>
50 #include <sys/kernel.h>
54 #include <sys/kauth.h>
56 #include <nfs/rpcv2.h>
57 #include <nfs/nfsproto.h>
59 #include <nfs/nfsnode.h>
60 #include <nfs/nfsmount.h>
61 #include <nfs/nfs_var.h>
63 struct pool nfs_node_pool
;
64 struct pool nfs_vattr_pool
;
65 static struct workqueue
*nfs_sillyworkq
;
69 static void nfs_gop_size(struct vnode
*, off_t
, off_t
*, int);
70 static int nfs_gop_alloc(struct vnode
*, off_t
, off_t
, int, kauth_cred_t
);
71 static int nfs_gop_write(struct vnode
*, struct vm_page
**, int, int);
72 static void nfs_sillyworker(struct work
*, void *);
74 static const struct genfs_ops nfs_genfsops
= {
75 .gop_size
= nfs_gop_size
,
76 .gop_alloc
= nfs_gop_alloc
,
77 .gop_write
= nfs_gop_write
,
81 * Reinitialize inode hash table.
87 pool_init(&nfs_node_pool
, sizeof(struct nfsnode
), 0, 0, 0, "nfsnodepl",
88 &pool_allocator_nointr
, IPL_NONE
);
89 pool_init(&nfs_vattr_pool
, sizeof(struct vattr
), 0, 0, 0, "nfsvapl",
90 &pool_allocator_nointr
, IPL_NONE
);
91 if (workqueue_create(&nfs_sillyworkq
, "nfssilly", nfs_sillyworker
,
92 NULL
, PRI_NONE
, IPL_NONE
, 0) != 0) {
93 panic("nfs_node_init");
98 * Free resources previously allocated in nfs_node_reinit().
104 pool_destroy(&nfs_node_pool
);
105 pool_destroy(&nfs_vattr_pool
);
106 workqueue_destroy(nfs_sillyworkq
);
109 #define RBTONFSNODE(node) \
110 (void *)((uintptr_t)(node) - offsetof(struct nfsnode, n_rbnode))
119 nfs_compare_nodes(const struct rb_node
*parent
, const struct rb_node
*node
)
121 const struct nfsnode
* const pnp
= RBTONFSNODE(parent
);
122 const struct nfsnode
* const np
= RBTONFSNODE(node
);
124 if (pnp
->n_fhsize
!= np
->n_fhsize
)
125 return np
->n_fhsize
- pnp
->n_fhsize
;
127 return memcmp(np
->n_fhp
, pnp
->n_fhp
, np
->n_fhsize
);
131 nfs_compare_node_fh(const struct rb_node
*b
, const void *key
)
133 const struct nfsnode
* const pnp
= RBTONFSNODE(b
);
134 const struct fh_match
* const fhm
= key
;
136 if (pnp
->n_fhsize
!= fhm
->fhm_fhsize
)
137 return fhm
->fhm_fhsize
- pnp
->n_fhsize
;
139 return memcmp(fhm
->fhm_fhp
, pnp
->n_fhp
, pnp
->n_fhsize
);
142 static const struct rb_tree_ops nfs_node_rbtree_ops
= {
143 .rbto_compare_nodes
= nfs_compare_nodes
,
144 .rbto_compare_key
= nfs_compare_node_fh
,
148 nfs_rbtinit(struct nfsmount
*nmp
)
150 rb_tree_init(&nmp
->nm_rbtree
, &nfs_node_rbtree_ops
);
155 * Look up a vnode/nfsnode by file handle.
156 * Callers must check for mount points!!
157 * In all cases, a pointer to a
158 * nfsnode structure is returned.
161 nfs_nget1(struct mount
*mntp
, nfsfh_t
*fhp
, int fhsize
, struct nfsnode
**npp
, int lkflags
)
165 struct nfsmount
*nmp
= VFSTONFS(mntp
);
168 struct rb_node
*node
;
171 fhm
.fhm_fhsize
= fhsize
;
174 rw_enter(&nmp
->nm_rbtlock
, RW_READER
);
175 node
= rb_tree_find_node(&nmp
->nm_rbtree
, &fhm
);
177 np
= RBTONFSNODE(node
);
179 mutex_enter(&vp
->v_interlock
);
180 rw_exit(&nmp
->nm_rbtlock
);
181 error
= vget(vp
, LK_EXCLUSIVE
| LK_INTERLOCK
| lkflags
);
189 rw_exit(&nmp
->nm_rbtlock
);
191 error
= getnewvnode(VT_NFS
, mntp
, nfsv2_vnodeop_p
, &vp
);
196 np
= pool_get(&nfs_node_pool
, PR_WAITOK
);
197 memset(np
, 0, sizeof *np
);
201 * Insert the nfsnode in the hash queue for its new file handle
204 if (fhsize
> NFS_SMALLFH
) {
205 np
->n_fhp
= kmem_alloc(fhsize
, KM_SLEEP
);
207 np
->n_fhp
= &np
->n_fh
;
208 memcpy(np
->n_fhp
, fhp
, fhsize
);
209 np
->n_fhsize
= fhsize
;
211 np
->n_vattr
= pool_get(&nfs_vattr_pool
, PR_WAITOK
);
213 rw_enter(&nmp
->nm_rbtlock
, RW_WRITER
);
214 if (NULL
!= rb_tree_find_node(&nmp
->nm_rbtree
, &fhm
)) {
215 rw_exit(&nmp
->nm_rbtlock
);
216 if (fhsize
> NFS_SMALLFH
) {
217 kmem_free(np
->n_fhp
, fhsize
);
219 pool_put(&nfs_vattr_pool
, np
->n_vattr
);
220 pool_put(&nfs_node_pool
, np
);
225 genfs_node_init(vp
, &nfs_genfsops
);
227 * Initalize read/write creds to useful values. VOP_OPEN will
230 np
->n_rcred
= curlwp
->l_cred
;
231 kauth_cred_hold(np
->n_rcred
);
232 np
->n_wcred
= curlwp
->l_cred
;
233 kauth_cred_hold(np
->n_wcred
);
234 vlockmgr(&vp
->v_lock
, LK_EXCLUSIVE
);
235 NFS_INVALIDATE_ATTRCACHE(np
);
236 uvm_vnp_setsize(vp
, 0);
237 rb_tree_insert_node(&nmp
->nm_rbtree
, &np
->n_rbnode
);
238 rw_exit(&nmp
->nm_rbtlock
);
245 nfs_inactive(void *v
)
247 struct vop_inactive_args
/* {
252 struct sillyrename
*sp
;
253 struct vnode
*vp
= ap
->a_vp
;
256 if (vp
->v_type
!= VDIR
) {
257 sp
= np
->n_sillyrename
;
258 np
->n_sillyrename
= (struct sillyrename
*)0;
262 nfs_vinvalbuf(vp
, 0, sp
->s_cred
, curlwp
, 1);
263 *ap
->a_recycle
= (np
->n_flag
& NREMOVED
) != 0;
265 (NMODIFIED
| NFLUSHINPROG
| NFLUSHWANT
| NEOFVALID
| NTRUNCDELAYED
);
267 if (vp
->v_type
== VDIR
&& np
->n_dircache
)
268 nfs_invaldircache(vp
,
269 NFS_INVALDIRCACHE_FORCE
| NFS_INVALDIRCACHE_KEEPEOF
);
274 workqueue_enqueue(nfs_sillyworkq
, &sp
->s_work
, NULL
);
281 * Reclaim an nfsnode so that it can be used for other purposes.
286 struct vop_reclaim_args
/* {
289 struct vnode
*vp
= ap
->a_vp
;
290 struct nfsnode
*np
= VTONFS(vp
);
291 struct nfsmount
*nmp
= VFSTONFS(vp
->v_mount
);
293 if (prtactive
&& vp
->v_usecount
> 1)
294 vprint("nfs_reclaim: pushing active", vp
);
296 rw_enter(&nmp
->nm_rbtlock
, RW_WRITER
);
297 rb_tree_remove_node(&nmp
->nm_rbtree
, &np
->n_rbnode
);
298 rw_exit(&nmp
->nm_rbtlock
);
301 * Free up any directory cookie structures and
302 * large file handle structures that might be associated with
305 if (vp
->v_type
== VDIR
&& np
->n_dircache
!= NULL
) {
306 nfs_invaldircache(vp
, NFS_INVALDIRCACHE_FORCE
);
307 hashdone(np
->n_dircache
, HASH_LIST
, nfsdirhashmask
);
309 KASSERT(np
->n_dirgens
== NULL
);
311 if (np
->n_fhsize
> NFS_SMALLFH
)
312 kmem_free(np
->n_fhp
, np
->n_fhsize
);
314 pool_put(&nfs_vattr_pool
, np
->n_vattr
);
316 kauth_cred_free(np
->n_rcred
);
319 kauth_cred_free(np
->n_wcred
);
322 if (vp
->v_type
== VREG
) {
323 mutex_destroy(&np
->n_commitlock
);
325 genfs_node_destroy(vp
);
326 pool_put(&nfs_node_pool
, np
);
332 nfs_gop_size(struct vnode
*vp
, off_t size
, off_t
*eobp
, int flags
)
335 *eobp
= MAX(size
, vp
->v_size
);
339 nfs_gop_alloc(struct vnode
*vp
, off_t off
, off_t len
, int flags
,
347 nfs_gop_write(struct vnode
*vp
, struct vm_page
**pgs
, int npages
, int flags
)
351 for (i
= 0; i
< npages
; i
++) {
352 pmap_page_protect(pgs
[i
], VM_PROT_READ
);
354 return genfs_gop_write(vp
, pgs
, npages
, flags
);
358 * Remove a silly file that was rename'd earlier
361 nfs_sillyworker(struct work
*work
, void *arg
)
363 struct sillyrename
*sp
;
366 sp
= (struct sillyrename
*)work
;
367 error
= vn_lock(sp
->s_dvp
, LK_EXCLUSIVE
);
368 if (error
|| sp
->s_dvp
->v_data
== NULL
) {
369 /* XXX should recover */
370 printf("%s: vp=%p error=%d\n", __func__
, sp
->s_dvp
, error
);
380 kauth_cred_free(sp
->s_cred
);
381 kmem_free(sp
, sizeof(*sp
));