1*b819cea2SGordon Ross /*
2*b819cea2SGordon Ross  * This file and its contents are supplied under the terms of the
3*b819cea2SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
4*b819cea2SGordon Ross  * You may only use this file in accordance with the terms of version
5*b819cea2SGordon Ross  * 1.0 of the CDDL.
6*b819cea2SGordon Ross  *
7*b819cea2SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
8*b819cea2SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
9*b819cea2SGordon Ross  * http://www.illumos.org/license/CDDL.
10*b819cea2SGordon Ross  */
11*b819cea2SGordon Ross 
12*b819cea2SGordon Ross /*
13*b819cea2SGordon Ross  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
14*b819cea2SGordon Ross  */
15*b819cea2SGordon Ross 
16*b819cea2SGordon Ross #include <sys/types.h>
17*b819cea2SGordon Ross #include <sys/param.h>
18*b819cea2SGordon Ross #include <sys/systm.h>
19*b819cea2SGordon Ross #include <sys/cmn_err.h>
20*b819cea2SGordon Ross #include <sys/cred.h>
21*b819cea2SGordon Ross #include <sys/debug.h>
22*b819cea2SGordon Ross #include <sys/errno.h>
23*b819cea2SGordon Ross #include <sys/t_lock.h>
24*b819cea2SGordon Ross #include <sys/user.h>
25*b819cea2SGordon Ross #include <sys/uio.h>
26*b819cea2SGordon Ross #include <sys/file.h>
27*b819cea2SGordon Ross #include <sys/pathname.h>
28*b819cea2SGordon Ross #include <sys/sysmacros.h>
29*b819cea2SGordon Ross #include <sys/vfs.h>
30*b819cea2SGordon Ross #include <sys/vnode.h>
31*b819cea2SGordon Ross #include <sys/avl.h>
32*b819cea2SGordon Ross #include <sys/stat.h>
33*b819cea2SGordon Ross #include <sys/mode.h>
34*b819cea2SGordon Ross 
35*b819cea2SGordon Ross #include <fcntl.h>
36*b819cea2SGordon Ross #include <unistd.h>
37*b819cea2SGordon Ross 
38*b819cea2SGordon Ross #include "vncache.h"
39*b819cea2SGordon Ross 
40*b819cea2SGordon Ross kmem_cache_t *vn_cache;
41*b819cea2SGordon Ross 
42*b819cea2SGordon Ross /*
43*b819cea2SGordon Ross  * You can dump this AVL tree with mdb, i.e.
44*b819cea2SGordon Ross  * vncache_avl ::walk avl |::print -s1 vnode_t
45*b819cea2SGordon Ross  */
46*b819cea2SGordon Ross avl_tree_t vncache_avl;
47*b819cea2SGordon Ross kmutex_t vncache_lock;
48*b819cea2SGordon Ross 
49*b819cea2SGordon Ross /*
50*b819cea2SGordon Ross  * Vnode cache.
51*b819cea2SGordon Ross  */
52*b819cea2SGordon Ross 
53*b819cea2SGordon Ross /* ARGSUSED */
54*b819cea2SGordon Ross static int
vn_cache_constructor(void * buf,void * cdrarg,int kmflags)55*b819cea2SGordon Ross vn_cache_constructor(void *buf, void *cdrarg, int kmflags)
56*b819cea2SGordon Ross {
57*b819cea2SGordon Ross 	struct vnode *vp;
58*b819cea2SGordon Ross 
59*b819cea2SGordon Ross 	vp = buf;
60*b819cea2SGordon Ross 	bzero(vp, sizeof (*vp));
61*b819cea2SGordon Ross 
62*b819cea2SGordon Ross 	mutex_init(&vp->v_lock, NULL, MUTEX_DEFAULT, NULL);
63*b819cea2SGordon Ross 	vp->v_fd = -1;
64*b819cea2SGordon Ross 
65*b819cea2SGordon Ross 	return (0);
66*b819cea2SGordon Ross }
67*b819cea2SGordon Ross 
68*b819cea2SGordon Ross /* ARGSUSED */
69*b819cea2SGordon Ross static void
vn_cache_destructor(void * buf,void * cdrarg)70*b819cea2SGordon Ross vn_cache_destructor(void *buf, void *cdrarg)
71*b819cea2SGordon Ross {
72*b819cea2SGordon Ross 	struct vnode *vp;
73*b819cea2SGordon Ross 
74*b819cea2SGordon Ross 	vp = buf;
75*b819cea2SGordon Ross 
76*b819cea2SGordon Ross 	mutex_destroy(&vp->v_lock);
77*b819cea2SGordon Ross }
78*b819cea2SGordon Ross 
79*b819cea2SGordon Ross /*
80*b819cea2SGordon Ross  * Used by file systems when fs-specific nodes (e.g., ufs inodes) are
81*b819cea2SGordon Ross  * cached by the file system and vnodes remain associated.
82*b819cea2SGordon Ross  */
83*b819cea2SGordon Ross void
vn_recycle(vnode_t * vp)84*b819cea2SGordon Ross vn_recycle(vnode_t *vp)
85*b819cea2SGordon Ross {
86*b819cea2SGordon Ross 
87*b819cea2SGordon Ross 	ASSERT(vp->v_fd == -1);
88*b819cea2SGordon Ross 
89*b819cea2SGordon Ross 	vp->v_rdcnt = 0;
90*b819cea2SGordon Ross 	vp->v_wrcnt = 0;
91*b819cea2SGordon Ross 
92*b819cea2SGordon Ross 	if (vp->v_path) {
93*b819cea2SGordon Ross 		strfree(vp->v_path);
94*b819cea2SGordon Ross 		vp->v_path = NULL;
95*b819cea2SGordon Ross 	}
96*b819cea2SGordon Ross }
97*b819cea2SGordon Ross 
98*b819cea2SGordon Ross 
99*b819cea2SGordon Ross /*
100*b819cea2SGordon Ross  * Used to reset the vnode fields including those that are directly accessible
101*b819cea2SGordon Ross  * as well as those which require an accessor function.
102*b819cea2SGordon Ross  *
103*b819cea2SGordon Ross  * Does not initialize:
104*b819cea2SGordon Ross  *	synchronization objects: v_lock, v_vsd_lock, v_nbllock, v_cv
105*b819cea2SGordon Ross  *	v_data (since FS-nodes and vnodes point to each other and should
106*b819cea2SGordon Ross  *		be updated simultaneously)
107*b819cea2SGordon Ross  *	v_op (in case someone needs to make a VOP call on this object)
108*b819cea2SGordon Ross  */
109*b819cea2SGordon Ross void
vn_reinit(vnode_t * vp)110*b819cea2SGordon Ross vn_reinit(vnode_t *vp)
111*b819cea2SGordon Ross {
112*b819cea2SGordon Ross 	vp->v_count = 1;
113*b819cea2SGordon Ross 	vp->v_vfsp = NULL;
114*b819cea2SGordon Ross 	vp->v_stream = NULL;
115*b819cea2SGordon Ross 	vp->v_flag = 0;
116*b819cea2SGordon Ross 	vp->v_type = VNON;
117*b819cea2SGordon Ross 	vp->v_rdev = NODEV;
118*b819cea2SGordon Ross 
119*b819cea2SGordon Ross 	vn_recycle(vp);
120*b819cea2SGordon Ross }
121*b819cea2SGordon Ross 
122*b819cea2SGordon Ross vnode_t *
vn_alloc(int kmflag)123*b819cea2SGordon Ross vn_alloc(int kmflag)
124*b819cea2SGordon Ross {
125*b819cea2SGordon Ross 	vnode_t *vp;
126*b819cea2SGordon Ross 
127*b819cea2SGordon Ross 	vp = kmem_cache_alloc(vn_cache, kmflag);
128*b819cea2SGordon Ross 
129*b819cea2SGordon Ross 	if (vp != NULL) {
130*b819cea2SGordon Ross 		vn_reinit(vp);
131*b819cea2SGordon Ross 	}
132*b819cea2SGordon Ross 
133*b819cea2SGordon Ross 	return (vp);
134*b819cea2SGordon Ross }
135*b819cea2SGordon Ross 
136*b819cea2SGordon Ross void
vn_free(vnode_t * vp)137*b819cea2SGordon Ross vn_free(vnode_t *vp)
138*b819cea2SGordon Ross {
139*b819cea2SGordon Ross 
140*b819cea2SGordon Ross 	/*
141*b819cea2SGordon Ross 	 * Some file systems call vn_free() with v_count of zero,
142*b819cea2SGordon Ross 	 * some with v_count of 1.  In any case, the value should
143*b819cea2SGordon Ross 	 * never be anything else.
144*b819cea2SGordon Ross 	 */
145*b819cea2SGordon Ross 	ASSERT((vp->v_count == 0) || (vp->v_count == 1));
146*b819cea2SGordon Ross 	if (vp->v_path != NULL) {
147*b819cea2SGordon Ross 		strfree(vp->v_path);
148*b819cea2SGordon Ross 		vp->v_path = NULL;
149*b819cea2SGordon Ross 	}
150*b819cea2SGordon Ross 	ASSERT(vp->v_fd != -1);
151*b819cea2SGordon Ross 	(void) close(vp->v_fd);
152*b819cea2SGordon Ross 	vp->v_fd = -1;
153*b819cea2SGordon Ross 
154*b819cea2SGordon Ross 	kmem_cache_free(vn_cache, vp);
155*b819cea2SGordon Ross }
156*b819cea2SGordon Ross 
157*b819cea2SGordon Ross int
vncache_cmp(const void * v1,const void * v2)158*b819cea2SGordon Ross vncache_cmp(const void *v1, const void *v2)
159*b819cea2SGordon Ross {
160*b819cea2SGordon Ross 	const vnode_t *vp1, *vp2;
161*b819cea2SGordon Ross 
162*b819cea2SGordon Ross 	vp1 = v1;
163*b819cea2SGordon Ross 	vp2 = v2;
164*b819cea2SGordon Ross 
165*b819cea2SGordon Ross 	if (vp1->v_st_dev < vp2->v_st_dev)
166*b819cea2SGordon Ross 		return (-1);
167*b819cea2SGordon Ross 	if (vp1->v_st_dev > vp2->v_st_dev)
168*b819cea2SGordon Ross 		return (+1);
169*b819cea2SGordon Ross 	if (vp1->v_st_ino < vp2->v_st_ino)
170*b819cea2SGordon Ross 		return (-1);
171*b819cea2SGordon Ross 	if (vp1->v_st_ino > vp2->v_st_ino)
172*b819cea2SGordon Ross 		return (+1);
173*b819cea2SGordon Ross 
174*b819cea2SGordon Ross 	return (0);
175*b819cea2SGordon Ross }
176*b819cea2SGordon Ross 
177*b819cea2SGordon Ross vnode_t *
vncache_lookup(struct stat * st)178*b819cea2SGordon Ross vncache_lookup(struct stat *st)
179*b819cea2SGordon Ross {
180*b819cea2SGordon Ross 	vnode_t tmp_vn;
181*b819cea2SGordon Ross 	vnode_t *vp;
182*b819cea2SGordon Ross 
183*b819cea2SGordon Ross 	tmp_vn.v_st_dev = st->st_dev;
184*b819cea2SGordon Ross 	tmp_vn.v_st_ino = st->st_ino;
185*b819cea2SGordon Ross 
186*b819cea2SGordon Ross 	mutex_enter(&vncache_lock);
187*b819cea2SGordon Ross 	vp = avl_find(&vncache_avl, &tmp_vn, NULL);
188*b819cea2SGordon Ross 	if (vp != NULL)
189*b819cea2SGordon Ross 		vn_hold(vp);
190*b819cea2SGordon Ross 	mutex_exit(&vncache_lock);
191*b819cea2SGordon Ross 
192*b819cea2SGordon Ross 	return (vp);
193*b819cea2SGordon Ross }
194*b819cea2SGordon Ross 
195*b819cea2SGordon Ross vnode_t *
vncache_enter(struct stat * st,vnode_t * dvp,char * name,int fd)196*b819cea2SGordon Ross vncache_enter(struct stat *st, vnode_t *dvp, char *name, int fd)
197*b819cea2SGordon Ross {
198*b819cea2SGordon Ross 	vnode_t *old_vp;
199*b819cea2SGordon Ross 	vnode_t *new_vp;
200*b819cea2SGordon Ross 	vfs_t *vfs;
201*b819cea2SGordon Ross 	char *vpath;
202*b819cea2SGordon Ross 	avl_index_t	where;
203*b819cea2SGordon Ross 	int len;
204*b819cea2SGordon Ross 
205*b819cea2SGordon Ross 	/*
206*b819cea2SGordon Ross 	 * Fill in v_path
207*b819cea2SGordon Ross 	 * Note: fsop_root() calls with dvp=NULL
208*b819cea2SGordon Ross 	 */
209*b819cea2SGordon Ross 	len = strlen(name) + 1;
210*b819cea2SGordon Ross 	if (dvp == NULL) {
211*b819cea2SGordon Ross 		vpath = kmem_alloc(len, KM_SLEEP);
212*b819cea2SGordon Ross 		(void) strlcpy(vpath, name, len);
213*b819cea2SGordon Ross 		vfs = rootvfs;
214*b819cea2SGordon Ross 	} else {
215*b819cea2SGordon Ross 		/* add to length for parent path + "/" */
216*b819cea2SGordon Ross 		len += (strlen(dvp->v_path) + 1);
217*b819cea2SGordon Ross 		vpath = kmem_alloc(len, KM_SLEEP);
218*b819cea2SGordon Ross 		(void) snprintf(vpath, len, "%s/%s", dvp->v_path, name);
219*b819cea2SGordon Ross 		vfs = dvp->v_vfsp;
220*b819cea2SGordon Ross 	}
221*b819cea2SGordon Ross 
222*b819cea2SGordon Ross 	new_vp = vn_alloc(KM_SLEEP);
223*b819cea2SGordon Ross 	new_vp->v_path = vpath;
224*b819cea2SGordon Ross 	new_vp->v_fd = fd;
225*b819cea2SGordon Ross 	new_vp->v_st_dev = st->st_dev;
226*b819cea2SGordon Ross 	new_vp->v_st_ino = st->st_ino;
227*b819cea2SGordon Ross 	new_vp->v_vfsp = vfs;
228*b819cea2SGordon Ross 	new_vp->v_type = IFTOVT(st->st_mode);
229*b819cea2SGordon Ross 
230*b819cea2SGordon Ross 	mutex_enter(&vncache_lock);
231*b819cea2SGordon Ross 	old_vp = avl_find(&vncache_avl, new_vp, &where);
232*b819cea2SGordon Ross 	if (old_vp != NULL)
233*b819cea2SGordon Ross 		vn_hold(old_vp);
234*b819cea2SGordon Ross 	else
235*b819cea2SGordon Ross 		avl_insert(&vncache_avl, new_vp, where);
236*b819cea2SGordon Ross 	mutex_exit(&vncache_lock);
237*b819cea2SGordon Ross 
238*b819cea2SGordon Ross 	/* If we lost the race, free new_vp */
239*b819cea2SGordon Ross 	if (old_vp != NULL) {
240*b819cea2SGordon Ross 		vn_free(new_vp);
241*b819cea2SGordon Ross 		return (old_vp);
242*b819cea2SGordon Ross 	}
243*b819cea2SGordon Ross 
244*b819cea2SGordon Ross 	return (new_vp);
245*b819cea2SGordon Ross }
246*b819cea2SGordon Ross 
247*b819cea2SGordon Ross /*
248*b819cea2SGordon Ross  * Called after a successful rename to update v_path
249*b819cea2SGordon Ross  */
250*b819cea2SGordon Ross void
vncache_renamed(vnode_t * vp,vnode_t * to_dvp,char * to_name)251*b819cea2SGordon Ross vncache_renamed(vnode_t *vp, vnode_t *to_dvp, char *to_name)
252*b819cea2SGordon Ross {
253*b819cea2SGordon Ross 	char *vpath;
254*b819cea2SGordon Ross 	char *ovpath;
255*b819cea2SGordon Ross 	int len;
256*b819cea2SGordon Ross 
257*b819cea2SGordon Ross 	len = strlen(to_name) + 1;
258*b819cea2SGordon Ross 	/* add to length for parent path + "/" */
259*b819cea2SGordon Ross 	len += (strlen(to_dvp->v_path) + 1);
260*b819cea2SGordon Ross 	vpath = kmem_alloc(len, KM_SLEEP);
261*b819cea2SGordon Ross 	(void) snprintf(vpath, len, "%s/%s", to_dvp->v_path, to_name);
262*b819cea2SGordon Ross 
263*b819cea2SGordon Ross 	mutex_enter(&vncache_lock);
264*b819cea2SGordon Ross 	ovpath = vp->v_path;
265*b819cea2SGordon Ross 	vp->v_path = vpath;
266*b819cea2SGordon Ross 	mutex_exit(&vncache_lock);
267*b819cea2SGordon Ross 
268*b819cea2SGordon Ross 	strfree(ovpath);
269*b819cea2SGordon Ross }
270*b819cea2SGordon Ross 
271*b819cea2SGordon Ross /*
272*b819cea2SGordon Ross  * Last reference to this vnode is (possibly) going away.
273*b819cea2SGordon Ross  * This is normally called by vn_rele() when v_count==1.
274*b819cea2SGordon Ross  * Note that due to lock order concerns, we have to take
275*b819cea2SGordon Ross  * the vncache_lock (for the avl tree) and then recheck
276*b819cea2SGordon Ross  * v_count, which might have gained a ref during the time
277*b819cea2SGordon Ross  * we did not hold vp->v_lock.
278*b819cea2SGordon Ross  */
279*b819cea2SGordon Ross void
vncache_inactive(vnode_t * vp)280*b819cea2SGordon Ross vncache_inactive(vnode_t *vp)
281*b819cea2SGordon Ross {
282*b819cea2SGordon Ross 	uint_t count;
283*b819cea2SGordon Ross 
284*b819cea2SGordon Ross 	mutex_enter(&vncache_lock);
285*b819cea2SGordon Ross 	mutex_enter(&vp->v_lock);
286*b819cea2SGordon Ross 
287*b819cea2SGordon Ross 	if ((count = vp->v_count) <= 1) {
288*b819cea2SGordon Ross 		/* This is (still) the last ref. */
289*b819cea2SGordon Ross 		avl_remove(&vncache_avl, vp);
290*b819cea2SGordon Ross 	}
291*b819cea2SGordon Ross 
292*b819cea2SGordon Ross 	mutex_exit(&vp->v_lock);
293*b819cea2SGordon Ross 	mutex_exit(&vncache_lock);
294*b819cea2SGordon Ross 
295*b819cea2SGordon Ross 	if (count <= 1) {
296*b819cea2SGordon Ross 		vn_free(vp);
297*b819cea2SGordon Ross 	}
298*b819cea2SGordon Ross }
299*b819cea2SGordon Ross 
300*b819cea2SGordon Ross #pragma init(vncache_init)
301*b819cea2SGordon Ross int
vncache_init(void)302*b819cea2SGordon Ross vncache_init(void)
303*b819cea2SGordon Ross {
304*b819cea2SGordon Ross 	vn_cache = kmem_cache_create("vn_cache", sizeof (struct vnode),
305*b819cea2SGordon Ross 	    VNODE_ALIGN, vn_cache_constructor, vn_cache_destructor, NULL, NULL,
306*b819cea2SGordon Ross 	    NULL, 0);
307*b819cea2SGordon Ross 	avl_create(&vncache_avl,
308*b819cea2SGordon Ross 	    vncache_cmp,
309*b819cea2SGordon Ross 	    sizeof (vnode_t),
310*b819cea2SGordon Ross 	    offsetof(vnode_t, v_avl_node));
311*b819cea2SGordon Ross 	mutex_init(&vncache_lock, NULL, MUTEX_DEFAULT, NULL);
312*b819cea2SGordon Ross 	return (0);
313*b819cea2SGordon Ross }
314*b819cea2SGordon Ross 
315*b819cea2SGordon Ross #pragma fini(vncache_fini)
316*b819cea2SGordon Ross void
vncache_fini(void)317*b819cea2SGordon Ross vncache_fini(void)
318*b819cea2SGordon Ross {
319*b819cea2SGordon Ross 	mutex_destroy(&vncache_lock);
320*b819cea2SGordon Ross 	avl_destroy(&vncache_avl);
321*b819cea2SGordon Ross 	kmem_cache_destroy(vn_cache);
322*b819cea2SGordon Ross }
323