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 * Copyright (c) 2017 by Delphix. All rights reserved. 27 */ 28 29 30 #include <sys/systm.h> 31 #include <sys/cmn_err.h> 32 33 #include <nfs/nfs.h> 34 35 #include <nfs/nfs4.h> 36 #include <nfs/rnode4.h> 37 #include <nfs/nfs4_clnt.h> 38 39 static struct kmem_cache *svnode_cache; 40 41 struct sv_stats 42 { 43 int sv_activate; 44 int sv_find; 45 int sv_match; 46 int sv_inactive; 47 int sv_exchange; 48 } sv_stats; 49 50 static int sv_match(nfs4_fname_t *, nfs4_sharedfh_t *, svnode_t *); 51 52 /* 53 * Map a vnode back to the shadow which points to it. This is 54 * hard now that the vnode is not embedded in the shadow vnode. 55 */ 56 57 58 svnode_t * 59 vtosv(vnode_t *vp) 60 { 61 rnode4_t *rp = VTOR4(vp); 62 svnode_t *svp, *svp_found = NULL; 63 64 /* Check to see if it's the master shadow vnode first. */ 65 66 if (RTOV4(rp) == vp) 67 return (&rp->r_svnode); 68 69 mutex_enter(&rp->r_svlock); 70 71 for (svp = rp->r_svnode.sv_forw; svp != &rp->r_svnode; 72 svp = svp->sv_forw) 73 if (svp->sv_r_vnode == vp) { 74 svp_found = svp; 75 break; 76 } 77 78 mutex_exit(&rp->r_svlock); 79 ASSERT(svp_found != NULL); 80 81 return (svp_found); 82 } 83 84 /* 85 * sv_activate - find and activate the shadow vnode for the given 86 * directory file handle and name. May replace *vpp with a held reference 87 * to a different vnode, in which case the reference to the previous one is 88 * released. 89 */ 90 91 void 92 sv_activate(vnode_t **vpp, vnode_t *dvp, nfs4_fname_t **namepp, int newnode) 93 { 94 svnode_t *svp; 95 vnode_t *resvp; 96 nfs4_fname_t *svpname; 97 rnode4_t *rp = VTOR4(*vpp); 98 svp = VTOSV(*vpp); 99 100 ASSERT(namepp != NULL); 101 ASSERT(*namepp != NULL); 102 ASSERT(dvp != NULL); 103 104 sv_stats.sv_activate++; 105 106 ASSERT(RW_LOCK_HELD(&rp->r_hashq->r_lock)); 107 108 /* 109 * If make_rnode made a new rnode (ie. newnode != 0), then 110 * the master vnode was (partially) initialized there. If 111 * it was not a new rnode, then it returns the master vnode. 112 * Call sv_find to find and/or initialize the shadow 113 * vnode. 114 */ 115 116 if (newnode) { 117 /* 118 * Initialize the shadow vnode. 119 */ 120 svp->sv_forw = svp->sv_back = svp; 121 ASSERT(svp->sv_dfh == NULL); 122 svp->sv_dfh = VTOR4(dvp)->r_fh; 123 sfh4_hold(svp->sv_dfh); 124 ASSERT(svp->sv_name == NULL); 125 svp->sv_name = *namepp; 126 } else if ((*vpp)->v_type == VREG && !((*vpp)->v_flag & VROOT)) { 127 resvp = sv_find(*vpp, dvp, namepp); 128 ASSERT(resvp->v_type == VREG); 129 VN_RELE(*vpp); 130 *vpp = resvp; 131 } else { 132 /* 133 * No shadow vnodes (i.e. hard links) in this branch. 134 * If sv_activate() is called for an existing rnode 135 * (newnode isn't set) but with a new name, the sv_name 136 * needs to be updated and the old sv_name released. 137 * 138 * fname mismatches can occur due to server side renames, 139 * here is a chance to update the fname in case there is 140 * a mismatch. Since this is not a newnode we hold r_svlock 141 * to protect sv_name. 142 */ 143 mutex_enter(&rp->r_svlock); 144 svpname = svp->sv_name; 145 if (svpname != *namepp) { 146 /* 147 * Call fn_rele() to release the hold for the 148 * previous shadow vnode reference. Don't 149 * release the hold on the fname pointed to by 150 * namepp as we have new reference to it from 151 * this shadow vnode. 152 */ 153 svp->sv_name = *namepp; 154 mutex_exit(&rp->r_svlock); 155 fn_rele(&svpname); 156 } else { 157 mutex_exit(&rp->r_svlock); 158 fn_rele(namepp); 159 } 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 VN_RELE_LOCKED(vp); 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