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 2009 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 nfs4_fname_t *svpname; 94 rnode4_t *rp = VTOR4(*vpp); 95 svp = VTOSV(*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->sv_forw = svp->sv_back = svp; 118 ASSERT(svp->sv_dfh == NULL); 119 svp->sv_dfh = VTOR4(dvp)->r_fh; 120 sfh4_hold(svp->sv_dfh); 121 ASSERT(svp->sv_name == NULL); 122 svp->sv_name = *namepp; 123 } else if ((*vpp)->v_type == VREG && !((*vpp)->v_flag & VROOT)) { 124 resvp = sv_find(*vpp, dvp, namepp); 125 ASSERT(resvp->v_type == VREG); 126 VN_RELE(*vpp); 127 *vpp = resvp; 128 } else if ((*vpp)->v_type == VDIR) { 129 /* 130 * Directories only have a single shadow vnode which 131 * is the master shadow vnode. This is because directories 132 * can't have hard links. If sv_activate() is 133 * called for an existing rnode (newnode isn't set) 134 * but with a new name the fname needs to be updated 135 * and the old one released. 136 * 137 * fname mismatches can occur due to server side renames, 138 * here is a chance to update the fname in case there is 139 * a mismatch. Since this is not a newnode we hold r_svlock 140 * to protect sv_name. 141 */ 142 mutex_enter(&rp->r_svlock); 143 svpname = svp->sv_name; 144 if (svpname != *namepp) { 145 /* 146 * Call fn_rele() to release the hold for the 147 * previous shadow vnode reference. Don't 148 * release the hold on the fname pointed to by 149 * namepp as we have new reference to it from 150 * this shadow vnode. 151 */ 152 svp->sv_name = *namepp; 153 mutex_exit(&rp->r_svlock); 154 fn_rele(&svpname); 155 } else { 156 mutex_exit(&rp->r_svlock); 157 fn_rele(namepp); 158 } 159 } else { 160 fn_rele(namepp); 161 } 162 } 163 164 /* 165 * sv_find - find the shadow vnode for the desired name and directory 166 * file handle. If one does not exist, then create it. Returns the shadow 167 * vnode. The caller is responsible for freeing the reference. 168 * Consumes the name reference and nulls it out. 169 * 170 * Side effects: increments the reference count on the master vnode if the 171 * shadow vnode had to be created. 172 */ 173 174 vnode_t * 175 sv_find(vnode_t *mvp, vnode_t *dvp, nfs4_fname_t **namepp) 176 { 177 vnode_t *vp; 178 rnode4_t *rp = VTOR4(mvp); 179 svnode_t *svp; 180 svnode_t *master_svp = VTOSV(mvp); 181 rnode4_t *drp = VTOR4(dvp); 182 nfs4_fname_t *nm; 183 184 ASSERT(dvp != NULL); 185 186 sv_stats.sv_find++; 187 188 ASSERT(namepp != NULL); 189 ASSERT(*namepp != NULL); 190 nm = *namepp; 191 *namepp = NULL; 192 193 /* 194 * At this point, all we know is that we have an rnode whose 195 * file handle matches the file handle of the object we want. 196 * We have to verify that component name and the directory 197 * match. If so, then we are done. 198 * 199 * Note: mvp is always the master vnode. 200 */ 201 202 ASSERT(!IS_SHADOW(mvp, rp)); 203 204 if (sv_match(nm, drp->r_fh, master_svp)) { 205 VN_HOLD(mvp); 206 fn_rele(&nm); 207 return (mvp); 208 } 209 210 /* 211 * No match, search through the shadow vnode list. 212 * Hold the r_svlock to prevent changes. 213 */ 214 215 mutex_enter(&rp->r_svlock); 216 217 for (svp = master_svp->sv_forw; svp != master_svp; svp = svp->sv_forw) 218 if (sv_match(nm, drp->r_fh, svp)) { 219 220 /* 221 * A matching shadow vnode is found, bump the 222 * reference count on it and return it. 223 */ 224 225 vp = SVTOV(svp); 226 VN_HOLD(vp); 227 fn_rele(&nm); 228 mutex_exit(&rp->r_svlock); 229 return (vp); 230 } 231 232 /* 233 * No match searching the list, go allocate a new shadow 234 */ 235 svp = kmem_cache_alloc(svnode_cache, KM_SLEEP); 236 svp->sv_r_vnode = vn_alloc(KM_SLEEP); 237 vp = SVTOV(svp); 238 239 /* Initialize the vnode */ 240 241 vn_setops(vp, nfs4_vnodeops); 242 vp->v_data = (caddr_t)rp; 243 vp->v_vfsp = mvp->v_vfsp; 244 ASSERT(nfs4_consistent_type(mvp)); 245 vp->v_type = mvp->v_type; 246 vp->v_pages = (page_t *)-1; /* No pages, please */ 247 vn_exists(vp); 248 249 /* Initialize the shadow vnode */ 250 251 svp->sv_dfh = VTOR4(dvp)->r_fh; 252 sfh4_hold(svp->sv_dfh); 253 254 svp->sv_name = nm; 255 VN_HOLD(mvp); 256 insque(svp, master_svp); 257 mutex_exit(&rp->r_svlock); 258 259 return (vp); 260 } 261 262 /* 263 * sv_match - check to see if the shadow vnode matches the desired 264 * name and directory file handle. Returns non-zero if there's a match, 265 * zero if it's not a match. 266 */ 267 268 static int 269 sv_match(nfs4_fname_t *nm, nfs4_sharedfh_t *fhp, svnode_t *svp) 270 { 271 sv_stats.sv_match++; 272 273 return (svp->sv_name != NULL && svp->sv_name == nm && 274 SFH4_SAME(svp->sv_dfh, fhp)); 275 } 276 277 /* 278 * sv_inactive - deactivate a shadow vnode. sv_inactive is called 279 * from nfs4_inactive. Whenever a shadow vnode is de-activated, 280 * sv_inactive cleans up the mess and releases the reference on the 281 * master vnode. 282 */ 283 284 void 285 sv_inactive(vnode_t *vp) 286 { 287 svnode_t *svp; 288 rnode4_t *rp; 289 vnode_t *mvp; 290 291 sv_stats.sv_inactive++; 292 293 svp = VTOSV(vp); 294 rp = VTOR4(vp); 295 mvp = rp->r_vnode; 296 297 ASSERT(mvp != vp); 298 299 /* 300 * Remove the shadow vnode from the list. The serialization 301 * is provided by the svnode list lock. This could be done 302 * with the r_statelock, but that would require more locking 303 * in the activation path. 304 */ 305 306 mutex_enter(&rp->r_svlock); 307 mutex_enter(&vp->v_lock); 308 /* check if someone slipped in while locks were dropped */ 309 if (vp->v_count > 1) { 310 vp->v_count--; 311 mutex_exit(&vp->v_lock); 312 mutex_exit(&rp->r_svlock); 313 return; 314 } 315 remque(svp); 316 mutex_exit(&vp->v_lock); 317 mutex_exit(&rp->r_svlock); 318 319 sv_uninit(svp); 320 svp->sv_forw = svp->sv_back = NULL; 321 kmem_cache_free(svnode_cache, svp); 322 vn_invalid(vp); 323 vn_free(vp); 324 325 /* release the reference held by this shadow on the master */ 326 327 VN_RELE(mvp); 328 } 329 330 /* 331 * sv_uninit - free any data structures allocated by the shadow vnode. 332 */ 333 334 void 335 sv_uninit(svnode_t *svp) 336 { 337 if (svp->sv_name != NULL) 338 fn_rele(&svp->sv_name); 339 if (svp->sv_dfh != NULL) 340 sfh4_rele(&svp->sv_dfh); 341 } 342 343 /* 344 * sv_exchange - exchange a shadow vnode for the master vnode. This 345 * occurs during nfs4_open, since only the master vnode owns the files 346 * resources (eg. pages). 347 */ 348 349 void 350 sv_exchange(vnode_t **vpp) 351 { 352 vnode_t *mvp; 353 354 sv_stats.sv_exchange++; 355 356 /* RTOV always returns the master vnode */ 357 mvp = RTOV4(VTOR4(*vpp)); 358 VN_HOLD(mvp) 359 VN_RELE(*vpp); 360 *vpp = mvp; 361 } 362 363 int 364 nfs4_shadow_init(void) 365 { 366 /* 367 * Allocate shadow vnode cache 368 */ 369 svnode_cache = kmem_cache_create("svnode_cache", 370 sizeof (svnode_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 371 372 return (0); 373 } 374 375 int 376 nfs4_shadow_fini(void) 377 { 378 kmem_cache_destroy(svnode_cache); 379 380 return (0); 381 } 382