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