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 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 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 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 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 * 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 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 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 * 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 * 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 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 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 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 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