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