1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/systm.h> 30 #include <sys/cmn_err.h> 31 32 #include <nfs/nfs.h> 33 34 #include <nfs/nfs4.h> 35 #include <nfs/rnode4.h> 36 #include <nfs/nfs4_clnt.h> 37 38 static struct kmem_cache *svnode_cache; 39 40 struct sv_stats 41 { 42 int sv_activate; 43 int sv_find; 44 int sv_match; 45 int sv_inactive; 46 int sv_exchange; 47 } sv_stats; 48 49 static int sv_match(nfs4_fname_t *, nfs4_sharedfh_t *, svnode_t *); 50 51 /* 52 * Map a vnode back to the shadow which points to it. This is 53 * hard now that the vnode is not embedded in the shadow vnode. 54 */ 55 56 57 svnode_t * 58 vtosv(vnode_t *vp) 59 { 60 rnode4_t *rp = VTOR4(vp); 61 svnode_t *svp, *svp_found = NULL; 62 63 /* Check to see if it's the master shadow vnode first. */ 64 65 if (RTOV4(rp) == vp) 66 return (&rp->r_svnode); 67 68 mutex_enter(&rp->r_svlock); 69 70 for (svp = rp->r_svnode.sv_forw; svp != &rp->r_svnode; 71 svp = svp->sv_forw) 72 if (svp->sv_r_vnode == vp) { 73 svp_found = svp; 74 break; 75 } 76 77 mutex_exit(&rp->r_svlock); 78 ASSERT(svp_found != NULL); 79 80 return (svp_found); 81 } 82 83 /* 84 * sv_activate - find and activate the shadow vnode for the given 85 * directory file handle and name. May replace *vpp with a held reference 86 * to a different vnode, in which case the reference to the previous one is 87 * released. 88 */ 89 90 void 91 sv_activate(vnode_t **vpp, vnode_t *dvp, nfs4_fname_t **namepp, int newnode) 92 { 93 svnode_t *svp; 94 vnode_t *resvp; 95 rnode4_t *rp = VTOR4(*vpp); 96 97 ASSERT(namepp != NULL); 98 ASSERT(*namepp != NULL); 99 ASSERT(dvp != NULL); 100 101 sv_stats.sv_activate++; 102 103 ASSERT(RW_LOCK_HELD(&rp->r_hashq->r_lock)); 104 105 /* 106 * If make_rnode made a new rnode (ie. newnode != 0), then 107 * the master vnode was (partially) initialized there. If 108 * it was not a new rnode, then it returns the master vnode. 109 * Call sv_find to find and/or initialize the shadow 110 * vnode. 111 */ 112 113 if (newnode) { 114 /* 115 * Initialize the shadow vnode. 116 */ 117 svp = vtosv(*vpp); 118 svp->sv_forw = svp->sv_back = svp; 119 ASSERT(svp->sv_dfh == NULL); 120 svp->sv_dfh = VTOR4(dvp)->r_fh; 121 sfh4_hold(svp->sv_dfh); 122 ASSERT(svp->sv_name == NULL); 123 svp->sv_name = *namepp; 124 *namepp = NULL; 125 } else if ((*vpp)->v_type == VREG && !((*vpp)->v_flag & VROOT)) { 126 resvp = sv_find(*vpp, dvp, namepp); 127 ASSERT(resvp->v_type == VREG); 128 VN_RELE(*vpp); 129 *vpp = resvp; 130 } else { 131 fn_rele(namepp); 132 } 133 } 134 135 /* 136 * sv_find - find the shadow vnode for the desired name and directory 137 * file handle. If one does not exist, then create it. Returns the shadow 138 * vnode. The caller is responsible for freeing the reference. 139 * Consumes the name reference and nulls it out. 140 * 141 * Side effects: increments the reference count on the master vnode if the 142 * shadow vnode had to be created. 143 */ 144 145 vnode_t * 146 sv_find(vnode_t *mvp, vnode_t *dvp, nfs4_fname_t **namepp) 147 { 148 vnode_t *vp; 149 rnode4_t *rp = VTOR4(mvp); 150 svnode_t *svp; 151 svnode_t *master_svp = vtosv(mvp); 152 rnode4_t *drp = VTOR4(dvp); 153 nfs4_fname_t *nm; 154 155 ASSERT(dvp != NULL); 156 157 sv_stats.sv_find++; 158 159 ASSERT(namepp != NULL); 160 ASSERT(*namepp != NULL); 161 nm = *namepp; 162 *namepp = NULL; 163 164 /* 165 * At this point, all we know is that we have an rnode whose 166 * file handle matches the file handle of the object we want. 167 * We have to verify that component name and the directory 168 * match. If so, then we are done. 169 * 170 * Note: mvp is always the master vnode. 171 */ 172 173 ASSERT(!IS_SHADOW(mvp, rp)); 174 175 if (sv_match(nm, drp->r_fh, master_svp)) { 176 VN_HOLD(mvp); 177 fn_rele(&nm); 178 return (mvp); 179 } 180 181 /* 182 * No match, search through the shadow vnode list. 183 * Hold the r_svlock to prevent changes. 184 */ 185 186 mutex_enter(&rp->r_svlock); 187 188 for (svp = master_svp->sv_forw; svp != master_svp; svp = svp->sv_forw) 189 if (sv_match(nm, drp->r_fh, svp)) { 190 191 /* 192 * A matching shadow vnode is found, bump the 193 * reference count on it and return it. 194 */ 195 196 vp = SVTOV(svp); 197 VN_HOLD(vp); 198 fn_rele(&nm); 199 mutex_exit(&rp->r_svlock); 200 return (vp); 201 } 202 203 /* 204 * No match searching the list, go allocate a new shadow 205 */ 206 svp = kmem_cache_alloc(svnode_cache, KM_SLEEP); 207 svp->sv_r_vnode = vn_alloc(KM_SLEEP); 208 vp = SVTOV(svp); 209 210 /* Initialize the vnode */ 211 212 vn_setops(vp, nfs4_vnodeops); 213 vp->v_data = (caddr_t)rp; 214 vp->v_vfsp = mvp->v_vfsp; 215 ASSERT(nfs4_consistent_type(mvp)); 216 vp->v_type = mvp->v_type; 217 vp->v_pages = (page_t *)-1; /* No pages, please */ 218 vn_exists(vp); 219 /* XXX - Need to VFS_HOLD() ? */ 220 221 /* Initialize the shadow vnode */ 222 223 svp->sv_dfh = VTOR4(dvp)->r_fh; 224 sfh4_hold(svp->sv_dfh); 225 226 svp->sv_name = nm; 227 VN_HOLD(mvp); 228 insque(svp, master_svp); 229 mutex_exit(&rp->r_svlock); 230 231 return (vp); 232 } 233 234 /* 235 * sv_match - check to see if the shadow vnode matches the desired 236 * name and directory file handle. Returns non-zero if there's a match, 237 * zero if it's not a match. 238 */ 239 240 static int 241 sv_match(nfs4_fname_t *nm, nfs4_sharedfh_t *fhp, svnode_t *svp) 242 { 243 sv_stats.sv_match++; 244 245 return (svp->sv_name != NULL && svp->sv_name == nm && 246 SFH4_SAME(svp->sv_dfh, fhp)); 247 } 248 249 /* 250 * sv_inactive - deactivate a shadow vnode. sv_inactive is called 251 * from nfs4_inactive. Whenever a shadow vnode is de-activated, 252 * sv_inactive cleans up the mess and releases the reference on the 253 * master vnode. 254 */ 255 256 void 257 sv_inactive(vnode_t *vp) 258 { 259 svnode_t *svp; 260 rnode4_t *rp; 261 vnode_t *mvp; 262 263 sv_stats.sv_inactive++; 264 265 svp = VTOSV(vp); 266 rp = VTOR4(vp); 267 mvp = rp->r_vnode; 268 269 ASSERT(mvp != vp); 270 271 /* 272 * Remove the shadow vnode from the list. The serialization 273 * is provided by the svnode list lock. This could be done 274 * with the r_statelock, but that would require more locking 275 * in the activation path. 276 */ 277 278 mutex_enter(&rp->r_svlock); 279 mutex_enter(&vp->v_lock); 280 /* check if someone slipped in while locks were dropped */ 281 if (vp->v_count > 1) { 282 vp->v_count--; 283 mutex_exit(&vp->v_lock); 284 mutex_exit(&rp->r_svlock); 285 return; 286 } 287 remque(svp); 288 mutex_exit(&vp->v_lock); 289 mutex_exit(&rp->r_svlock); 290 291 sv_uninit(svp); 292 svp->sv_forw = svp->sv_back = NULL; 293 kmem_cache_free(svnode_cache, svp); 294 vn_invalid(vp); 295 vn_free(vp); 296 297 /* release the reference held by this shadow on the master */ 298 299 VN_RELE(mvp); 300 } 301 302 /* 303 * sv_uninit - free any data structures allocated by the shadow vnode. 304 */ 305 306 void 307 sv_uninit(svnode_t *svp) 308 { 309 if (svp->sv_name != NULL) 310 fn_rele(&svp->sv_name); 311 if (svp->sv_dfh != NULL) 312 sfh4_rele(&svp->sv_dfh); 313 } 314 315 /* 316 * sv_exchange - exchange a shadow vnode for the master vnode. This 317 * occurs during nfs4_open, since only the master vnode owns the files 318 * resources (eg. pages). 319 */ 320 321 void 322 sv_exchange(vnode_t **vpp) 323 { 324 vnode_t *mvp; 325 326 sv_stats.sv_exchange++; 327 328 /* RTOV always returns the master vnode */ 329 mvp = RTOV4(VTOR4(*vpp)); 330 VN_HOLD(mvp) 331 VN_RELE(*vpp); 332 *vpp = mvp; 333 } 334 335 int 336 nfs4_shadow_init(void) 337 { 338 /* 339 * Allocate shadow vnode cache 340 */ 341 svnode_cache = kmem_cache_create("svnode_cache", 342 sizeof (svnode_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 343 344 return (0); 345 } 346 347 int 348 nfs4_shadow_fini(void) 349 { 350 kmem_cache_destroy(svnode_cache); 351 352 return (0); 353 } 354