1 2621 llai1 /* 2 2621 llai1 * CDDL HEADER START 3 2621 llai1 * 4 2621 llai1 * The contents of this file are subject to the terms of the 5 2621 llai1 * Common Development and Distribution License (the "License"). 6 2621 llai1 * You may not use this file except in compliance with the License. 7 2621 llai1 * 8 2621 llai1 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 2621 llai1 * or http://www.opensolaris.org/os/licensing. 10 2621 llai1 * See the License for the specific language governing permissions 11 2621 llai1 * and limitations under the License. 12 2621 llai1 * 13 2621 llai1 * When distributing Covered Code, include this CDDL HEADER in each 14 2621 llai1 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 2621 llai1 * If applicable, add the following below this CDDL HEADER, with the 16 2621 llai1 * fields enclosed by brackets "[]" replaced with your own identifying 17 2621 llai1 * information: Portions Copyright [yyyy] [name of copyright owner] 18 2621 llai1 * 19 2621 llai1 * CDDL HEADER END 20 2621 llai1 */ 21 2621 llai1 /* 22 10097 Eric * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 2621 llai1 * Use is subject to license terms. 24 2621 llai1 */ 25 2621 llai1 26 2621 llai1 /* 27 2621 llai1 * utility routines for the /dev fs 28 2621 llai1 */ 29 2621 llai1 30 2621 llai1 #include <sys/types.h> 31 2621 llai1 #include <sys/param.h> 32 2621 llai1 #include <sys/t_lock.h> 33 2621 llai1 #include <sys/systm.h> 34 2621 llai1 #include <sys/sysmacros.h> 35 2621 llai1 #include <sys/user.h> 36 2621 llai1 #include <sys/time.h> 37 2621 llai1 #include <sys/vfs.h> 38 2621 llai1 #include <sys/vnode.h> 39 2621 llai1 #include <sys/file.h> 40 2621 llai1 #include <sys/fcntl.h> 41 2621 llai1 #include <sys/flock.h> 42 2621 llai1 #include <sys/kmem.h> 43 2621 llai1 #include <sys/uio.h> 44 2621 llai1 #include <sys/errno.h> 45 2621 llai1 #include <sys/stat.h> 46 2621 llai1 #include <sys/cred.h> 47 2621 llai1 #include <sys/dirent.h> 48 2621 llai1 #include <sys/pathname.h> 49 2621 llai1 #include <sys/cmn_err.h> 50 2621 llai1 #include <sys/debug.h> 51 2621 llai1 #include <sys/mode.h> 52 2621 llai1 #include <sys/policy.h> 53 2621 llai1 #include <fs/fs_subr.h> 54 2621 llai1 #include <sys/mount.h> 55 2621 llai1 #include <sys/fs/snode.h> 56 2621 llai1 #include <sys/fs/dv_node.h> 57 2621 llai1 #include <sys/fs/sdev_impl.h> 58 2621 llai1 #include <sys/sunndi.h> 59 2621 llai1 #include <sys/sunmdi.h> 60 2621 llai1 #include <sys/conf.h> 61 2621 llai1 #include <sys/proc.h> 62 2621 llai1 #include <sys/user.h> 63 2621 llai1 #include <sys/modctl.h> 64 2621 llai1 65 2621 llai1 #ifdef DEBUG 66 2621 llai1 int sdev_debug = 0x00000001; 67 2621 llai1 int sdev_debug_cache_flags = 0; 68 2621 llai1 #endif 69 2621 llai1 70 2621 llai1 /* 71 2621 llai1 * globals 72 2621 llai1 */ 73 2621 llai1 /* prototype memory vattrs */ 74 2621 llai1 vattr_t sdev_vattr_dir = { 75 2621 llai1 AT_TYPE|AT_MODE|AT_UID|AT_GID, /* va_mask */ 76 2621 llai1 VDIR, /* va_type */ 77 2621 llai1 SDEV_DIRMODE_DEFAULT, /* va_mode */ 78 2621 llai1 SDEV_UID_DEFAULT, /* va_uid */ 79 2621 llai1 SDEV_GID_DEFAULT, /* va_gid */ 80 2621 llai1 0, /* va_fsid */ 81 2621 llai1 0, /* va_nodeid */ 82 2621 llai1 0, /* va_nlink */ 83 2621 llai1 0, /* va_size */ 84 2621 llai1 0, /* va_atime */ 85 2621 llai1 0, /* va_mtime */ 86 2621 llai1 0, /* va_ctime */ 87 2621 llai1 0, /* va_rdev */ 88 2621 llai1 0, /* va_blksize */ 89 2621 llai1 0, /* va_nblocks */ 90 2621 llai1 0 /* va_vcode */ 91 2621 llai1 }; 92 2621 llai1 93 2621 llai1 vattr_t sdev_vattr_lnk = { 94 2621 llai1 AT_TYPE|AT_MODE, /* va_mask */ 95 2621 llai1 VLNK, /* va_type */ 96 2621 llai1 SDEV_LNKMODE_DEFAULT, /* va_mode */ 97 2621 llai1 SDEV_UID_DEFAULT, /* va_uid */ 98 2621 llai1 SDEV_GID_DEFAULT, /* va_gid */ 99 2621 llai1 0, /* va_fsid */ 100 2621 llai1 0, /* va_nodeid */ 101 2621 llai1 0, /* va_nlink */ 102 2621 llai1 0, /* va_size */ 103 2621 llai1 0, /* va_atime */ 104 2621 llai1 0, /* va_mtime */ 105 2621 llai1 0, /* va_ctime */ 106 2621 llai1 0, /* va_rdev */ 107 2621 llai1 0, /* va_blksize */ 108 2621 llai1 0, /* va_nblocks */ 109 2621 llai1 0 /* va_vcode */ 110 2621 llai1 }; 111 2621 llai1 112 2621 llai1 vattr_t sdev_vattr_blk = { 113 2621 llai1 AT_TYPE|AT_MODE|AT_UID|AT_GID, /* va_mask */ 114 2621 llai1 VBLK, /* va_type */ 115 2621 llai1 S_IFBLK | SDEV_DEVMODE_DEFAULT, /* va_mode */ 116 2621 llai1 SDEV_UID_DEFAULT, /* va_uid */ 117 2621 llai1 SDEV_GID_DEFAULT, /* va_gid */ 118 2621 llai1 0, /* va_fsid */ 119 2621 llai1 0, /* va_nodeid */ 120 2621 llai1 0, /* va_nlink */ 121 2621 llai1 0, /* va_size */ 122 2621 llai1 0, /* va_atime */ 123 2621 llai1 0, /* va_mtime */ 124 2621 llai1 0, /* va_ctime */ 125 2621 llai1 0, /* va_rdev */ 126 2621 llai1 0, /* va_blksize */ 127 2621 llai1 0, /* va_nblocks */ 128 2621 llai1 0 /* va_vcode */ 129 2621 llai1 }; 130 2621 llai1 131 2621 llai1 vattr_t sdev_vattr_chr = { 132 2621 llai1 AT_TYPE|AT_MODE|AT_UID|AT_GID, /* va_mask */ 133 2621 llai1 VCHR, /* va_type */ 134 2621 llai1 S_IFCHR | SDEV_DEVMODE_DEFAULT, /* va_mode */ 135 2621 llai1 SDEV_UID_DEFAULT, /* va_uid */ 136 2621 llai1 SDEV_GID_DEFAULT, /* va_gid */ 137 2621 llai1 0, /* va_fsid */ 138 2621 llai1 0, /* va_nodeid */ 139 2621 llai1 0, /* va_nlink */ 140 2621 llai1 0, /* va_size */ 141 2621 llai1 0, /* va_atime */ 142 2621 llai1 0, /* va_mtime */ 143 2621 llai1 0, /* va_ctime */ 144 2621 llai1 0, /* va_rdev */ 145 2621 llai1 0, /* va_blksize */ 146 2621 llai1 0, /* va_nblocks */ 147 2621 llai1 0 /* va_vcode */ 148 2621 llai1 }; 149 2621 llai1 150 2621 llai1 kmem_cache_t *sdev_node_cache; /* sdev_node cache */ 151 2621 llai1 int devtype; /* fstype */ 152 2621 llai1 153 2621 llai1 /* static */ 154 2621 llai1 static struct vnodeops *sdev_get_vop(struct sdev_node *); 155 10588 Eric static void sdev_set_no_negcache(struct sdev_node *); 156 2621 llai1 static fs_operation_def_t *sdev_merge_vtab(const fs_operation_def_t []); 157 2621 llai1 static void sdev_free_vtab(fs_operation_def_t *); 158 2621 llai1 159 2621 llai1 static void 160 2621 llai1 sdev_prof_free(struct sdev_node *dv) 161 2621 llai1 { 162 2621 llai1 ASSERT(!SDEV_IS_GLOBAL(dv)); 163 2621 llai1 if (dv->sdev_prof.dev_name) 164 2621 llai1 nvlist_free(dv->sdev_prof.dev_name); 165 2621 llai1 if (dv->sdev_prof.dev_map) 166 2621 llai1 nvlist_free(dv->sdev_prof.dev_map); 167 2621 llai1 if (dv->sdev_prof.dev_symlink) 168 2621 llai1 nvlist_free(dv->sdev_prof.dev_symlink); 169 2621 llai1 if (dv->sdev_prof.dev_glob_incdir) 170 2621 llai1 nvlist_free(dv->sdev_prof.dev_glob_incdir); 171 2621 llai1 if (dv->sdev_prof.dev_glob_excdir) 172 2621 llai1 nvlist_free(dv->sdev_prof.dev_glob_excdir); 173 2621 llai1 bzero(&dv->sdev_prof, sizeof (dv->sdev_prof)); 174 2621 llai1 } 175 2621 llai1 176 6712 tomee /* sdev_node cache constructor */ 177 2621 llai1 /*ARGSUSED1*/ 178 2621 llai1 static int 179 2621 llai1 i_sdev_node_ctor(void *buf, void *cfarg, int flag) 180 2621 llai1 { 181 2621 llai1 struct sdev_node *dv = (struct sdev_node *)buf; 182 2621 llai1 struct vnode *vp; 183 2621 llai1 184 2621 llai1 bzero(buf, sizeof (struct sdev_node)); 185 6712 tomee vp = dv->sdev_vnode = vn_alloc(flag); 186 6712 tomee if (vp == NULL) { 187 6712 tomee return (-1); 188 6712 tomee } 189 6712 tomee vp->v_data = dv; 190 2621 llai1 rw_init(&dv->sdev_contents, NULL, RW_DEFAULT, NULL); 191 2621 llai1 return (0); 192 2621 llai1 } 193 2621 llai1 194 6712 tomee /* sdev_node cache destructor */ 195 2621 llai1 /*ARGSUSED1*/ 196 2621 llai1 static void 197 2621 llai1 i_sdev_node_dtor(void *buf, void *arg) 198 2621 llai1 { 199 2621 llai1 struct sdev_node *dv = (struct sdev_node *)buf; 200 2621 llai1 struct vnode *vp = SDEVTOV(dv); 201 2621 llai1 202 2621 llai1 rw_destroy(&dv->sdev_contents); 203 2621 llai1 vn_free(vp); 204 2621 llai1 } 205 2621 llai1 206 2621 llai1 /* initialize sdev_node cache */ 207 2621 llai1 void 208 2621 llai1 sdev_node_cache_init() 209 2621 llai1 { 210 2621 llai1 int flags = 0; 211 2621 llai1 212 2621 llai1 #ifdef DEBUG 213 2621 llai1 flags = sdev_debug_cache_flags; 214 2621 llai1 if (flags) 215 2621 llai1 sdcmn_err(("cache debug flags 0x%x\n", flags)); 216 2621 llai1 #endif /* DEBUG */ 217 2621 llai1 218 2621 llai1 ASSERT(sdev_node_cache == NULL); 219 2621 llai1 sdev_node_cache = kmem_cache_create("sdev_node_cache", 220 2621 llai1 sizeof (struct sdev_node), 0, i_sdev_node_ctor, i_sdev_node_dtor, 221 2621 llai1 NULL, NULL, NULL, flags); 222 2621 llai1 } 223 2621 llai1 224 2621 llai1 /* destroy sdev_node cache */ 225 2621 llai1 void 226 2621 llai1 sdev_node_cache_fini() 227 2621 llai1 { 228 2621 llai1 ASSERT(sdev_node_cache != NULL); 229 2621 llai1 kmem_cache_destroy(sdev_node_cache); 230 2621 llai1 sdev_node_cache = NULL; 231 2621 llai1 } 232 2621 llai1 233 6260 jg /* 234 6260 jg * Compare two nodes lexographically to balance avl tree 235 6260 jg */ 236 6260 jg static int 237 6260 jg sdev_compare_nodes(const struct sdev_node *dv1, const struct sdev_node *dv2) 238 6260 jg { 239 6260 jg int rv; 240 6260 jg if ((rv = strcmp(dv1->sdev_name, dv2->sdev_name)) == 0) 241 6260 jg return (0); 242 6260 jg return ((rv < 0) ? -1 : 1); 243 6260 jg } 244 6260 jg 245 2621 llai1 void 246 2621 llai1 sdev_set_nodestate(struct sdev_node *dv, sdev_node_state_t state) 247 2621 llai1 { 248 2621 llai1 ASSERT(dv); 249 2621 llai1 ASSERT(RW_WRITE_HELD(&dv->sdev_contents)); 250 2621 llai1 dv->sdev_state = state; 251 2621 llai1 } 252 2621 llai1 253 2621 llai1 static void 254 2621 llai1 sdev_attrinit(struct sdev_node *dv, vattr_t *vap) 255 2621 llai1 { 256 2621 llai1 timestruc_t now; 257 2621 llai1 258 2621 llai1 ASSERT(vap); 259 2621 llai1 260 2621 llai1 dv->sdev_attr = kmem_zalloc(sizeof (struct vattr), KM_SLEEP); 261 2621 llai1 *dv->sdev_attr = *vap; 262 2621 llai1 263 2621 llai1 dv->sdev_attr->va_mode = MAKEIMODE(vap->va_type, vap->va_mode); 264 2621 llai1 265 2621 llai1 gethrestime(&now); 266 2621 llai1 dv->sdev_attr->va_atime = now; 267 2621 llai1 dv->sdev_attr->va_mtime = now; 268 2621 llai1 dv->sdev_attr->va_ctime = now; 269 2621 llai1 } 270 2621 llai1 271 2621 llai1 /* alloc and initialize a sdev_node */ 272 2621 llai1 int 273 2621 llai1 sdev_nodeinit(struct sdev_node *ddv, char *nm, struct sdev_node **newdv, 274 2621 llai1 vattr_t *vap) 275 2621 llai1 { 276 2621 llai1 struct sdev_node *dv = NULL; 277 2621 llai1 struct vnode *vp; 278 2621 llai1 size_t nmlen, len; 279 2621 llai1 devname_handle_t *dhl; 280 2621 llai1 281 2621 llai1 nmlen = strlen(nm) + 1; 282 2621 llai1 if (nmlen > MAXNAMELEN) { 283 2621 llai1 sdcmn_err9(("sdev_nodeinit: node name %s" 284 2621 llai1 " too long\n", nm)); 285 2621 llai1 *newdv = NULL; 286 2621 llai1 return (ENAMETOOLONG); 287 2621 llai1 } 288 2621 llai1 289 2621 llai1 dv = kmem_cache_alloc(sdev_node_cache, KM_SLEEP); 290 2621 llai1 291 2621 llai1 dv->sdev_name = kmem_alloc(nmlen, KM_SLEEP); 292 2621 llai1 bcopy(nm, dv->sdev_name, nmlen); 293 2621 llai1 dv->sdev_namelen = nmlen - 1; /* '\0' not included */ 294 2621 llai1 len = strlen(ddv->sdev_path) + strlen(nm) + 2; 295 2621 llai1 dv->sdev_path = kmem_alloc(len, KM_SLEEP); 296 2621 llai1 (void) snprintf(dv->sdev_path, len, "%s/%s", ddv->sdev_path, nm); 297 2621 llai1 /* overwritten for VLNK nodes */ 298 2621 llai1 dv->sdev_symlink = NULL; 299 2621 llai1 300 2621 llai1 vp = SDEVTOV(dv); 301 2621 llai1 vn_reinit(vp); 302 2621 llai1 vp->v_vfsp = SDEVTOV(ddv)->v_vfsp; 303 2621 llai1 if (vap) 304 2621 llai1 vp->v_type = vap->va_type; 305 2621 llai1 306 2621 llai1 /* 307 2621 llai1 * initialized to the parent's vnodeops. 308 2621 llai1 * maybe overwriten for a VDIR 309 2621 llai1 */ 310 2621 llai1 vn_setops(vp, vn_getops(SDEVTOV(ddv))); 311 2621 llai1 vn_exists(vp); 312 2621 llai1 313 2621 llai1 dv->sdev_dotdot = NULL; 314 2621 llai1 dv->sdev_attrvp = NULL; 315 2621 llai1 if (vap) { 316 2621 llai1 sdev_attrinit(dv, vap); 317 2621 llai1 } else { 318 2621 llai1 dv->sdev_attr = NULL; 319 2621 llai1 } 320 2621 llai1 321 2621 llai1 dv->sdev_ino = sdev_mkino(dv); 322 2621 llai1 dv->sdev_nlink = 0; /* updated on insert */ 323 2621 llai1 dv->sdev_flags = ddv->sdev_flags; /* inherit from the parent first */ 324 2621 llai1 dv->sdev_flags |= SDEV_BUILD; 325 2621 llai1 mutex_init(&dv->sdev_lookup_lock, NULL, MUTEX_DEFAULT, NULL); 326 2621 llai1 cv_init(&dv->sdev_lookup_cv, NULL, CV_DEFAULT, NULL); 327 2621 llai1 if (SDEV_IS_GLOBAL(ddv)) { 328 2621 llai1 dv->sdev_flags |= SDEV_GLOBAL; 329 2621 llai1 dhl = &(dv->sdev_handle); 330 2621 llai1 dhl->dh_data = dv; 331 2621 llai1 dhl->dh_args = NULL; 332 10588 Eric sdev_set_no_negcache(dv); 333 2621 llai1 dv->sdev_gdir_gen = 0; 334 2621 llai1 } else { 335 2621 llai1 dv->sdev_flags &= ~SDEV_GLOBAL; 336 2621 llai1 dv->sdev_origin = NULL; /* set later */ 337 2621 llai1 bzero(&dv->sdev_prof, sizeof (dv->sdev_prof)); 338 2621 llai1 dv->sdev_ldir_gen = 0; 339 2621 llai1 dv->sdev_devtree_gen = 0; 340 2621 llai1 } 341 2621 llai1 342 2621 llai1 rw_enter(&dv->sdev_contents, RW_WRITER); 343 2621 llai1 sdev_set_nodestate(dv, SDEV_INIT); 344 2621 llai1 rw_exit(&dv->sdev_contents); 345 2621 llai1 *newdv = dv; 346 2621 llai1 347 2621 llai1 return (0); 348 2621 llai1 } 349 2621 llai1 350 2621 llai1 /* 351 2621 llai1 * transition a sdev_node into SDEV_READY state 352 2621 llai1 */ 353 2621 llai1 int 354 2621 llai1 sdev_nodeready(struct sdev_node *dv, struct vattr *vap, struct vnode *avp, 355 2621 llai1 void *args, struct cred *cred) 356 2621 llai1 { 357 2621 llai1 int error = 0; 358 2621 llai1 struct vnode *vp = SDEVTOV(dv); 359 2621 llai1 vtype_t type; 360 2621 llai1 361 2621 llai1 ASSERT(dv && (dv->sdev_state != SDEV_READY) && vap); 362 2621 llai1 363 2621 llai1 type = vap->va_type; 364 2621 llai1 vp->v_type = type; 365 2621 llai1 vp->v_rdev = vap->va_rdev; 366 2621 llai1 rw_enter(&dv->sdev_contents, RW_WRITER); 367 2621 llai1 if (type == VDIR) { 368 2621 llai1 dv->sdev_nlink = 2; 369 2621 llai1 dv->sdev_flags &= ~SDEV_PERSIST; 370 2621 llai1 dv->sdev_flags &= ~SDEV_DYNAMIC; 371 2621 llai1 vn_setops(vp, sdev_get_vop(dv)); /* from internal vtab */ 372 2621 llai1 ASSERT(dv->sdev_dotdot); 373 2621 llai1 ASSERT(SDEVTOV(dv->sdev_dotdot)->v_type == VDIR); 374 2621 llai1 vp->v_rdev = SDEVTOV(dv->sdev_dotdot)->v_rdev; 375 6260 jg avl_create(&dv->sdev_entries, 376 6260 jg (int (*)(const void *, const void *))sdev_compare_nodes, 377 6260 jg sizeof (struct sdev_node), 378 6260 jg offsetof(struct sdev_node, sdev_avllink)); 379 2621 llai1 } else if (type == VLNK) { 380 2621 llai1 ASSERT(args); 381 2621 llai1 dv->sdev_nlink = 1; 382 2621 llai1 dv->sdev_symlink = i_ddi_strdup((char *)args, KM_SLEEP); 383 2621 llai1 } else { 384 2621 llai1 dv->sdev_nlink = 1; 385 2621 llai1 } 386 2621 llai1 387 2621 llai1 if (!(SDEV_IS_GLOBAL(dv))) { 388 2621 llai1 dv->sdev_origin = (struct sdev_node *)args; 389 2621 llai1 dv->sdev_flags &= ~SDEV_PERSIST; 390 2621 llai1 } 391 2621 llai1 392 2621 llai1 /* 393 2621 llai1 * shadow node is created here OR 394 2621 llai1 * if failed (indicated by dv->sdev_attrvp == NULL), 395 2621 llai1 * created later in sdev_setattr 396 2621 llai1 */ 397 2621 llai1 if (avp) { 398 2621 llai1 dv->sdev_attrvp = avp; 399 2621 llai1 } else { 400 2621 llai1 if (dv->sdev_attr == NULL) 401 2621 llai1 sdev_attrinit(dv, vap); 402 2621 llai1 else 403 2621 llai1 *dv->sdev_attr = *vap; 404 2621 llai1 405 10588 Eric if ((dv->sdev_attrvp == NULL) && SDEV_IS_PERSIST(dv)) 406 2621 llai1 error = sdev_shadow_node(dv, cred); 407 2621 llai1 } 408 2621 llai1 409 6335 jg if (error == 0) { 410 6335 jg /* transition to READY state */ 411 6335 jg sdev_set_nodestate(dv, SDEV_READY); 412 6335 jg sdev_nc_node_exists(dv); 413 6335 jg } else { 414 6335 jg sdev_set_nodestate(dv, SDEV_ZOMBIE); 415 6335 jg } 416 2621 llai1 rw_exit(&dv->sdev_contents); 417 2621 llai1 return (error); 418 2621 llai1 } 419 2621 llai1 420 2621 llai1 /* 421 2621 llai1 * setting ZOMBIE state 422 2621 llai1 */ 423 2621 llai1 static int 424 2621 llai1 sdev_nodezombied(struct sdev_node *dv) 425 2621 llai1 { 426 2621 llai1 rw_enter(&dv->sdev_contents, RW_WRITER); 427 2621 llai1 sdev_set_nodestate(dv, SDEV_ZOMBIE); 428 2621 llai1 rw_exit(&dv->sdev_contents); 429 2621 llai1 return (0); 430 2621 llai1 } 431 2621 llai1 432 2621 llai1 /* 433 2621 llai1 * Build the VROOT sdev_node. 434 2621 llai1 */ 435 2621 llai1 /*ARGSUSED*/ 436 2621 llai1 struct sdev_node * 437 2621 llai1 sdev_mkroot(struct vfs *vfsp, dev_t devdev, struct vnode *mvp, 438 2621 llai1 struct vnode *avp, struct cred *cred) 439 2621 llai1 { 440 2621 llai1 struct sdev_node *dv; 441 2621 llai1 struct vnode *vp; 442 2621 llai1 char devdir[] = "/dev"; 443 2621 llai1 444 2621 llai1 ASSERT(sdev_node_cache != NULL); 445 2621 llai1 ASSERT(avp); 446 2621 llai1 dv = kmem_cache_alloc(sdev_node_cache, KM_SLEEP); 447 2621 llai1 vp = SDEVTOV(dv); 448 2621 llai1 vn_reinit(vp); 449 2621 llai1 vp->v_flag |= VROOT; 450 2621 llai1 vp->v_vfsp = vfsp; 451 2621 llai1 vp->v_type = VDIR; 452 2621 llai1 vp->v_rdev = devdev; 453 2621 llai1 vn_setops(vp, sdev_vnodeops); /* apply the default vnodeops at /dev */ 454 2621 llai1 vn_exists(vp); 455 2621 llai1 456 2621 llai1 if (vfsp->vfs_mntpt) 457 2621 llai1 dv->sdev_name = i_ddi_strdup( 458 2621 llai1 (char *)refstr_value(vfsp->vfs_mntpt), KM_SLEEP); 459 2621 llai1 else 460 2621 llai1 /* vfs_mountdev1 set mount point later */ 461 2621 llai1 dv->sdev_name = i_ddi_strdup("/dev", KM_SLEEP); 462 2621 llai1 dv->sdev_namelen = strlen(dv->sdev_name); /* '\0' not included */ 463 2621 llai1 dv->sdev_path = i_ddi_strdup(devdir, KM_SLEEP); 464 2621 llai1 dv->sdev_ino = SDEV_ROOTINO; 465 2621 llai1 dv->sdev_nlink = 2; /* name + . (no sdev_insert) */ 466 2621 llai1 dv->sdev_dotdot = dv; /* .. == self */ 467 2621 llai1 dv->sdev_attrvp = avp; 468 2621 llai1 dv->sdev_attr = NULL; 469 2621 llai1 mutex_init(&dv->sdev_lookup_lock, NULL, MUTEX_DEFAULT, NULL); 470 2621 llai1 cv_init(&dv->sdev_lookup_cv, NULL, CV_DEFAULT, NULL); 471 2621 llai1 if (strcmp(dv->sdev_name, "/dev") == 0) { 472 2621 llai1 dv->sdev_flags = SDEV_BUILD|SDEV_GLOBAL|SDEV_PERSIST; 473 2621 llai1 bzero(&dv->sdev_handle, sizeof (dv->sdev_handle)); 474 2621 llai1 dv->sdev_gdir_gen = 0; 475 2621 llai1 } else { 476 2621 llai1 dv->sdev_flags = SDEV_BUILD; 477 2621 llai1 dv->sdev_flags &= ~SDEV_PERSIST; 478 2621 llai1 bzero(&dv->sdev_prof, sizeof (dv->sdev_prof)); 479 2621 llai1 dv->sdev_ldir_gen = 0; 480 2621 llai1 dv->sdev_devtree_gen = 0; 481 2621 llai1 } 482 6260 jg 483 6260 jg avl_create(&dv->sdev_entries, 484 6260 jg (int (*)(const void *, const void *))sdev_compare_nodes, 485 6260 jg sizeof (struct sdev_node), 486 6260 jg offsetof(struct sdev_node, sdev_avllink)); 487 2621 llai1 488 2621 llai1 rw_enter(&dv->sdev_contents, RW_WRITER); 489 2621 llai1 sdev_set_nodestate(dv, SDEV_READY); 490 2621 llai1 rw_exit(&dv->sdev_contents); 491 2621 llai1 sdev_nc_node_exists(dv); 492 2621 llai1 return (dv); 493 2621 llai1 } 494 2621 llai1 495 2621 llai1 /* directory dependent vop table */ 496 2621 llai1 struct sdev_vop_table { 497 2621 llai1 char *vt_name; /* subdirectory name */ 498 2621 llai1 const fs_operation_def_t *vt_service; /* vnodeops table */ 499 2621 llai1 struct vnodeops *vt_vops; /* constructed vop */ 500 2621 llai1 struct vnodeops **vt_global_vops; /* global container for vop */ 501 2621 llai1 int (*vt_vtor)(struct sdev_node *); /* validate sdev_node */ 502 2621 llai1 int vt_flags; 503 2621 llai1 }; 504 2621 llai1 505 2621 llai1 /* 506 2621 llai1 * A nice improvement would be to provide a plug-in mechanism 507 2621 llai1 * for this table instead of a const table. 508 2621 llai1 */ 509 2621 llai1 static struct sdev_vop_table vtab[] = 510 2621 llai1 { 511 2621 llai1 { "pts", devpts_vnodeops_tbl, NULL, &devpts_vnodeops, devpts_validate, 512 7688 Aaron SDEV_DYNAMIC | SDEV_VTOR }, 513 7688 Aaron 514 7688 Aaron { "vt", devvt_vnodeops_tbl, NULL, &devvt_vnodeops, devvt_validate, 515 2621 llai1 SDEV_DYNAMIC | SDEV_VTOR }, 516 2621 llai1 517 10588 Eric { "zvol", devzvol_vnodeops_tbl, NULL, &devzvol_vnodeops, 518 10588 Eric devzvol_validate, SDEV_DYNAMIC | SDEV_VTOR | SDEV_SUBDIR }, 519 10588 Eric 520 2621 llai1 { "zcons", NULL, NULL, NULL, NULL, SDEV_NO_NCACHE }, 521 5895 yz147064 522 5895 yz147064 { "net", devnet_vnodeops_tbl, NULL, &devnet_vnodeops, devnet_validate, 523 5895 yz147064 SDEV_DYNAMIC | SDEV_VTOR }, 524 8023 Phil 525 8023 Phil { "ipnet", devipnet_vnodeops_tbl, NULL, &devipnet_vnodeops, 526 8023 Phil devipnet_validate, SDEV_DYNAMIC | SDEV_VTOR | SDEV_NO_NCACHE }, 527 2621 llai1 528 2621 llai1 { NULL, NULL, NULL, NULL, NULL, 0} 529 2621 llai1 }; 530 2621 llai1 531 10588 Eric struct sdev_vop_table * 532 10588 Eric sdev_match(struct sdev_node *dv) 533 10588 Eric { 534 10588 Eric int vlen; 535 10588 Eric int i; 536 10588 Eric 537 10588 Eric for (i = 0; vtab[i].vt_name; i++) { 538 10588 Eric if (strcmp(vtab[i].vt_name, dv->sdev_name) == 0) 539 10588 Eric return (&vtab[i]); 540 10588 Eric if (vtab[i].vt_flags & SDEV_SUBDIR) { 541 10588 Eric char *ptr; 542 10588 Eric 543 10588 Eric ASSERT(strlen(dv->sdev_path) > 5); 544 10588 Eric ptr = dv->sdev_path + 5; 545 10588 Eric vlen = strlen(vtab[i].vt_name); 546 10588 Eric if ((strncmp(vtab[i].vt_name, ptr, 547 10588 Eric vlen - 1) == 0) && ptr[vlen] == '/') 548 10588 Eric return (&vtab[i]); 549 10588 Eric } 550 10588 Eric 551 10588 Eric } 552 10588 Eric return (NULL); 553 10588 Eric } 554 2621 llai1 555 2621 llai1 /* 556 2621 llai1 * sets a directory's vnodeops if the directory is in the vtab; 557 2621 llai1 */ 558 2621 llai1 static struct vnodeops * 559 2621 llai1 sdev_get_vop(struct sdev_node *dv) 560 2621 llai1 { 561 10588 Eric struct sdev_vop_table *vtp; 562 2621 llai1 char *path; 563 2621 llai1 564 2621 llai1 path = dv->sdev_path; 565 2621 llai1 ASSERT(path); 566 2621 llai1 567 2621 llai1 /* gets the relative path to /dev/ */ 568 2621 llai1 path += 5; 569 2621 llai1 570 10588 Eric /* gets the vtab entry it matches */ 571 10588 Eric if ((vtp = sdev_match(dv)) != NULL) { 572 10588 Eric dv->sdev_flags |= vtp->vt_flags; 573 2621 llai1 574 10588 Eric if (vtp->vt_vops) { 575 10588 Eric if (vtp->vt_global_vops) 576 10588 Eric *(vtp->vt_global_vops) = vtp->vt_vops; 577 10588 Eric return (vtp->vt_vops); 578 2621 llai1 } 579 2621 llai1 580 10588 Eric if (vtp->vt_service) { 581 2621 llai1 fs_operation_def_t *templ; 582 10588 Eric templ = sdev_merge_vtab(vtp->vt_service); 583 10588 Eric if (vn_make_ops(vtp->vt_name, 584 2621 llai1 (const fs_operation_def_t *)templ, 585 10588 Eric &vtp->vt_vops) != 0) { 586 2621 llai1 cmn_err(CE_PANIC, "%s: malformed vnode ops\n", 587 10588 Eric vtp->vt_name); 588 2621 llai1 /*NOTREACHED*/ 589 2621 llai1 } 590 10588 Eric if (vtp->vt_global_vops) { 591 10588 Eric *(vtp->vt_global_vops) = vtp->vt_vops; 592 2621 llai1 } 593 2621 llai1 sdev_free_vtab(templ); 594 10588 Eric return (vtp->vt_vops); 595 2621 llai1 } 596 2621 llai1 return (sdev_vnodeops); 597 2621 llai1 } 598 2621 llai1 599 2621 llai1 /* child inherits the persistence of the parent */ 600 2621 llai1 if (SDEV_IS_PERSIST(dv->sdev_dotdot)) 601 2621 llai1 dv->sdev_flags |= SDEV_PERSIST; 602 2621 llai1 603 2621 llai1 return (sdev_vnodeops); 604 2621 llai1 } 605 2621 llai1 606 2621 llai1 static void 607 10588 Eric sdev_set_no_negcache(struct sdev_node *dv) 608 2621 llai1 { 609 2621 llai1 int i; 610 2621 llai1 char *path; 611 2621 llai1 612 2621 llai1 ASSERT(dv->sdev_path); 613 2621 llai1 path = dv->sdev_path + strlen("/dev/"); 614 2621 llai1 615 2621 llai1 for (i = 0; vtab[i].vt_name; i++) { 616 2621 llai1 if (strcmp(vtab[i].vt_name, path) == 0) { 617 2621 llai1 if (vtab[i].vt_flags & SDEV_NO_NCACHE) 618 2621 llai1 dv->sdev_flags |= SDEV_NO_NCACHE; 619 2621 llai1 break; 620 2621 llai1 } 621 2621 llai1 } 622 2621 llai1 } 623 2621 llai1 624 2621 llai1 void * 625 2621 llai1 sdev_get_vtor(struct sdev_node *dv) 626 2621 llai1 { 627 10588 Eric struct sdev_vop_table *vtp; 628 2621 llai1 629 10588 Eric vtp = sdev_match(dv); 630 10588 Eric if (vtp) 631 10588 Eric return ((void *)vtp->vt_vtor); 632 10588 Eric else 633 10588 Eric return (NULL); 634 2621 llai1 } 635 2621 llai1 636 2621 llai1 /* 637 2621 llai1 * Build the base root inode 638 2621 llai1 */ 639 2621 llai1 ino_t 640 2621 llai1 sdev_mkino(struct sdev_node *dv) 641 2621 llai1 { 642 2621 llai1 ino_t ino; 643 2621 llai1 644 2621 llai1 /* 645 2621 llai1 * for now, follow the lead of tmpfs here 646 2621 llai1 * need to someday understand the requirements here 647 2621 llai1 */ 648 2621 llai1 ino = (ino_t)(uint32_t)((uintptr_t)dv >> 3); 649 2621 llai1 ino += SDEV_ROOTINO + 1; 650 2621 llai1 651 2621 llai1 return (ino); 652 2621 llai1 } 653 2621 llai1 654 10588 Eric int 655 2621 llai1 sdev_getlink(struct vnode *linkvp, char **link) 656 2621 llai1 { 657 2621 llai1 int err; 658 2621 llai1 char *buf; 659 2621 llai1 struct uio uio = {0}; 660 2621 llai1 struct iovec iov = {0}; 661 2621 llai1 662 2621 llai1 if (linkvp == NULL) 663 2621 llai1 return (ENOENT); 664 2621 llai1 ASSERT(linkvp->v_type == VLNK); 665 2621 llai1 666 2621 llai1 buf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 667 2621 llai1 iov.iov_base = buf; 668 2621 llai1 iov.iov_len = MAXPATHLEN; 669 2621 llai1 uio.uio_iov = &iov; 670 2621 llai1 uio.uio_iovcnt = 1; 671 2621 llai1 uio.uio_resid = MAXPATHLEN; 672 2621 llai1 uio.uio_segflg = UIO_SYSSPACE; 673 2621 llai1 uio.uio_llimit = MAXOFFSET_T; 674 2621 llai1 675 5331 amw err = VOP_READLINK(linkvp, &uio, kcred, NULL); 676 2621 llai1 if (err) { 677 2621 llai1 cmn_err(CE_WARN, "readlink %s failed in dev\n", buf); 678 2621 llai1 kmem_free(buf, MAXPATHLEN); 679 2621 llai1 return (ENOENT); 680 2621 llai1 } 681 2621 llai1 682 2621 llai1 /* mission complete */ 683 2621 llai1 *link = i_ddi_strdup(buf, KM_SLEEP); 684 2621 llai1 kmem_free(buf, MAXPATHLEN); 685 2621 llai1 return (0); 686 2621 llai1 } 687 2621 llai1 688 2621 llai1 /* 689 2621 llai1 * A convenient wrapper to get the devfs node vnode for a device 690 2621 llai1 * minor functionality: readlink() of a /dev symlink 691 2621 llai1 * Place the link into dv->sdev_symlink 692 2621 llai1 */ 693 2621 llai1 static int 694 2621 llai1 sdev_follow_link(struct sdev_node *dv) 695 2621 llai1 { 696 2621 llai1 int err; 697 2621 llai1 struct vnode *linkvp; 698 2621 llai1 char *link = NULL; 699 2621 llai1 700 2621 llai1 linkvp = SDEVTOV(dv); 701 2621 llai1 if (linkvp == NULL) 702 2621 llai1 return (ENOENT); 703 2621 llai1 ASSERT(linkvp->v_type == VLNK); 704 2621 llai1 err = sdev_getlink(linkvp, &link); 705 2621 llai1 if (err) { 706 2621 llai1 (void) sdev_nodezombied(dv); 707 2621 llai1 dv->sdev_symlink = NULL; 708 2621 llai1 return (ENOENT); 709 2621 llai1 } 710 2621 llai1 711 2621 llai1 ASSERT(link != NULL); 712 2621 llai1 dv->sdev_symlink = link; 713 2621 llai1 return (0); 714 2621 llai1 } 715 2621 llai1 716 2621 llai1 static int 717 2621 llai1 sdev_node_check(struct sdev_node *dv, struct vattr *nvap, void *nargs) 718 2621 llai1 { 719 2621 llai1 vtype_t otype = SDEVTOV(dv)->v_type; 720 2621 llai1 721 2621 llai1 /* 722 2621 llai1 * existing sdev_node has a different type. 723 2621 llai1 */ 724 2621 llai1 if (otype != nvap->va_type) { 725 2621 llai1 sdcmn_err9(("sdev_node_check: existing node " 726 2621 llai1 " %s type %d does not match new node type %d\n", 727 2621 llai1 dv->sdev_name, otype, nvap->va_type)); 728 2621 llai1 return (EEXIST); 729 2621 llai1 } 730 2621 llai1 731 2621 llai1 /* 732 2621 llai1 * For a symlink, the target should be the same. 733 2621 llai1 */ 734 2621 llai1 if (otype == VLNK) { 735 2621 llai1 ASSERT(nargs != NULL); 736 2621 llai1 ASSERT(dv->sdev_symlink != NULL); 737 2621 llai1 if (strcmp(dv->sdev_symlink, (char *)nargs) != 0) { 738 2621 llai1 sdcmn_err9(("sdev_node_check: existing node " 739 2621 llai1 " %s has different symlink %s as new node " 740 2621 llai1 " %s\n", dv->sdev_name, dv->sdev_symlink, 741 2621 llai1 (char *)nargs)); 742 2621 llai1 return (EEXIST); 743 2621 llai1 } 744 2621 llai1 } 745 2621 llai1 746 2621 llai1 return (0); 747 2621 llai1 } 748 2621 llai1 749 2621 llai1 /* 750 2621 llai1 * sdev_mknode - a wrapper for sdev_nodeinit(), sdev_nodeready() 751 2621 llai1 * 752 2621 llai1 * arguments: 753 2621 llai1 * - ddv (parent) 754 2621 llai1 * - nm (child name) 755 2621 llai1 * - newdv (sdev_node for nm is returned here) 756 2621 llai1 * - vap (vattr for the node to be created, va_type should be set. 757 6335 jg * - avp (attribute vnode) 758 2621 llai1 * the defaults should be used if unknown) 759 2621 llai1 * - cred 760 2621 llai1 * - args 761 2621 llai1 * . tnm (for VLNK) 762 2621 llai1 * . global sdev_node (for !SDEV_GLOBAL) 763 2621 llai1 * - state: SDEV_INIT, SDEV_READY 764 2621 llai1 * 765 2621 llai1 * only ddv, nm, newddv, vap, cred are required for sdev_mknode(SDEV_INIT) 766 2621 llai1 * 767 2621 llai1 * NOTE: directory contents writers lock needs to be held before 768 2621 llai1 * calling this routine. 769 2621 llai1 */ 770 2621 llai1 int 771 2621 llai1 sdev_mknode(struct sdev_node *ddv, char *nm, struct sdev_node **newdv, 772 2621 llai1 struct vattr *vap, struct vnode *avp, void *args, struct cred *cred, 773 2621 llai1 sdev_node_state_t state) 774 2621 llai1 { 775 2621 llai1 int error = 0; 776 2621 llai1 sdev_node_state_t node_state; 777 2621 llai1 struct sdev_node *dv = NULL; 778 2621 llai1 779 2621 llai1 ASSERT(state != SDEV_ZOMBIE); 780 2621 llai1 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 781 2621 llai1 782 2621 llai1 if (*newdv) { 783 2621 llai1 dv = *newdv; 784 2621 llai1 } else { 785 2621 llai1 /* allocate and initialize a sdev_node */ 786 2621 llai1 if (ddv->sdev_state == SDEV_ZOMBIE) { 787 2621 llai1 sdcmn_err9(("sdev_mknode: parent %s ZOMBIEd\n", 788 2621 llai1 ddv->sdev_path)); 789 2621 llai1 return (ENOENT); 790 2621 llai1 } 791 2621 llai1 792 2621 llai1 error = sdev_nodeinit(ddv, nm, &dv, vap); 793 2621 llai1 if (error != 0) { 794 2621 llai1 sdcmn_err9(("sdev_mknode: error %d," 795 2621 llai1 " name %s can not be initialized\n", 796 2621 llai1 error, nm)); 797 6335 jg return (error); 798 2621 llai1 } 799 2621 llai1 ASSERT(dv); 800 2621 llai1 801 2621 llai1 /* insert into the directory cache */ 802 2621 llai1 error = sdev_cache_update(ddv, &dv, nm, SDEV_CACHE_ADD); 803 2621 llai1 if (error) { 804 2621 llai1 sdcmn_err9(("sdev_mknode: node %s can not" 805 2621 llai1 " be added into directory cache\n", nm)); 806 2621 llai1 return (ENOENT); 807 2621 llai1 } 808 2621 llai1 } 809 2621 llai1 810 2621 llai1 ASSERT(dv); 811 2621 llai1 node_state = dv->sdev_state; 812 2621 llai1 ASSERT(node_state != SDEV_ZOMBIE); 813 2621 llai1 814 2621 llai1 if (state == SDEV_READY) { 815 2621 llai1 switch (node_state) { 816 2621 llai1 case SDEV_INIT: 817 2621 llai1 error = sdev_nodeready(dv, vap, avp, args, cred); 818 2621 llai1 if (error) { 819 2621 llai1 sdcmn_err9(("sdev_mknode: node %s can NOT" 820 2621 llai1 " be transitioned into READY state, " 821 2621 llai1 "error %d\n", nm, error)); 822 2621 llai1 } 823 2621 llai1 break; 824 2621 llai1 case SDEV_READY: 825 2621 llai1 /* 826 2621 llai1 * Do some sanity checking to make sure 827 2621 llai1 * the existing sdev_node is what has been 828 2621 llai1 * asked for. 829 2621 llai1 */ 830 2621 llai1 error = sdev_node_check(dv, vap, args); 831 2621 llai1 break; 832 2621 llai1 default: 833 2621 llai1 break; 834 2621 llai1 } 835 2621 llai1 } 836 2621 llai1 837 2621 llai1 if (!error) { 838 2621 llai1 *newdv = dv; 839 2621 llai1 ASSERT((*newdv)->sdev_state != SDEV_ZOMBIE); 840 2621 llai1 } else { 841 2621 llai1 SDEV_SIMPLE_RELE(dv); 842 2621 llai1 *newdv = NULL; 843 2621 llai1 } 844 2621 llai1 845 2621 llai1 return (error); 846 2621 llai1 } 847 2621 llai1 848 2621 llai1 /* 849 6335 jg * convenient wrapper to change vp's ATIME, CTIME and MTIME 850 2621 llai1 */ 851 2621 llai1 void 852 2621 llai1 sdev_update_timestamps(struct vnode *vp, cred_t *cred, uint_t mask) 853 2621 llai1 { 854 2621 llai1 struct vattr attr; 855 2621 llai1 timestruc_t now; 856 2621 llai1 int err; 857 2621 llai1 858 2621 llai1 ASSERT(vp); 859 2621 llai1 gethrestime(&now); 860 2621 llai1 if (mask & AT_CTIME) 861 2621 llai1 attr.va_ctime = now; 862 2621 llai1 if (mask & AT_MTIME) 863 2621 llai1 attr.va_mtime = now; 864 2621 llai1 if (mask & AT_ATIME) 865 2621 llai1 attr.va_atime = now; 866 2621 llai1 867 2621 llai1 attr.va_mask = (mask & AT_TIMES); 868 2621 llai1 err = VOP_SETATTR(vp, &attr, 0, cred, NULL); 869 2621 llai1 if (err && (err != EROFS)) { 870 2621 llai1 sdcmn_err(("update timestamps error %d\n", err)); 871 2621 llai1 } 872 2621 llai1 } 873 2621 llai1 874 2621 llai1 /* 875 2621 llai1 * the backing store vnode is released here 876 2621 llai1 */ 877 2621 llai1 /*ARGSUSED1*/ 878 2621 llai1 void 879 2621 llai1 sdev_nodedestroy(struct sdev_node *dv, uint_t flags) 880 2621 llai1 { 881 2621 llai1 /* no references */ 882 2621 llai1 ASSERT(dv->sdev_nlink == 0); 883 2621 llai1 884 2621 llai1 if (dv->sdev_attrvp != NULLVP) { 885 2621 llai1 VN_RELE(dv->sdev_attrvp); 886 2621 llai1 /* 887 2621 llai1 * reset the attrvp so that no more 888 2621 llai1 * references can be made on this already 889 2621 llai1 * vn_rele() vnode 890 2621 llai1 */ 891 2621 llai1 dv->sdev_attrvp = NULLVP; 892 2621 llai1 } 893 2621 llai1 894 2621 llai1 if (dv->sdev_attr != NULL) { 895 2621 llai1 kmem_free(dv->sdev_attr, sizeof (struct vattr)); 896 2621 llai1 dv->sdev_attr = NULL; 897 2621 llai1 } 898 2621 llai1 899 2621 llai1 if (dv->sdev_name != NULL) { 900 2621 llai1 kmem_free(dv->sdev_name, dv->sdev_namelen + 1); 901 2621 llai1 dv->sdev_name = NULL; 902 2621 llai1 } 903 2621 llai1 904 2621 llai1 if (dv->sdev_symlink != NULL) { 905 2621 llai1 kmem_free(dv->sdev_symlink, strlen(dv->sdev_symlink) + 1); 906 2621 llai1 dv->sdev_symlink = NULL; 907 2621 llai1 } 908 2621 llai1 909 2621 llai1 if (dv->sdev_path) { 910 2621 llai1 kmem_free(dv->sdev_path, strlen(dv->sdev_path) + 1); 911 2621 llai1 dv->sdev_path = NULL; 912 2621 llai1 } 913 2621 llai1 914 2621 llai1 if (!SDEV_IS_GLOBAL(dv)) 915 2621 llai1 sdev_prof_free(dv); 916 2621 llai1 917 6260 jg if (SDEVTOV(dv)->v_type == VDIR) { 918 6260 jg ASSERT(SDEV_FIRST_ENTRY(dv) == NULL); 919 6260 jg avl_destroy(&dv->sdev_entries); 920 6260 jg } 921 6260 jg 922 2621 llai1 mutex_destroy(&dv->sdev_lookup_lock); 923 2621 llai1 cv_destroy(&dv->sdev_lookup_cv); 924 2621 llai1 925 2621 llai1 /* return node to initial state as per constructor */ 926 2621 llai1 (void) memset((void *)&dv->sdev_instance_data, 0, 927 2621 llai1 sizeof (dv->sdev_instance_data)); 928 2621 llai1 vn_invalid(SDEVTOV(dv)); 929 2621 llai1 kmem_cache_free(sdev_node_cache, dv); 930 2621 llai1 } 931 2621 llai1 932 2621 llai1 /* 933 2621 llai1 * DIRECTORY CACHE lookup 934 2621 llai1 */ 935 2621 llai1 struct sdev_node * 936 2621 llai1 sdev_findbyname(struct sdev_node *ddv, char *nm) 937 2621 llai1 { 938 2621 llai1 struct sdev_node *dv; 939 6260 jg struct sdev_node dvtmp; 940 6260 jg avl_index_t where; 941 2621 llai1 942 2621 llai1 ASSERT(RW_LOCK_HELD(&ddv->sdev_contents)); 943 2621 llai1 944 6260 jg dvtmp.sdev_name = nm; 945 6260 jg dv = avl_find(&ddv->sdev_entries, &dvtmp, &where); 946 6260 jg if (dv) { 947 6260 jg ASSERT(dv->sdev_dotdot == ddv); 948 6260 jg ASSERT(strcmp(dv->sdev_name, nm) == 0); 949 6347 jg SDEV_HOLD(dv); 950 6347 jg return (dv); 951 2621 llai1 } 952 2621 llai1 return (NULL); 953 2621 llai1 } 954 2621 llai1 955 2621 llai1 /* 956 2621 llai1 * Inserts a new sdev_node in a parent directory 957 2621 llai1 */ 958 2621 llai1 void 959 2621 llai1 sdev_direnter(struct sdev_node *ddv, struct sdev_node *dv) 960 2621 llai1 { 961 6260 jg avl_index_t where; 962 6260 jg 963 2621 llai1 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 964 2621 llai1 ASSERT(SDEVTOV(ddv)->v_type == VDIR); 965 2621 llai1 ASSERT(ddv->sdev_nlink >= 2); 966 2621 llai1 ASSERT(dv->sdev_nlink == 0); 967 2621 llai1 968 2621 llai1 dv->sdev_dotdot = ddv; 969 6260 jg VERIFY(avl_find(&ddv->sdev_entries, dv, &where) == NULL); 970 6260 jg avl_insert(&ddv->sdev_entries, dv, where); 971 2621 llai1 ddv->sdev_nlink++; 972 2621 llai1 } 973 2621 llai1 974 2621 llai1 /* 975 2621 llai1 * The following check is needed because while sdev_nodes are linked 976 2621 llai1 * in SDEV_INIT state, they have their link counts incremented only 977 2621 llai1 * in SDEV_READY state. 978 2621 llai1 */ 979 2621 llai1 static void 980 2621 llai1 decr_link(struct sdev_node *dv) 981 2621 llai1 { 982 2621 llai1 if (dv->sdev_state != SDEV_INIT) 983 2621 llai1 dv->sdev_nlink--; 984 2621 llai1 else 985 2621 llai1 ASSERT(dv->sdev_nlink == 0); 986 2621 llai1 } 987 2621 llai1 988 2621 llai1 /* 989 2621 llai1 * Delete an existing dv from directory cache 990 2621 llai1 * 991 2621 llai1 * In the case of a node is still held by non-zero reference count, 992 2621 llai1 * the node is put into ZOMBIE state. Once the reference count 993 2621 llai1 * reaches "0", the node is unlinked and destroyed, 994 2621 llai1 * in sdev_inactive(). 995 2621 llai1 */ 996 2621 llai1 static int 997 2621 llai1 sdev_dirdelete(struct sdev_node *ddv, struct sdev_node *dv) 998 2621 llai1 { 999 2621 llai1 struct vnode *vp; 1000 2621 llai1 1001 2621 llai1 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1002 2621 llai1 1003 2621 llai1 vp = SDEVTOV(dv); 1004 2621 llai1 mutex_enter(&vp->v_lock); 1005 2621 llai1 1006 2621 llai1 /* dv is held still */ 1007 2621 llai1 if (vp->v_count > 1) { 1008 2621 llai1 rw_enter(&dv->sdev_contents, RW_WRITER); 1009 2621 llai1 if (dv->sdev_state == SDEV_READY) { 1010 2621 llai1 sdcmn_err9(( 1011 10588 Eric "sdev_dirdelete: node %s busy with count %d\n", 1012 2621 llai1 dv->sdev_name, vp->v_count)); 1013 2621 llai1 dv->sdev_state = SDEV_ZOMBIE; 1014 2621 llai1 } 1015 2621 llai1 rw_exit(&dv->sdev_contents); 1016 2621 llai1 --vp->v_count; 1017 2621 llai1 mutex_exit(&vp->v_lock); 1018 2621 llai1 return (EBUSY); 1019 2621 llai1 } 1020 2621 llai1 ASSERT(vp->v_count == 1); 1021 2621 llai1 1022 2621 llai1 /* unlink from the memory cache */ 1023 2621 llai1 ddv->sdev_nlink--; /* .. to above */ 1024 2621 llai1 if (vp->v_type == VDIR) { 1025 2621 llai1 decr_link(dv); /* . to self */ 1026 2621 llai1 } 1027 2621 llai1 1028 6260 jg avl_remove(&ddv->sdev_entries, dv); 1029 2621 llai1 decr_link(dv); /* name, back to zero */ 1030 2621 llai1 vp->v_count--; 1031 2621 llai1 mutex_exit(&vp->v_lock); 1032 2621 llai1 1033 2621 llai1 /* destroy the node */ 1034 2621 llai1 sdev_nodedestroy(dv, 0); 1035 2621 llai1 return (0); 1036 2621 llai1 } 1037 2621 llai1 1038 2621 llai1 /* 1039 2621 llai1 * check if the source is in the path of the target 1040 2621 llai1 * 1041 2621 llai1 * source and target are different 1042 2621 llai1 */ 1043 2621 llai1 /*ARGSUSED2*/ 1044 2621 llai1 static int 1045 2621 llai1 sdev_checkpath(struct sdev_node *sdv, struct sdev_node *tdv, struct cred *cred) 1046 2621 llai1 { 1047 2621 llai1 int error = 0; 1048 2621 llai1 struct sdev_node *dotdot, *dir; 1049 2621 llai1 1050 2621 llai1 dotdot = tdv->sdev_dotdot; 1051 2621 llai1 ASSERT(dotdot); 1052 2621 llai1 1053 2621 llai1 /* fs root */ 1054 2621 llai1 if (dotdot == tdv) { 1055 2621 llai1 return (0); 1056 2621 llai1 } 1057 2621 llai1 1058 2621 llai1 for (;;) { 1059 2621 llai1 /* 1060 2621 llai1 * avoid error cases like 1061 2621 llai1 * mv a a/b 1062 2621 llai1 * mv a a/b/c 1063 2621 llai1 * etc. 1064 2621 llai1 */ 1065 2621 llai1 if (dotdot == sdv) { 1066 2621 llai1 error = EINVAL; 1067 2621 llai1 break; 1068 2621 llai1 } 1069 2621 llai1 1070 2621 llai1 dir = dotdot; 1071 2621 llai1 dotdot = dir->sdev_dotdot; 1072 2621 llai1 1073 2621 llai1 /* done checking because root is reached */ 1074 2621 llai1 if (dir == dotdot) { 1075 2621 llai1 break; 1076 2621 llai1 } 1077 2621 llai1 } 1078 2621 llai1 return (error); 1079 2621 llai1 } 1080 2621 llai1 1081 2621 llai1 int 1082 2621 llai1 sdev_rnmnode(struct sdev_node *oddv, struct sdev_node *odv, 1083 2621 llai1 struct sdev_node *nddv, struct sdev_node **ndvp, char *nnm, 1084 2621 llai1 struct cred *cred) 1085 2621 llai1 { 1086 2621 llai1 int error = 0; 1087 2621 llai1 struct vnode *ovp = SDEVTOV(odv); 1088 2621 llai1 struct vnode *nvp; 1089 2621 llai1 struct vattr vattr; 1090 2621 llai1 int doingdir = (ovp->v_type == VDIR); 1091 2621 llai1 char *link = NULL; 1092 2729 llai1 int samedir = (oddv == nddv) ? 1 : 0; 1093 2729 llai1 int bkstore = 0; 1094 2729 llai1 struct sdev_node *idv = NULL; 1095 2729 llai1 struct sdev_node *ndv = NULL; 1096 2729 llai1 timestruc_t now; 1097 2729 llai1 1098 2729 llai1 vattr.va_mask = AT_MODE|AT_UID|AT_GID; 1099 5331 amw error = VOP_GETATTR(ovp, &vattr, 0, cred, NULL); 1100 2729 llai1 if (error) 1101 2729 llai1 return (error); 1102 2729 llai1 1103 2729 llai1 if (!samedir) 1104 2729 llai1 rw_enter(&oddv->sdev_contents, RW_WRITER); 1105 2729 llai1 rw_enter(&nddv->sdev_contents, RW_WRITER); 1106 2729 llai1 1107 2729 llai1 /* 1108 2729 llai1 * the source may have been deleted by another thread before 1109 2729 llai1 * we gets here. 1110 2729 llai1 */ 1111 2729 llai1 if (odv->sdev_state != SDEV_READY) { 1112 2729 llai1 error = ENOENT; 1113 2729 llai1 goto err_out; 1114 2729 llai1 } 1115 2729 llai1 1116 2729 llai1 if (doingdir && (odv == nddv)) { 1117 2729 llai1 error = EINVAL; 1118 2729 llai1 goto err_out; 1119 2729 llai1 } 1120 2621 llai1 1121 2621 llai1 /* 1122 2621 llai1 * If renaming a directory, and the parents are different (".." must be 1123 2621 llai1 * changed) then the source dir must not be in the dir hierarchy above 1124 2621 llai1 * the target since it would orphan everything below the source dir. 1125 2621 llai1 */ 1126 2621 llai1 if (doingdir && (oddv != nddv)) { 1127 2621 llai1 error = sdev_checkpath(odv, nddv, cred); 1128 2621 llai1 if (error) 1129 2729 llai1 goto err_out; 1130 2621 llai1 } 1131 2621 llai1 1132 2729 llai1 /* destination existing */ 1133 2621 llai1 if (*ndvp) { 1134 2621 llai1 nvp = SDEVTOV(*ndvp); 1135 2621 llai1 ASSERT(nvp); 1136 2621 llai1 1137 2621 llai1 /* handling renaming to itself */ 1138 2729 llai1 if (odv == *ndvp) { 1139 2729 llai1 error = 0; 1140 2729 llai1 goto err_out; 1141 2729 llai1 } 1142 2621 llai1 1143 2729 llai1 if (nvp->v_type == VDIR) { 1144 2729 llai1 if (!doingdir) { 1145 2729 llai1 error = EISDIR; 1146 2729 llai1 goto err_out; 1147 2729 llai1 } 1148 2729 llai1 1149 2729 llai1 if (vn_vfswlock(nvp)) { 1150 2729 llai1 error = EBUSY; 1151 2729 llai1 goto err_out; 1152 2729 llai1 } 1153 2729 llai1 1154 2729 llai1 if (vn_mountedvfs(nvp) != NULL) { 1155 2729 llai1 vn_vfsunlock(nvp); 1156 2729 llai1 error = EBUSY; 1157 2729 llai1 goto err_out; 1158 2729 llai1 } 1159 2729 llai1 1160 2729 llai1 /* in case dir1 exists in dir2 and "mv dir1 dir2" */ 1161 2729 llai1 if ((*ndvp)->sdev_nlink > 2) { 1162 2729 llai1 vn_vfsunlock(nvp); 1163 2729 llai1 error = EEXIST; 1164 2729 llai1 goto err_out; 1165 2729 llai1 } 1166 2729 llai1 vn_vfsunlock(nvp); 1167 2729 llai1 1168 2729 llai1 (void) sdev_dirdelete(nddv, *ndvp); 1169 2729 llai1 *ndvp = NULL; 1170 6335 jg ASSERT(nddv->sdev_attrvp); 1171 2729 llai1 error = VOP_RMDIR(nddv->sdev_attrvp, nnm, 1172 6065 cth nddv->sdev_attrvp, cred, NULL, 0); 1173 2729 llai1 if (error) 1174 2729 llai1 goto err_out; 1175 2729 llai1 } else { 1176 2729 llai1 if (doingdir) { 1177 2729 llai1 error = ENOTDIR; 1178 2729 llai1 goto err_out; 1179 2729 llai1 } 1180 2729 llai1 1181 2729 llai1 if (SDEV_IS_PERSIST((*ndvp))) { 1182 2729 llai1 bkstore = 1; 1183 2729 llai1 } 1184 2621 llai1 1185 2621 llai1 /* 1186 2729 llai1 * get rid of the node from the directory cache 1187 2729 llai1 * note, in case EBUSY is returned, the ZOMBIE 1188 2729 llai1 * node is taken care in sdev_mknode. 1189 2621 llai1 */ 1190 2729 llai1 (void) sdev_dirdelete(nddv, *ndvp); 1191 2729 llai1 *ndvp = NULL; 1192 2729 llai1 if (bkstore) { 1193 6335 jg ASSERT(nddv->sdev_attrvp); 1194 2729 llai1 error = VOP_REMOVE(nddv->sdev_attrvp, 1195 5331 amw nnm, cred, NULL, 0); 1196 2729 llai1 if (error) 1197 6065 cth goto err_out; 1198 2621 llai1 } 1199 2621 llai1 } 1200 2621 llai1 } 1201 2621 llai1 1202 2621 llai1 /* fix the source for a symlink */ 1203 2621 llai1 if (vattr.va_type == VLNK) { 1204 2621 llai1 if (odv->sdev_symlink == NULL) { 1205 2621 llai1 error = sdev_follow_link(odv); 1206 2729 llai1 if (error) { 1207 2729 llai1 error = ENOENT; 1208 2729 llai1 goto err_out; 1209 2729 llai1 } 1210 2621 llai1 } 1211 2621 llai1 ASSERT(odv->sdev_symlink); 1212 2621 llai1 link = i_ddi_strdup(odv->sdev_symlink, KM_SLEEP); 1213 2621 llai1 } 1214 2621 llai1 1215 2729 llai1 /* 1216 2729 llai1 * make a fresh node from the source attrs 1217 2729 llai1 */ 1218 2729 llai1 ASSERT(RW_WRITE_HELD(&nddv->sdev_contents)); 1219 2729 llai1 error = sdev_mknode(nddv, nnm, ndvp, &vattr, 1220 2729 llai1 NULL, (void *)link, cred, SDEV_READY); 1221 2621 llai1 1222 2621 llai1 if (link) 1223 2621 llai1 kmem_free(link, strlen(link) + 1); 1224 2621 llai1 1225 2729 llai1 if (error) 1226 2729 llai1 goto err_out; 1227 2729 llai1 ASSERT(*ndvp); 1228 2729 llai1 ASSERT((*ndvp)->sdev_state == SDEV_READY); 1229 2729 llai1 1230 2729 llai1 /* move dir contents */ 1231 2729 llai1 if (doingdir) { 1232 6260 jg for (idv = SDEV_FIRST_ENTRY(odv); idv; 1233 6260 jg idv = SDEV_NEXT_ENTRY(odv, idv)) { 1234 2729 llai1 error = sdev_rnmnode(odv, idv, 1235 2729 llai1 (struct sdev_node *)(*ndvp), &ndv, 1236 2729 llai1 idv->sdev_name, cred); 1237 2729 llai1 if (error) 1238 2729 llai1 goto err_out; 1239 2729 llai1 ndv = NULL; 1240 2729 llai1 } 1241 2729 llai1 } 1242 2729 llai1 1243 2729 llai1 if ((*ndvp)->sdev_attrvp) { 1244 2729 llai1 sdev_update_timestamps((*ndvp)->sdev_attrvp, kcred, 1245 2729 llai1 AT_CTIME|AT_ATIME); 1246 2729 llai1 } else { 1247 2729 llai1 ASSERT((*ndvp)->sdev_attr); 1248 2729 llai1 gethrestime(&now); 1249 2729 llai1 (*ndvp)->sdev_attr->va_ctime = now; 1250 2729 llai1 (*ndvp)->sdev_attr->va_atime = now; 1251 2729 llai1 } 1252 2729 llai1 1253 2729 llai1 if (nddv->sdev_attrvp) { 1254 2729 llai1 sdev_update_timestamps(nddv->sdev_attrvp, kcred, 1255 2729 llai1 AT_MTIME|AT_ATIME); 1256 2729 llai1 } else { 1257 2729 llai1 ASSERT(nddv->sdev_attr); 1258 2729 llai1 gethrestime(&now); 1259 2729 llai1 nddv->sdev_attr->va_mtime = now; 1260 2729 llai1 nddv->sdev_attr->va_atime = now; 1261 2729 llai1 } 1262 2729 llai1 rw_exit(&nddv->sdev_contents); 1263 2729 llai1 if (!samedir) 1264 2729 llai1 rw_exit(&oddv->sdev_contents); 1265 2729 llai1 1266 2621 llai1 SDEV_RELE(*ndvp); 1267 2729 llai1 return (error); 1268 2729 llai1 1269 2729 llai1 err_out: 1270 2729 llai1 rw_exit(&nddv->sdev_contents); 1271 2729 llai1 if (!samedir) 1272 2729 llai1 rw_exit(&oddv->sdev_contents); 1273 2729 llai1 return (error); 1274 2621 llai1 } 1275 2621 llai1 1276 2621 llai1 /* 1277 2621 llai1 * Merge sdev_node specific information into an attribute structure. 1278 2621 llai1 * 1279 2621 llai1 * note: sdev_node is not locked here 1280 2621 llai1 */ 1281 2621 llai1 void 1282 2621 llai1 sdev_vattr_merge(struct sdev_node *dv, struct vattr *vap) 1283 2621 llai1 { 1284 2621 llai1 struct vnode *vp = SDEVTOV(dv); 1285 2621 llai1 1286 2621 llai1 vap->va_nlink = dv->sdev_nlink; 1287 2621 llai1 vap->va_nodeid = dv->sdev_ino; 1288 2621 llai1 vap->va_fsid = SDEVTOV(dv->sdev_dotdot)->v_rdev; 1289 2621 llai1 vap->va_type = vp->v_type; 1290 2621 llai1 1291 2621 llai1 if (vp->v_type == VDIR) { 1292 2621 llai1 vap->va_rdev = 0; 1293 2621 llai1 vap->va_fsid = vp->v_rdev; 1294 2621 llai1 } else if (vp->v_type == VLNK) { 1295 2621 llai1 vap->va_rdev = 0; 1296 2621 llai1 vap->va_mode &= ~S_IFMT; 1297 2621 llai1 vap->va_mode |= S_IFLNK; 1298 2621 llai1 } else if ((vp->v_type == VCHR) || (vp->v_type == VBLK)) { 1299 2621 llai1 vap->va_rdev = vp->v_rdev; 1300 2621 llai1 vap->va_mode &= ~S_IFMT; 1301 2621 llai1 if (vap->va_type == VCHR) 1302 2621 llai1 vap->va_mode |= S_IFCHR; 1303 2621 llai1 else 1304 2621 llai1 vap->va_mode |= S_IFBLK; 1305 2621 llai1 } else { 1306 2621 llai1 vap->va_rdev = 0; 1307 2621 llai1 } 1308 2621 llai1 } 1309 2621 llai1 1310 10588 Eric struct vattr * 1311 2621 llai1 sdev_getdefault_attr(enum vtype type) 1312 2621 llai1 { 1313 2621 llai1 if (type == VDIR) 1314 2621 llai1 return (&sdev_vattr_dir); 1315 2621 llai1 else if (type == VCHR) 1316 2621 llai1 return (&sdev_vattr_chr); 1317 2621 llai1 else if (type == VBLK) 1318 2621 llai1 return (&sdev_vattr_blk); 1319 2621 llai1 else if (type == VLNK) 1320 2621 llai1 return (&sdev_vattr_lnk); 1321 2621 llai1 else 1322 2621 llai1 return (NULL); 1323 2621 llai1 } 1324 2621 llai1 int 1325 2621 llai1 sdev_to_vp(struct sdev_node *dv, struct vnode **vpp) 1326 2621 llai1 { 1327 2621 llai1 int rv = 0; 1328 2621 llai1 struct vnode *vp = SDEVTOV(dv); 1329 2621 llai1 1330 2621 llai1 switch (vp->v_type) { 1331 2621 llai1 case VCHR: 1332 2621 llai1 case VBLK: 1333 2621 llai1 /* 1334 2621 llai1 * If vnode is a device, return special vnode instead 1335 2621 llai1 * (though it knows all about -us- via sp->s_realvp) 1336 2621 llai1 */ 1337 2621 llai1 *vpp = specvp(vp, vp->v_rdev, vp->v_type, kcred); 1338 2621 llai1 VN_RELE(vp); 1339 2621 llai1 if (*vpp == NULLVP) 1340 2621 llai1 rv = ENOSYS; 1341 2621 llai1 break; 1342 2621 llai1 default: /* most types are returned as is */ 1343 2621 llai1 *vpp = vp; 1344 2621 llai1 break; 1345 2621 llai1 } 1346 2621 llai1 return (rv); 1347 2621 llai1 } 1348 2621 llai1 1349 2621 llai1 /* 1350 2621 llai1 * junction between devname and root file system, e.g. ufs 1351 2621 llai1 */ 1352 2621 llai1 int 1353 2621 llai1 devname_backstore_lookup(struct sdev_node *ddv, char *nm, struct vnode **rvp) 1354 2621 llai1 { 1355 2621 llai1 struct vnode *rdvp = ddv->sdev_attrvp; 1356 2621 llai1 int rval = 0; 1357 2621 llai1 1358 2621 llai1 ASSERT(rdvp); 1359 2621 llai1 1360 5331 amw rval = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, kcred, NULL, NULL, 1361 5331 amw NULL); 1362 2621 llai1 return (rval); 1363 2621 llai1 } 1364 2621 llai1 1365 2621 llai1 static int 1366 2621 llai1 sdev_filldir_from_store(struct sdev_node *ddv, int dlen, struct cred *cred) 1367 2621 llai1 { 1368 2621 llai1 struct sdev_node *dv = NULL; 1369 2621 llai1 char *nm; 1370 2621 llai1 struct vnode *dirvp; 1371 2621 llai1 int error; 1372 2621 llai1 vnode_t *vp; 1373 2621 llai1 int eof; 1374 2621 llai1 struct iovec iov; 1375 2621 llai1 struct uio uio; 1376 2621 llai1 struct dirent64 *dp; 1377 2621 llai1 dirent64_t *dbuf; 1378 2621 llai1 size_t dbuflen; 1379 2621 llai1 struct vattr vattr; 1380 2621 llai1 char *link = NULL; 1381 2621 llai1 1382 2621 llai1 if (ddv->sdev_attrvp == NULL) 1383 2621 llai1 return (0); 1384 2621 llai1 if (!(ddv->sdev_flags & SDEV_BUILD)) 1385 2621 llai1 return (0); 1386 2621 llai1 1387 2621 llai1 dirvp = ddv->sdev_attrvp; 1388 2621 llai1 VN_HOLD(dirvp); 1389 2621 llai1 dbuf = kmem_zalloc(dlen, KM_SLEEP); 1390 2621 llai1 1391 2621 llai1 uio.uio_iov = &iov; 1392 2621 llai1 uio.uio_iovcnt = 1; 1393 2621 llai1 uio.uio_segflg = UIO_SYSSPACE; 1394 2621 llai1 uio.uio_fmode = 0; 1395 2621 llai1 uio.uio_extflg = UIO_COPY_CACHED; 1396 2621 llai1 uio.uio_loffset = 0; 1397 2621 llai1 uio.uio_llimit = MAXOFFSET_T; 1398 2621 llai1 1399 2621 llai1 eof = 0; 1400 2621 llai1 error = 0; 1401 2621 llai1 while (!error && !eof) { 1402 2621 llai1 uio.uio_resid = dlen; 1403 2621 llai1 iov.iov_base = (char *)dbuf; 1404 2621 llai1 iov.iov_len = dlen; 1405 2621 llai1 (void) VOP_RWLOCK(dirvp, V_WRITELOCK_FALSE, NULL); 1406 5331 amw error = VOP_READDIR(dirvp, &uio, kcred, &eof, NULL, 0); 1407 2621 llai1 VOP_RWUNLOCK(dirvp, V_WRITELOCK_FALSE, NULL); 1408 2621 llai1 1409 2621 llai1 dbuflen = dlen - uio.uio_resid; 1410 2621 llai1 if (error || dbuflen == 0) 1411 2621 llai1 break; 1412 2621 llai1 1413 10588 Eric if (!(ddv->sdev_flags & SDEV_BUILD)) 1414 2621 llai1 break; 1415 2621 llai1 1416 2621 llai1 for (dp = dbuf; ((intptr_t)dp < 1417 2621 llai1 (intptr_t)dbuf + dbuflen); 1418 2621 llai1 dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen)) { 1419 2621 llai1 nm = dp->d_name; 1420 2621 llai1 1421 2621 llai1 if (strcmp(nm, ".") == 0 || 1422 2621 llai1 strcmp(nm, "..") == 0) 1423 2621 llai1 continue; 1424 2621 llai1 1425 2621 llai1 vp = NULLVP; 1426 2621 llai1 dv = sdev_cache_lookup(ddv, nm); 1427 2621 llai1 if (dv) { 1428 2621 llai1 if (dv->sdev_state != SDEV_ZOMBIE) { 1429 2621 llai1 SDEV_SIMPLE_RELE(dv); 1430 2621 llai1 } else { 1431 2621 llai1 /* 1432 2621 llai1 * A ZOMBIE node may not have been 1433 2621 llai1 * cleaned up from the backing store, 1434 2621 llai1 * bypass this entry in this case, 1435 2621 llai1 * and clean it up from the directory 1436 2621 llai1 * cache if this is the last call. 1437 2621 llai1 */ 1438 2621 llai1 (void) sdev_dirdelete(ddv, dv); 1439 2621 llai1 } 1440 2621 llai1 continue; 1441 2621 llai1 } 1442 2621 llai1 1443 2621 llai1 /* refill the cache if not already */ 1444 2621 llai1 error = devname_backstore_lookup(ddv, nm, &vp); 1445 2621 llai1 if (error) 1446 2621 llai1 continue; 1447 2621 llai1 1448 2621 llai1 vattr.va_mask = AT_MODE|AT_UID|AT_GID; 1449 5331 amw error = VOP_GETATTR(vp, &vattr, 0, cred, NULL); 1450 2621 llai1 if (error) 1451 2621 llai1 continue; 1452 2621 llai1 1453 2621 llai1 if (vattr.va_type == VLNK) { 1454 2621 llai1 error = sdev_getlink(vp, &link); 1455 2621 llai1 if (error) { 1456 2621 llai1 continue; 1457 2621 llai1 } 1458 2621 llai1 ASSERT(link != NULL); 1459 2621 llai1 } 1460 2621 llai1 1461 2621 llai1 if (!rw_tryupgrade(&ddv->sdev_contents)) { 1462 2621 llai1 rw_exit(&ddv->sdev_contents); 1463 2621 llai1 rw_enter(&ddv->sdev_contents, RW_WRITER); 1464 2621 llai1 } 1465 2621 llai1 error = sdev_mknode(ddv, nm, &dv, &vattr, vp, link, 1466 2621 llai1 cred, SDEV_READY); 1467 2621 llai1 rw_downgrade(&ddv->sdev_contents); 1468 2621 llai1 1469 2621 llai1 if (link != NULL) { 1470 2621 llai1 kmem_free(link, strlen(link) + 1); 1471 2621 llai1 link = NULL; 1472 2621 llai1 } 1473 2621 llai1 1474 2621 llai1 if (!error) { 1475 2621 llai1 ASSERT(dv); 1476 2621 llai1 ASSERT(dv->sdev_state != SDEV_ZOMBIE); 1477 2621 llai1 SDEV_SIMPLE_RELE(dv); 1478 2621 llai1 } 1479 2621 llai1 vp = NULL; 1480 2621 llai1 dv = NULL; 1481 2621 llai1 } 1482 2621 llai1 } 1483 2621 llai1 1484 2621 llai1 done: 1485 2621 llai1 VN_RELE(dirvp); 1486 2621 llai1 kmem_free(dbuf, dlen); 1487 2621 llai1 1488 2621 llai1 return (error); 1489 2621 llai1 } 1490 2621 llai1 1491 3843 jg void 1492 2621 llai1 sdev_filldir_dynamic(struct sdev_node *ddv) 1493 2621 llai1 { 1494 2621 llai1 int error; 1495 2621 llai1 int i; 1496 2621 llai1 struct vattr *vap; 1497 2621 llai1 char *nm = NULL; 1498 2621 llai1 struct sdev_node *dv = NULL; 1499 2621 llai1 1500 3843 jg ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1501 3843 jg ASSERT((ddv->sdev_flags & SDEV_BUILD)); 1502 2621 llai1 1503 2621 llai1 vap = sdev_getdefault_attr(VDIR); 1504 10588 Eric gethrestime(&vap->va_atime); 1505 10588 Eric vap->va_mtime = vap->va_atime; 1506 10588 Eric vap->va_ctime = vap->va_atime; 1507 2621 llai1 for (i = 0; vtab[i].vt_name != NULL; i++) { 1508 2621 llai1 nm = vtab[i].vt_name; 1509 2621 llai1 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1510 3843 jg dv = NULL; 1511 2621 llai1 error = sdev_mknode(ddv, nm, &dv, vap, NULL, 1512 2621 llai1 NULL, kcred, SDEV_READY); 1513 3843 jg if (error) { 1514 3843 jg cmn_err(CE_WARN, "%s/%s: error %d\n", 1515 3843 jg ddv->sdev_name, nm, error); 1516 3843 jg } else { 1517 3843 jg ASSERT(dv); 1518 3843 jg ASSERT(dv->sdev_state != SDEV_ZOMBIE); 1519 3843 jg SDEV_SIMPLE_RELE(dv); 1520 3843 jg } 1521 2621 llai1 } 1522 2621 llai1 } 1523 2621 llai1 1524 2621 llai1 /* 1525 2621 llai1 * Creating a backing store entry based on sdev_attr. 1526 2621 llai1 * This is called either as part of node creation in a persistent directory 1527 2621 llai1 * or from setattr/setsecattr to persist access attributes across reboot. 1528 2621 llai1 */ 1529 2621 llai1 int 1530 2621 llai1 sdev_shadow_node(struct sdev_node *dv, struct cred *cred) 1531 2621 llai1 { 1532 2621 llai1 int error = 0; 1533 2621 llai1 struct vnode *dvp = SDEVTOV(dv->sdev_dotdot); 1534 2621 llai1 struct vnode *rdvp = VTOSDEV(dvp)->sdev_attrvp; 1535 2621 llai1 struct vattr *vap = dv->sdev_attr; 1536 2621 llai1 char *nm = dv->sdev_name; 1537 2621 llai1 struct vnode *tmpvp, **rvp = &tmpvp, *rrvp = NULL; 1538 2621 llai1 1539 2621 llai1 ASSERT(dv && dv->sdev_name && rdvp); 1540 2621 llai1 ASSERT(RW_WRITE_HELD(&dv->sdev_contents) && dv->sdev_attrvp == NULL); 1541 2621 llai1 1542 2621 llai1 lookup: 1543 2621 llai1 /* try to find it in the backing store */ 1544 5331 amw error = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, cred, NULL, NULL, 1545 5331 amw NULL); 1546 2621 llai1 if (error == 0) { 1547 5331 amw if (VOP_REALVP(*rvp, &rrvp, NULL) == 0) { 1548 2621 llai1 VN_HOLD(rrvp); 1549 2621 llai1 VN_RELE(*rvp); 1550 2621 llai1 *rvp = rrvp; 1551 2621 llai1 } 1552 2621 llai1 1553 2621 llai1 kmem_free(dv->sdev_attr, sizeof (vattr_t)); 1554 2621 llai1 dv->sdev_attr = NULL; 1555 2621 llai1 dv->sdev_attrvp = *rvp; 1556 2621 llai1 return (0); 1557 2621 llai1 } 1558 2621 llai1 1559 2621 llai1 /* let's try to persist the node */ 1560 2621 llai1 gethrestime(&vap->va_atime); 1561 2621 llai1 vap->va_mtime = vap->va_atime; 1562 2621 llai1 vap->va_ctime = vap->va_atime; 1563 2621 llai1 vap->va_mask |= AT_TYPE|AT_MODE; 1564 2621 llai1 switch (vap->va_type) { 1565 2621 llai1 case VDIR: 1566 5331 amw error = VOP_MKDIR(rdvp, nm, vap, rvp, cred, NULL, 0, NULL); 1567 2621 llai1 sdcmn_err9(("sdev_shadow_node: mkdir vp %p error %d\n", 1568 2621 llai1 (void *)(*rvp), error)); 1569 2621 llai1 break; 1570 2621 llai1 case VCHR: 1571 2621 llai1 case VBLK: 1572 2621 llai1 case VREG: 1573 2621 llai1 case VDOOR: 1574 2621 llai1 error = VOP_CREATE(rdvp, nm, vap, NONEXCL, VREAD|VWRITE, 1575 5331 amw rvp, cred, 0, NULL, NULL); 1576 2621 llai1 sdcmn_err9(("sdev_shadow_node: create vp %p, error %d\n", 1577 2621 llai1 (void *)(*rvp), error)); 1578 2621 llai1 if (!error) 1579 2621 llai1 VN_RELE(*rvp); 1580 2621 llai1 break; 1581 2621 llai1 case VLNK: 1582 2621 llai1 ASSERT(dv->sdev_symlink); 1583 5331 amw error = VOP_SYMLINK(rdvp, nm, vap, dv->sdev_symlink, cred, 1584 5331 amw NULL, 0); 1585 2621 llai1 sdcmn_err9(("sdev_shadow_node: create symlink error %d\n", 1586 2621 llai1 error)); 1587 2621 llai1 break; 1588 2621 llai1 default: 1589 2621 llai1 cmn_err(CE_PANIC, "dev: %s: sdev_shadow_node " 1590 2621 llai1 "create\n", nm); 1591 2621 llai1 /*NOTREACHED*/ 1592 2621 llai1 } 1593 2621 llai1 1594 2621 llai1 /* go back to lookup to factor out spec node and set attrvp */ 1595 2621 llai1 if (error == 0) 1596 2621 llai1 goto lookup; 1597 2621 llai1 1598 6335 jg sdcmn_err(("cannot persist %s - error %d\n", dv->sdev_path, error)); 1599 2621 llai1 return (error); 1600 2621 llai1 } 1601 2621 llai1 1602 2621 llai1 static int 1603 2621 llai1 sdev_cache_add(struct sdev_node *ddv, struct sdev_node **dv, char *nm) 1604 2621 llai1 { 1605 2621 llai1 int error = 0; 1606 2621 llai1 struct sdev_node *dup = NULL; 1607 2621 llai1 1608 2621 llai1 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1609 2621 llai1 if ((dup = sdev_findbyname(ddv, nm)) == NULL) { 1610 2621 llai1 sdev_direnter(ddv, *dv); 1611 2621 llai1 } else { 1612 2621 llai1 if (dup->sdev_state == SDEV_ZOMBIE) { 1613 2621 llai1 error = sdev_dirdelete(ddv, dup); 1614 2621 llai1 /* 1615 2621 llai1 * The ZOMBIE node is still hanging 1616 2621 llai1 * around with more than one reference counts. 1617 2621 llai1 * Fail the new node creation so that 1618 2621 llai1 * the directory cache won't have 1619 2621 llai1 * duplicate entries for the same named node 1620 2621 llai1 */ 1621 2621 llai1 if (error == EBUSY) { 1622 2621 llai1 SDEV_SIMPLE_RELE(*dv); 1623 2621 llai1 sdev_nodedestroy(*dv, 0); 1624 2621 llai1 *dv = NULL; 1625 2621 llai1 return (error); 1626 2621 llai1 } 1627 2621 llai1 sdev_direnter(ddv, *dv); 1628 2621 llai1 } else { 1629 2621 llai1 ASSERT((*dv)->sdev_state != SDEV_ZOMBIE); 1630 2621 llai1 SDEV_SIMPLE_RELE(*dv); 1631 2621 llai1 sdev_nodedestroy(*dv, 0); 1632 2621 llai1 *dv = dup; 1633 2621 llai1 } 1634 2621 llai1 } 1635 2621 llai1 1636 2621 llai1 return (0); 1637 2621 llai1 } 1638 2621 llai1 1639 2621 llai1 static int 1640 2621 llai1 sdev_cache_delete(struct sdev_node *ddv, struct sdev_node **dv) 1641 2621 llai1 { 1642 2621 llai1 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1643 2621 llai1 return (sdev_dirdelete(ddv, *dv)); 1644 2621 llai1 } 1645 2621 llai1 1646 2621 llai1 /* 1647 2621 llai1 * update the in-core directory cache 1648 2621 llai1 */ 1649 2621 llai1 int 1650 2621 llai1 sdev_cache_update(struct sdev_node *ddv, struct sdev_node **dv, char *nm, 1651 2621 llai1 sdev_cache_ops_t ops) 1652 2621 llai1 { 1653 2621 llai1 int error = 0; 1654 2621 llai1 1655 2621 llai1 ASSERT((SDEV_HELD(*dv))); 1656 2621 llai1 1657 2621 llai1 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1658 2621 llai1 switch (ops) { 1659 2621 llai1 case SDEV_CACHE_ADD: 1660 2621 llai1 error = sdev_cache_add(ddv, dv, nm); 1661 2621 llai1 break; 1662 2621 llai1 case SDEV_CACHE_DELETE: 1663 2621 llai1 error = sdev_cache_delete(ddv, dv); 1664 2621 llai1 break; 1665 2621 llai1 default: 1666 2621 llai1 break; 1667 2621 llai1 } 1668 2621 llai1 1669 2621 llai1 return (error); 1670 2621 llai1 } 1671 2621 llai1 1672 2621 llai1 /* 1673 5331 amw * retrieve the named entry from the directory cache 1674 2621 llai1 */ 1675 2621 llai1 struct sdev_node * 1676 2621 llai1 sdev_cache_lookup(struct sdev_node *ddv, char *nm) 1677 2621 llai1 { 1678 2621 llai1 struct sdev_node *dv = NULL; 1679 2621 llai1 1680 2621 llai1 ASSERT(RW_LOCK_HELD(&ddv->sdev_contents)); 1681 2621 llai1 dv = sdev_findbyname(ddv, nm); 1682 2621 llai1 1683 2621 llai1 return (dv); 1684 2621 llai1 } 1685 2621 llai1 1686 2621 llai1 /* 1687 2621 llai1 * Implicit reconfig for nodes constructed by a link generator 1688 2621 llai1 * Start devfsadm if needed, or if devfsadm is in progress, 1689 2621 llai1 * prepare to block on devfsadm either completing or 1690 2621 llai1 * constructing the desired node. As devfsadmd is global 1691 2621 llai1 * in scope, constructing all necessary nodes, we only 1692 2621 llai1 * need to initiate it once. 1693 2621 llai1 */ 1694 2621 llai1 static int 1695 2621 llai1 sdev_call_devfsadmd(struct sdev_node *ddv, struct sdev_node *dv, char *nm) 1696 2621 llai1 { 1697 2621 llai1 int error = 0; 1698 2621 llai1 1699 2621 llai1 if (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state)) { 1700 2621 llai1 sdcmn_err6(("lookup: waiting for %s/%s, 0x%x\n", 1701 2621 llai1 ddv->sdev_name, nm, devfsadm_state)); 1702 2621 llai1 mutex_enter(&dv->sdev_lookup_lock); 1703 2621 llai1 SDEV_BLOCK_OTHERS(dv, (SDEV_LOOKUP | SDEV_LGWAITING)); 1704 2621 llai1 mutex_exit(&dv->sdev_lookup_lock); 1705 2621 llai1 error = 0; 1706 2621 llai1 } else if (!DEVNAME_DEVFSADM_HAS_RUN(devfsadm_state)) { 1707 2621 llai1 sdcmn_err6(("lookup %s/%s starting devfsadm, 0x%x\n", 1708 6065 cth ddv->sdev_name, nm, devfsadm_state)); 1709 2621 llai1 1710 2621 llai1 sdev_devfsadmd_thread(ddv, dv, kcred); 1711 2621 llai1 mutex_enter(&dv->sdev_lookup_lock); 1712 2621 llai1 SDEV_BLOCK_OTHERS(dv, 1713 2621 llai1 (SDEV_LOOKUP | SDEV_LGWAITING)); 1714 2621 llai1 mutex_exit(&dv->sdev_lookup_lock); 1715 2621 llai1 error = 0; 1716 2621 llai1 } else { 1717 2621 llai1 error = -1; 1718 2621 llai1 } 1719 2621 llai1 1720 2621 llai1 return (error); 1721 2621 llai1 } 1722 2621 llai1 1723 2621 llai1 /* 1724 2621 llai1 * Support for specialized device naming construction mechanisms 1725 2621 llai1 */ 1726 2621 llai1 static int 1727 2621 llai1 sdev_call_dircallback(struct sdev_node *ddv, struct sdev_node **dvp, char *nm, 1728 2621 llai1 int (*callback)(struct sdev_node *, char *, void **, struct cred *, 1729 2621 llai1 void *, char *), int flags, struct cred *cred) 1730 2621 llai1 { 1731 2621 llai1 int rv = 0; 1732 2621 llai1 char *physpath = NULL; 1733 2621 llai1 struct vattr vattr; 1734 2621 llai1 struct vattr *vap; 1735 10588 Eric struct sdev_node *dv = NULL; 1736 2621 llai1 1737 10588 Eric ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 1738 10588 Eric if (flags & SDEV_VLINK) { 1739 7688 Aaron physpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 1740 7688 Aaron rv = callback(ddv, nm, (void *)&physpath, kcred, NULL, 1741 7688 Aaron NULL); 1742 7688 Aaron if (rv) { 1743 7688 Aaron kmem_free(physpath, MAXPATHLEN); 1744 7688 Aaron return (-1); 1745 7688 Aaron } 1746 7688 Aaron 1747 7688 Aaron vap = sdev_getdefault_attr(VLNK); 1748 7688 Aaron vap->va_size = strlen(physpath); 1749 10588 Eric gethrestime(&vap->va_atime); 1750 10588 Eric vap->va_mtime = vap->va_atime; 1751 10588 Eric vap->va_ctime = vap->va_atime; 1752 7688 Aaron 1753 7688 Aaron rv = sdev_mknode(ddv, nm, &dv, vap, NULL, 1754 7688 Aaron (void *)physpath, cred, SDEV_READY); 1755 7688 Aaron kmem_free(physpath, MAXPATHLEN); 1756 7688 Aaron if (rv) 1757 7688 Aaron return (rv); 1758 2621 llai1 } else if (flags & SDEV_VATTR) { 1759 2621 llai1 /* 1760 2621 llai1 * /dev/pts 1761 2621 llai1 * 1762 2621 llai1 * callback is responsible to set the basic attributes, 1763 2621 llai1 * e.g. va_type/va_uid/va_gid/ 1764 2621 llai1 * dev_t if VCHR or VBLK/ 1765 2621 llai1 */ 1766 2621 llai1 ASSERT(callback); 1767 2621 llai1 rv = callback(ddv, nm, (void *)&vattr, kcred, NULL, NULL); 1768 2621 llai1 if (rv) { 1769 2621 llai1 sdcmn_err3(("devname_lookup_func: SDEV_NONE " 1770 2621 llai1 "callback failed \n")); 1771 2621 llai1 return (-1); 1772 2621 llai1 } 1773 2621 llai1 1774 2621 llai1 rv = sdev_mknode(ddv, nm, &dv, &vattr, NULL, NULL, 1775 2621 llai1 cred, SDEV_READY); 1776 2621 llai1 1777 2621 llai1 if (rv) 1778 2621 llai1 return (rv); 1779 2621 llai1 1780 2621 llai1 } else { 1781 2621 llai1 impossible(("lookup: %s/%s by %s not supported (%d)\n", 1782 2621 llai1 SDEVTOV(ddv)->v_path, nm, curproc->p_user.u_comm, 1783 2621 llai1 __LINE__)); 1784 2621 llai1 rv = -1; 1785 2621 llai1 } 1786 2621 llai1 1787 2621 llai1 *dvp = dv; 1788 2621 llai1 return (rv); 1789 2621 llai1 } 1790 2621 llai1 1791 2621 llai1 static int 1792 2621 llai1 is_devfsadm_thread(char *exec_name) 1793 2621 llai1 { 1794 2621 llai1 /* 1795 2621 llai1 * note: because devfsadmd -> /usr/sbin/devfsadm 1796 2621 llai1 * it is safe to use "devfsadm" to capture the lookups 1797 2621 llai1 * from devfsadm and its daemon version. 1798 2621 llai1 */ 1799 2621 llai1 if (strcmp(exec_name, "devfsadm") == 0) 1800 2621 llai1 return (1); 1801 2621 llai1 return (0); 1802 2621 llai1 } 1803 2621 llai1 1804 2621 llai1 /* 1805 2621 llai1 * Lookup Order: 1806 2621 llai1 * sdev_node cache; 1807 2621 llai1 * backing store (SDEV_PERSIST); 1808 2621 llai1 * DBNR: a. dir_ops implemented in the loadable modules; 1809 2621 llai1 * b. vnode ops in vtab. 1810 2621 llai1 */ 1811 2621 llai1 int 1812 2621 llai1 devname_lookup_func(struct sdev_node *ddv, char *nm, struct vnode **vpp, 1813 2621 llai1 struct cred *cred, int (*callback)(struct sdev_node *, char *, void **, 1814 2621 llai1 struct cred *, void *, char *), int flags) 1815 2621 llai1 { 1816 2621 llai1 int rv = 0, nmlen; 1817 2621 llai1 struct vnode *rvp = NULL; 1818 2621 llai1 struct sdev_node *dv = NULL; 1819 2621 llai1 int retried = 0; 1820 2621 llai1 int error = 0; 1821 2621 llai1 struct vattr vattr; 1822 2621 llai1 char *lookup_thread = curproc->p_user.u_comm; 1823 2621 llai1 int failed_flags = 0; 1824 2621 llai1 int (*vtor)(struct sdev_node *) = NULL; 1825 2621 llai1 int state; 1826 2621 llai1 int parent_state; 1827 2621 llai1 char *link = NULL; 1828 2621 llai1 1829 2621 llai1 if (SDEVTOV(ddv)->v_type != VDIR) 1830 2621 llai1 return (ENOTDIR); 1831 2621 llai1 1832 2621 llai1 /* 1833 2621 llai1 * Empty name or ., return node itself. 1834 2621 llai1 */ 1835 2621 llai1 nmlen = strlen(nm); 1836 2621 llai1 if ((nmlen == 0) || ((nmlen == 1) && (nm[0] == '.'))) { 1837 2621 llai1 *vpp = SDEVTOV(ddv); 1838 2621 llai1 VN_HOLD(*vpp); 1839 2621 llai1 return (0); 1840 2621 llai1 } 1841 2621 llai1 1842 2621 llai1 /* 1843 2621 llai1 * .., return the parent directory 1844 2621 llai1 */ 1845 2621 llai1 if ((nmlen == 2) && (strcmp(nm, "..") == 0)) { 1846 2621 llai1 *vpp = SDEVTOV(ddv->sdev_dotdot); 1847 2621 llai1 VN_HOLD(*vpp); 1848 2621 llai1 return (0); 1849 2621 llai1 } 1850 2621 llai1 1851 2621 llai1 rw_enter(&ddv->sdev_contents, RW_READER); 1852 2621 llai1 if (ddv->sdev_flags & SDEV_VTOR) { 1853 2621 llai1 vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv); 1854 2621 llai1 ASSERT(vtor); 1855 2621 llai1 } 1856 2621 llai1 1857 2621 llai1 tryagain: 1858 2621 llai1 /* 1859 2621 llai1 * (a) directory cache lookup: 1860 2621 llai1 */ 1861 2621 llai1 ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 1862 2621 llai1 parent_state = ddv->sdev_state; 1863 2621 llai1 dv = sdev_cache_lookup(ddv, nm); 1864 2621 llai1 if (dv) { 1865 2621 llai1 state = dv->sdev_state; 1866 2621 llai1 switch (state) { 1867 2621 llai1 case SDEV_INIT: 1868 2621 llai1 if (is_devfsadm_thread(lookup_thread)) 1869 2621 llai1 break; 1870 2621 llai1 1871 2621 llai1 /* ZOMBIED parent won't allow node creation */ 1872 2621 llai1 if (parent_state == SDEV_ZOMBIE) { 1873 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, 1874 2621 llai1 retried); 1875 2621 llai1 goto nolock_notfound; 1876 2621 llai1 } 1877 2621 llai1 1878 2621 llai1 mutex_enter(&dv->sdev_lookup_lock); 1879 2621 llai1 /* compensate the threads started after devfsadm */ 1880 2621 llai1 if (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state) && 1881 2621 llai1 !(SDEV_IS_LOOKUP(dv))) 1882 2621 llai1 SDEV_BLOCK_OTHERS(dv, 1883 2621 llai1 (SDEV_LOOKUP | SDEV_LGWAITING)); 1884 2621 llai1 1885 2621 llai1 if (SDEV_IS_LOOKUP(dv)) { 1886 2621 llai1 failed_flags |= SLF_REBUILT; 1887 2621 llai1 rw_exit(&ddv->sdev_contents); 1888 2621 llai1 error = sdev_wait4lookup(dv, SDEV_LOOKUP); 1889 2621 llai1 mutex_exit(&dv->sdev_lookup_lock); 1890 2621 llai1 rw_enter(&ddv->sdev_contents, RW_READER); 1891 2621 llai1 1892 2621 llai1 if (error != 0) { 1893 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, 1894 2621 llai1 retried); 1895 2621 llai1 goto nolock_notfound; 1896 2621 llai1 } 1897 2621 llai1 1898 2621 llai1 state = dv->sdev_state; 1899 2621 llai1 if (state == SDEV_INIT) { 1900 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, 1901 2621 llai1 retried); 1902 2621 llai1 goto nolock_notfound; 1903 2621 llai1 } else if (state == SDEV_READY) { 1904 2621 llai1 goto found; 1905 2621 llai1 } else if (state == SDEV_ZOMBIE) { 1906 2621 llai1 rw_exit(&ddv->sdev_contents); 1907 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, 1908 2621 llai1 retried); 1909 2621 llai1 SDEV_RELE(dv); 1910 2621 llai1 goto lookup_failed; 1911 2621 llai1 } 1912 2621 llai1 } else { 1913 2621 llai1 mutex_exit(&dv->sdev_lookup_lock); 1914 2621 llai1 } 1915 2621 llai1 break; 1916 2621 llai1 case SDEV_READY: 1917 2621 llai1 goto found; 1918 2621 llai1 case SDEV_ZOMBIE: 1919 2621 llai1 rw_exit(&ddv->sdev_contents); 1920 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 1921 2621 llai1 SDEV_RELE(dv); 1922 2621 llai1 goto lookup_failed; 1923 2621 llai1 default: 1924 2621 llai1 rw_exit(&ddv->sdev_contents); 1925 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 1926 2621 llai1 sdev_lookup_failed(ddv, nm, failed_flags); 1927 2621 llai1 *vpp = NULLVP; 1928 2621 llai1 return (ENOENT); 1929 2621 llai1 } 1930 2621 llai1 } 1931 2621 llai1 ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 1932 2621 llai1 1933 2621 llai1 /* 1934 2621 llai1 * ZOMBIED parent does not allow new node creation. 1935 2621 llai1 * bail out early 1936 2621 llai1 */ 1937 2621 llai1 if (parent_state == SDEV_ZOMBIE) { 1938 2621 llai1 rw_exit(&ddv->sdev_contents); 1939 10588 Eric *vpp = NULLVP; 1940 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 1941 2621 llai1 return (ENOENT); 1942 2621 llai1 } 1943 2621 llai1 1944 2621 llai1 /* 1945 2621 llai1 * (b0): backing store lookup 1946 2621 llai1 * SDEV_PERSIST is default except: 1947 2621 llai1 * 1) pts nodes 1948 2621 llai1 * 2) non-chmod'ed local nodes 1949 10588 Eric * 3) zvol nodes 1950 2621 llai1 */ 1951 2621 llai1 if (SDEV_IS_PERSIST(ddv)) { 1952 2621 llai1 error = devname_backstore_lookup(ddv, nm, &rvp); 1953 2621 llai1 1954 2621 llai1 if (!error) { 1955 2621 llai1 1956 2621 llai1 vattr.va_mask = AT_MODE|AT_UID|AT_GID; 1957 5331 amw error = VOP_GETATTR(rvp, &vattr, 0, cred, NULL); 1958 2621 llai1 if (error) { 1959 2621 llai1 rw_exit(&ddv->sdev_contents); 1960 2621 llai1 if (dv) 1961 2621 llai1 SDEV_RELE(dv); 1962 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 1963 2621 llai1 sdev_lookup_failed(ddv, nm, failed_flags); 1964 2621 llai1 *vpp = NULLVP; 1965 2621 llai1 return (ENOENT); 1966 2621 llai1 } 1967 2621 llai1 1968 2621 llai1 if (vattr.va_type == VLNK) { 1969 2621 llai1 error = sdev_getlink(rvp, &link); 1970 2621 llai1 if (error) { 1971 2621 llai1 rw_exit(&ddv->sdev_contents); 1972 2621 llai1 if (dv) 1973 2621 llai1 SDEV_RELE(dv); 1974 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, 1975 2621 llai1 retried); 1976 2621 llai1 sdev_lookup_failed(ddv, nm, 1977 2621 llai1 failed_flags); 1978 2621 llai1 *vpp = NULLVP; 1979 2621 llai1 return (ENOENT); 1980 2621 llai1 } 1981 2621 llai1 ASSERT(link != NULL); 1982 2621 llai1 } 1983 2621 llai1 1984 2621 llai1 if (!rw_tryupgrade(&ddv->sdev_contents)) { 1985 2621 llai1 rw_exit(&ddv->sdev_contents); 1986 2621 llai1 rw_enter(&ddv->sdev_contents, RW_WRITER); 1987 2621 llai1 } 1988 2621 llai1 error = sdev_mknode(ddv, nm, &dv, &vattr, 1989 2621 llai1 rvp, link, cred, SDEV_READY); 1990 2621 llai1 rw_downgrade(&ddv->sdev_contents); 1991 2621 llai1 1992 2621 llai1 if (link != NULL) { 1993 2621 llai1 kmem_free(link, strlen(link) + 1); 1994 2621 llai1 link = NULL; 1995 2621 llai1 } 1996 2621 llai1 1997 2621 llai1 if (error) { 1998 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 1999 2621 llai1 rw_exit(&ddv->sdev_contents); 2000 2621 llai1 if (dv) 2001 2621 llai1 SDEV_RELE(dv); 2002 2621 llai1 goto lookup_failed; 2003 2621 llai1 } else { 2004 2621 llai1 goto found; 2005 2621 llai1 } 2006 2621 llai1 } else if (retried) { 2007 2621 llai1 rw_exit(&ddv->sdev_contents); 2008 2621 llai1 sdcmn_err3(("retry of lookup of %s/%s: failed\n", 2009 2621 llai1 ddv->sdev_name, nm)); 2010 2621 llai1 if (dv) 2011 2621 llai1 SDEV_RELE(dv); 2012 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2013 2621 llai1 sdev_lookup_failed(ddv, nm, failed_flags); 2014 2621 llai1 *vpp = NULLVP; 2015 2621 llai1 return (ENOENT); 2016 2621 llai1 } 2017 2621 llai1 } 2018 2621 llai1 2019 8023 Phil lookup_create_node: 2020 2621 llai1 /* first thread that is doing the lookup on this node */ 2021 10588 Eric if (callback) { 2022 10588 Eric ASSERT(dv == NULL); 2023 10588 Eric if (!rw_tryupgrade(&ddv->sdev_contents)) { 2024 10588 Eric rw_exit(&ddv->sdev_contents); 2025 10588 Eric rw_enter(&ddv->sdev_contents, RW_WRITER); 2026 10588 Eric } 2027 10588 Eric error = sdev_call_dircallback(ddv, &dv, nm, callback, 2028 10588 Eric flags, cred); 2029 10588 Eric rw_downgrade(&ddv->sdev_contents); 2030 10588 Eric if (error == 0) { 2031 10588 Eric goto found; 2032 10588 Eric } else { 2033 10588 Eric SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2034 10588 Eric rw_exit(&ddv->sdev_contents); 2035 10588 Eric goto lookup_failed; 2036 10588 Eric } 2037 10588 Eric } 2038 2621 llai1 if (!dv) { 2039 2621 llai1 if (!rw_tryupgrade(&ddv->sdev_contents)) { 2040 2621 llai1 rw_exit(&ddv->sdev_contents); 2041 2621 llai1 rw_enter(&ddv->sdev_contents, RW_WRITER); 2042 2621 llai1 } 2043 2621 llai1 error = sdev_mknode(ddv, nm, &dv, NULL, NULL, NULL, 2044 2621 llai1 cred, SDEV_INIT); 2045 2621 llai1 if (!dv) { 2046 2621 llai1 rw_exit(&ddv->sdev_contents); 2047 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2048 2621 llai1 sdev_lookup_failed(ddv, nm, failed_flags); 2049 2621 llai1 *vpp = NULLVP; 2050 2621 llai1 return (ENOENT); 2051 2621 llai1 } 2052 2621 llai1 rw_downgrade(&ddv->sdev_contents); 2053 2621 llai1 } 2054 2621 llai1 2055 2621 llai1 /* 2056 2621 llai1 * (b1) invoking devfsadm once per life time for devfsadm nodes 2057 2621 llai1 */ 2058 10588 Eric ASSERT(SDEV_HELD(dv)); 2059 2621 llai1 2060 10588 Eric if (SDEV_IS_NO_NCACHE(dv)) 2061 10588 Eric failed_flags |= SLF_NO_NCACHE; 2062 10588 Eric if (sdev_reconfig_boot || !i_ddi_io_initialized() || 2063 10588 Eric SDEV_IS_DYNAMIC(ddv) || SDEV_IS_NO_NCACHE(dv) || 2064 10588 Eric ((moddebug & MODDEBUG_FINI_EBUSY) != 0)) { 2065 10588 Eric ASSERT(SDEV_HELD(dv)); 2066 10588 Eric SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2067 10588 Eric goto nolock_notfound; 2068 2621 llai1 } 2069 2621 llai1 2070 2621 llai1 /* 2071 10588 Eric * filter out known non-existent devices recorded 2072 10588 Eric * during initial reconfiguration boot for which 2073 10588 Eric * reconfig should not be done and lookup may 2074 10588 Eric * be short-circuited now. 2075 2621 llai1 */ 2076 10588 Eric if (sdev_lookup_filter(ddv, nm)) { 2077 10588 Eric SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2078 10588 Eric goto nolock_notfound; 2079 10588 Eric } 2080 10588 Eric 2081 10588 Eric /* bypassing devfsadm internal nodes */ 2082 10588 Eric if (is_devfsadm_thread(lookup_thread)) { 2083 10588 Eric SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2084 10588 Eric goto nolock_notfound; 2085 10588 Eric } 2086 10588 Eric 2087 10588 Eric if (sdev_reconfig_disable) { 2088 10588 Eric SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2089 10588 Eric goto nolock_notfound; 2090 10588 Eric } 2091 10588 Eric 2092 10588 Eric error = sdev_call_devfsadmd(ddv, dv, nm); 2093 10588 Eric if (error == 0) { 2094 10588 Eric sdcmn_err8(("lookup of %s/%s by %s: reconfig\n", 2095 10588 Eric ddv->sdev_name, nm, curproc->p_user.u_comm)); 2096 10588 Eric if (sdev_reconfig_verbose) { 2097 10588 Eric cmn_err(CE_CONT, 2098 10588 Eric "?lookup of %s/%s by %s: reconfig\n", 2099 10588 Eric ddv->sdev_name, nm, curproc->p_user.u_comm); 2100 2621 llai1 } 2101 10588 Eric retried = 1; 2102 10588 Eric failed_flags |= SLF_REBUILT; 2103 10588 Eric ASSERT(dv->sdev_state != SDEV_ZOMBIE); 2104 10588 Eric SDEV_SIMPLE_RELE(dv); 2105 10588 Eric goto tryagain; 2106 10588 Eric } else { 2107 10588 Eric SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2108 10588 Eric goto nolock_notfound; 2109 2621 llai1 } 2110 2621 llai1 2111 2621 llai1 found: 2112 2621 llai1 ASSERT(!(dv->sdev_flags & SDEV_STALE)); 2113 2621 llai1 ASSERT(dv->sdev_state == SDEV_READY); 2114 2621 llai1 if (vtor) { 2115 2621 llai1 /* 2116 2621 llai1 * Check validity of returned node 2117 2621 llai1 */ 2118 2621 llai1 switch (vtor(dv)) { 2119 2621 llai1 case SDEV_VTOR_VALID: 2120 2621 llai1 break; 2121 8023 Phil case SDEV_VTOR_STALE: 2122 8023 Phil /* 2123 8023 Phil * The name exists, but the cache entry is 2124 8023 Phil * stale and needs to be re-created. 2125 8023 Phil */ 2126 8023 Phil ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 2127 8023 Phil if (rw_tryupgrade(&ddv->sdev_contents) == 0) { 2128 8023 Phil rw_exit(&ddv->sdev_contents); 2129 8023 Phil rw_enter(&ddv->sdev_contents, RW_WRITER); 2130 8023 Phil } 2131 8023 Phil error = sdev_cache_update(ddv, &dv, nm, 2132 8023 Phil SDEV_CACHE_DELETE); 2133 8023 Phil rw_downgrade(&ddv->sdev_contents); 2134 8023 Phil if (error == 0) { 2135 8023 Phil dv = NULL; 2136 8023 Phil goto lookup_create_node; 2137 8023 Phil } 2138 8023 Phil /* FALLTHRU */ 2139 2621 llai1 case SDEV_VTOR_INVALID: 2140 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2141 2621 llai1 sdcmn_err7(("lookup: destroy invalid " 2142 2621 llai1 "node: %s(%p)\n", dv->sdev_name, (void *)dv)); 2143 2621 llai1 goto nolock_notfound; 2144 2621 llai1 case SDEV_VTOR_SKIP: 2145 2621 llai1 sdcmn_err7(("lookup: node not applicable - " 2146 2621 llai1 "skipping: %s(%p)\n", dv->sdev_name, (void *)dv)); 2147 2621 llai1 rw_exit(&ddv->sdev_contents); 2148 2621 llai1 SD_TRACE_FAILED_LOOKUP(ddv, nm, retried); 2149 2621 llai1 SDEV_RELE(dv); 2150 2621 llai1 goto lookup_failed; 2151 2621 llai1 default: 2152 2621 llai1 cmn_err(CE_PANIC, 2153 2621 llai1 "dev fs: validator failed: %s(%p)\n", 2154 2621 llai1 dv->sdev_name, (void *)dv); 2155 2621 llai1 break; 2156 2621 llai1 } 2157 2621 llai1 } 2158 2621 llai1 2159 2621 llai1 rw_exit(&ddv->sdev_contents); 2160 2621 llai1 rv = sdev_to_vp(dv, vpp); 2161 2621 llai1 sdcmn_err3(("devname_lookup_func: returning vp %p v_count %d state %d " 2162 2621 llai1 "for nm %s, error %d\n", (void *)*vpp, (*vpp)->v_count, 2163 2621 llai1 dv->sdev_state, nm, rv)); 2164 2621 llai1 return (rv); 2165 2621 llai1 2166 2621 llai1 nolock_notfound: 2167 2621 llai1 /* 2168 2621 llai1 * Destroy the node that is created for synchronization purposes. 2169 2621 llai1 */ 2170 2621 llai1 sdcmn_err3(("devname_lookup_func: %s with state %d\n", 2171 2621 llai1 nm, dv->sdev_state)); 2172 2621 llai1 ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 2173 2621 llai1 if (dv->sdev_state == SDEV_INIT) { 2174 2621 llai1 if (!rw_tryupgrade(&ddv->sdev_contents)) { 2175 2621 llai1 rw_exit(&ddv->sdev_contents); 2176 2621 llai1 rw_enter(&ddv->sdev_contents, RW_WRITER); 2177 2621 llai1 } 2178 2621 llai1 2179 2621 llai1 /* 2180 2621 llai1 * Node state may have changed during the lock 2181 2621 llai1 * changes. Re-check. 2182 2621 llai1 */ 2183 2621 llai1 if (dv->sdev_state == SDEV_INIT) { 2184 2621 llai1 (void) sdev_dirdelete(ddv, dv); 2185 2621 llai1 rw_exit(&ddv->sdev_contents); 2186 2621 llai1 sdev_lookup_failed(ddv, nm, failed_flags); 2187 2621 llai1 *vpp = NULL; 2188 2621 llai1 return (ENOENT); 2189 2621 llai1 } 2190 2621 llai1 } 2191 2621 llai1 2192 2621 llai1 rw_exit(&ddv->sdev_contents); 2193 2621 llai1 SDEV_RELE(dv); 2194 2621 llai1 2195 2621 llai1 lookup_failed: 2196 2621 llai1 sdev_lookup_failed(ddv, nm, failed_flags); 2197 2621 llai1 *vpp = NULL; 2198 2621 llai1 return (ENOENT); 2199 2621 llai1 } 2200 2621 llai1 2201 2621 llai1 /* 2202 2621 llai1 * Given a directory node, mark all nodes beneath as 2203 2621 llai1 * STALE, i.e. nodes that don't exist as far as new 2204 6347 jg * consumers are concerned. Remove them from the 2205 6347 jg * list of directory entries so that no lookup or 2206 6347 jg * directory traversal will find them. The node 2207 6347 jg * not deallocated so existing holds are not affected. 2208 2621 llai1 */ 2209 2621 llai1 void 2210 2621 llai1 sdev_stale(struct sdev_node *ddv) 2211 2621 llai1 { 2212 2621 llai1 struct sdev_node *dv; 2213 2621 llai1 struct vnode *vp; 2214 2621 llai1 2215 2621 llai1 ASSERT(SDEVTOV(ddv)->v_type == VDIR); 2216 2621 llai1 2217 2621 llai1 rw_enter(&ddv->sdev_contents, RW_WRITER); 2218 6260 jg for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = SDEV_NEXT_ENTRY(ddv, dv)) { 2219 2621 llai1 vp = SDEVTOV(dv); 2220 2621 llai1 if (vp->v_type == VDIR) 2221 2621 llai1 sdev_stale(dv); 2222 2621 llai1 2223 2621 llai1 sdcmn_err9(("sdev_stale: setting stale %s\n", 2224 6347 jg dv->sdev_path)); 2225 2621 llai1 dv->sdev_flags |= SDEV_STALE; 2226 6347 jg avl_remove(&ddv->sdev_entries, dv); 2227 2621 llai1 } 2228 2621 llai1 ddv->sdev_flags |= SDEV_BUILD; 2229 2621 llai1 rw_exit(&ddv->sdev_contents); 2230 2621 llai1 } 2231 2621 llai1 2232 2621 llai1 /* 2233 2621 llai1 * Given a directory node, clean out all the nodes beneath. 2234 2621 llai1 * If expr is specified, clean node with names matching expr. 2235 2621 llai1 * If SDEV_ENFORCE is specified in flags, busy nodes are made stale, 2236 2621 llai1 * so they are excluded from future lookups. 2237 2621 llai1 */ 2238 2621 llai1 int 2239 2621 llai1 sdev_cleandir(struct sdev_node *ddv, char *expr, uint_t flags) 2240 2621 llai1 { 2241 2621 llai1 int error = 0; 2242 2621 llai1 int busy = 0; 2243 2621 llai1 struct vnode *vp; 2244 2621 llai1 struct sdev_node *dv, *next = NULL; 2245 2621 llai1 int bkstore = 0; 2246 2621 llai1 int len = 0; 2247 2621 llai1 char *bks_name = NULL; 2248 2621 llai1 2249 2621 llai1 ASSERT(SDEVTOV(ddv)->v_type == VDIR); 2250 2621 llai1 2251 2621 llai1 /* 2252 2621 llai1 * We try our best to destroy all unused sdev_node's 2253 2621 llai1 */ 2254 2621 llai1 rw_enter(&ddv->sdev_contents, RW_WRITER); 2255 6260 jg for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) { 2256 6260 jg next = SDEV_NEXT_ENTRY(ddv, dv); 2257 2621 llai1 vp = SDEVTOV(dv); 2258 2621 llai1 2259 2621 llai1 if (expr && gmatch(dv->sdev_name, expr) == 0) 2260 2621 llai1 continue; 2261 2621 llai1 2262 2621 llai1 if (vp->v_type == VDIR && 2263 2621 llai1 sdev_cleandir(dv, NULL, flags) != 0) { 2264 2621 llai1 sdcmn_err9(("sdev_cleandir: dir %s busy\n", 2265 2621 llai1 dv->sdev_name)); 2266 2621 llai1 busy++; 2267 2621 llai1 continue; 2268 2621 llai1 } 2269 2621 llai1 2270 2621 llai1 if (vp->v_count > 0 && (flags & SDEV_ENFORCE) == 0) { 2271 2621 llai1 sdcmn_err9(("sdev_cleandir: dir %s busy\n", 2272 2621 llai1 dv->sdev_name)); 2273 2621 llai1 busy++; 2274 2621 llai1 continue; 2275 2621 llai1 } 2276 2621 llai1 2277 2621 llai1 /* 2278 2621 llai1 * at this point, either dv is not held or SDEV_ENFORCE 2279 2621 llai1 * is specified. In either case, dv needs to be deleted 2280 2621 llai1 */ 2281 2621 llai1 SDEV_HOLD(dv); 2282 2621 llai1 2283 2621 llai1 bkstore = SDEV_IS_PERSIST(dv) ? 1 : 0; 2284 2621 llai1 if (bkstore && (vp->v_type == VDIR)) 2285 2621 llai1 bkstore += 1; 2286 2621 llai1 2287 2621 llai1 if (bkstore) { 2288 2621 llai1 len = strlen(dv->sdev_name) + 1; 2289 2621 llai1 bks_name = kmem_alloc(len, KM_SLEEP); 2290 2621 llai1 bcopy(dv->sdev_name, bks_name, len); 2291 2621 llai1 } 2292 2621 llai1 2293 2621 llai1 error = sdev_dirdelete(ddv, dv); 2294 2621 llai1 2295 2621 llai1 if (error == EBUSY) { 2296 2621 llai1 sdcmn_err9(("sdev_cleandir: dir busy\n")); 2297 2621 llai1 busy++; 2298 2621 llai1 } 2299 2621 llai1 2300 2621 llai1 /* take care the backing store clean up */ 2301 2621 llai1 if (bkstore && (error == 0)) { 2302 2621 llai1 ASSERT(bks_name); 2303 2621 llai1 ASSERT(ddv->sdev_attrvp); 2304 2621 llai1 2305 2621 llai1 if (bkstore == 1) { 2306 2621 llai1 error = VOP_REMOVE(ddv->sdev_attrvp, 2307 5331 amw bks_name, kcred, NULL, 0); 2308 2621 llai1 } else if (bkstore == 2) { 2309 2621 llai1 error = VOP_RMDIR(ddv->sdev_attrvp, 2310 5331 amw bks_name, ddv->sdev_attrvp, kcred, NULL, 0); 2311 2621 llai1 } 2312 2621 llai1 2313 2621 llai1 /* do not propagate the backing store errors */ 2314 2621 llai1 if (error) { 2315 2621 llai1 sdcmn_err9(("sdev_cleandir: backing store" 2316 2621 llai1 "not cleaned\n")); 2317 2621 llai1 error = 0; 2318 2621 llai1 } 2319 2621 llai1 2320 2621 llai1 bkstore = 0; 2321 2621 llai1 kmem_free(bks_name, len); 2322 2621 llai1 bks_name = NULL; 2323 2621 llai1 len = 0; 2324 2621 llai1 } 2325 2621 llai1 } 2326 2621 llai1 2327 2621 llai1 ddv->sdev_flags |= SDEV_BUILD; 2328 2621 llai1 rw_exit(&ddv->sdev_contents); 2329 2621 llai1 2330 2621 llai1 if (busy) { 2331 2621 llai1 error = EBUSY; 2332 2621 llai1 } 2333 2621 llai1 2334 2621 llai1 return (error); 2335 2621 llai1 } 2336 2621 llai1 2337 2621 llai1 /* 2338 2621 llai1 * a convenient wrapper for readdir() funcs 2339 2621 llai1 */ 2340 2621 llai1 size_t 2341 2621 llai1 add_dir_entry(dirent64_t *de, char *nm, size_t size, ino_t ino, offset_t off) 2342 2621 llai1 { 2343 2621 llai1 size_t reclen = DIRENT64_RECLEN(strlen(nm)); 2344 2621 llai1 if (reclen > size) 2345 2621 llai1 return (0); 2346 2621 llai1 2347 2621 llai1 de->d_ino = (ino64_t)ino; 2348 2621 llai1 de->d_off = (off64_t)off + 1; 2349 2621 llai1 de->d_reclen = (ushort_t)reclen; 2350 2621 llai1 (void) strncpy(de->d_name, nm, DIRENT64_NAMELEN(reclen)); 2351 2621 llai1 return (reclen); 2352 2621 llai1 } 2353 2621 llai1 2354 2621 llai1 /* 2355 2621 llai1 * sdev_mount service routines 2356 2621 llai1 */ 2357 2621 llai1 int 2358 2621 llai1 sdev_copyin_mountargs(struct mounta *uap, struct sdev_mountargs *args) 2359 2621 llai1 { 2360 2621 llai1 int error; 2361 2621 llai1 2362 2621 llai1 if (uap->datalen != sizeof (*args)) 2363 2621 llai1 return (EINVAL); 2364 2621 llai1 2365 2621 llai1 if (error = copyin(uap->dataptr, args, sizeof (*args))) { 2366 2621 llai1 cmn_err(CE_WARN, "sdev_copyin_mountargs: can not" 2367 2621 llai1 "get user data. error %d\n", error); 2368 2621 llai1 return (EFAULT); 2369 2621 llai1 } 2370 2621 llai1 2371 2621 llai1 return (0); 2372 2621 llai1 } 2373 2621 llai1 2374 2621 llai1 #ifdef nextdp 2375 2621 llai1 #undef nextdp 2376 2621 llai1 #endif 2377 3133 jg #define nextdp(dp) ((struct dirent64 *) \ 2378 3133 jg (intptr_t)((char *)(dp) + (dp)->d_reclen)) 2379 2621 llai1 2380 2621 llai1 /* 2381 2621 llai1 * readdir helper func 2382 2621 llai1 */ 2383 2621 llai1 int 2384 2621 llai1 devname_readdir_func(vnode_t *vp, uio_t *uiop, cred_t *cred, int *eofp, 2385 2621 llai1 int flags) 2386 2621 llai1 { 2387 2621 llai1 struct sdev_node *ddv = VTOSDEV(vp); 2388 2621 llai1 struct sdev_node *dv; 2389 2621 llai1 dirent64_t *dp; 2390 2621 llai1 ulong_t outcount = 0; 2391 2621 llai1 size_t namelen; 2392 2621 llai1 ulong_t alloc_count; 2393 2621 llai1 void *outbuf; 2394 2621 llai1 struct iovec *iovp; 2395 2621 llai1 int error = 0; 2396 2621 llai1 size_t reclen; 2397 2621 llai1 offset_t diroff; 2398 2621 llai1 offset_t soff; 2399 2621 llai1 int this_reclen; 2400 2621 llai1 int (*vtor)(struct sdev_node *) = NULL; 2401 2621 llai1 struct vattr attr; 2402 2621 llai1 timestruc_t now; 2403 2621 llai1 2404 2621 llai1 ASSERT(ddv->sdev_attr || ddv->sdev_attrvp); 2405 2621 llai1 ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 2406 2621 llai1 2407 2621 llai1 if (uiop->uio_loffset >= MAXOFF_T) { 2408 2621 llai1 if (eofp) 2409 2621 llai1 *eofp = 1; 2410 2621 llai1 return (0); 2411 2621 llai1 } 2412 2621 llai1 2413 2621 llai1 if (uiop->uio_iovcnt != 1) 2414 2621 llai1 return (EINVAL); 2415 2621 llai1 2416 2621 llai1 if (vp->v_type != VDIR) 2417 2621 llai1 return (ENOTDIR); 2418 2621 llai1 2419 2621 llai1 if (ddv->sdev_flags & SDEV_VTOR) { 2420 2621 llai1 vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv); 2421 2621 llai1 ASSERT(vtor); 2422 2621 llai1 } 2423 2621 llai1 2424 2621 llai1 if (eofp != NULL) 2425 2621 llai1 *eofp = 0; 2426 2621 llai1 2427 3133 jg soff = uiop->uio_loffset; 2428 2621 llai1 iovp = uiop->uio_iov; 2429 2621 llai1 alloc_count = iovp->iov_len; 2430 2621 llai1 dp = outbuf = kmem_alloc(alloc_count, KM_SLEEP); 2431 2621 llai1 outcount = 0; 2432 2621 llai1 2433 2621 llai1 if (ddv->sdev_state == SDEV_ZOMBIE) 2434 2621 llai1 goto get_cache; 2435 2621 llai1 2436 2679 szhou if (SDEV_IS_GLOBAL(ddv)) { 2437 2621 llai1 2438 10097 Eric if ((sdev_boot_state == SDEV_BOOT_STATE_COMPLETE) && 2439 2621 llai1 !sdev_reconfig_boot && (flags & SDEV_BROWSE) && 2440 2621 llai1 !SDEV_IS_DYNAMIC(ddv) && !SDEV_IS_NO_NCACHE(ddv) && 2441 2621 llai1 ((moddebug & MODDEBUG_FINI_EBUSY) == 0) && 2442 2621 llai1 !DEVNAME_DEVFSADM_HAS_RUN(devfsadm_state) && 2443 2621 llai1 !DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state) && 2444 2621 llai1 !sdev_reconfig_disable) { 2445 2621 llai1 /* 2446 2621 llai1 * invoking "devfsadm" to do system device reconfig 2447 2621 llai1 */ 2448 2621 llai1 mutex_enter(&ddv->sdev_lookup_lock); 2449 2621 llai1 SDEV_BLOCK_OTHERS(ddv, 2450 2621 llai1 (SDEV_READDIR|SDEV_LGWAITING)); 2451 2621 llai1 mutex_exit(&ddv->sdev_lookup_lock); 2452 2621 llai1 2453 2621 llai1 sdcmn_err8(("readdir of %s by %s: reconfig\n", 2454 2621 llai1 ddv->sdev_path, curproc->p_user.u_comm)); 2455 2621 llai1 if (sdev_reconfig_verbose) { 2456 2621 llai1 cmn_err(CE_CONT, 2457 2621 llai1 "?readdir of %s by %s: reconfig\n", 2458 2621 llai1 ddv->sdev_path, curproc->p_user.u_comm); 2459 2621 llai1 } 2460 2621 llai1 2461 2621 llai1 sdev_devfsadmd_thread(ddv, NULL, kcred); 2462 2621 llai1 } else if (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state)) { 2463 2621 llai1 /* 2464 2621 llai1 * compensate the "ls" started later than "devfsadm" 2465 2621 llai1 */ 2466 2621 llai1 mutex_enter(&ddv->sdev_lookup_lock); 2467 2621 llai1 SDEV_BLOCK_OTHERS(ddv, (SDEV_READDIR|SDEV_LGWAITING)); 2468 2621 llai1 mutex_exit(&ddv->sdev_lookup_lock); 2469 2621 llai1 } 2470 2621 llai1 2471 2621 llai1 /* 2472 2621 llai1 * release the contents lock so that 2473 3843 jg * the cache may be updated by devfsadmd 2474 2621 llai1 */ 2475 2621 llai1 rw_exit(&ddv->sdev_contents); 2476 2621 llai1 mutex_enter(&ddv->sdev_lookup_lock); 2477 2621 llai1 if (SDEV_IS_READDIR(ddv)) 2478 2621 llai1 (void) sdev_wait4lookup(ddv, SDEV_READDIR); 2479 2621 llai1 mutex_exit(&ddv->sdev_lookup_lock); 2480 2621 llai1 rw_enter(&ddv->sdev_contents, RW_READER); 2481 2621 llai1 2482 2621 llai1 sdcmn_err4(("readdir of directory %s by %s\n", 2483 2621 llai1 ddv->sdev_name, curproc->p_user.u_comm)); 2484 3843 jg if (ddv->sdev_flags & SDEV_BUILD) { 2485 2621 llai1 if (SDEV_IS_PERSIST(ddv)) { 2486 2621 llai1 error = sdev_filldir_from_store(ddv, 2487 2621 llai1 alloc_count, cred); 2488 2621 llai1 } 2489 3843 jg ddv->sdev_flags &= ~SDEV_BUILD; 2490 2621 llai1 } 2491 2621 llai1 } 2492 2621 llai1 2493 2621 llai1 get_cache: 2494 2621 llai1 /* handle "." and ".." */ 2495 2621 llai1 diroff = 0; 2496 2621 llai1 if (soff == 0) { 2497 2621 llai1 /* first time */ 2498 2621 llai1 this_reclen = DIRENT64_RECLEN(1); 2499 2621 llai1 if (alloc_count < this_reclen) { 2500 2621 llai1 error = EINVAL; 2501 2621 llai1 goto done; 2502 2621 llai1 } 2503 2621 llai1 2504 2621 llai1 dp->d_ino = (ino64_t)ddv->sdev_ino; 2505 2621 llai1 dp->d_off = (off64_t)1; 2506 2621 llai1 dp->d_reclen = (ushort_t)this_reclen; 2507 2621 llai1 2508 2621 llai1 (void) strncpy(dp->d_name, ".", 2509 2621 llai1 DIRENT64_NAMELEN(this_reclen)); 2510 2621 llai1 outcount += dp->d_reclen; 2511 2621 llai1 dp = nextdp(dp); 2512 2621 llai1 } 2513 2621 llai1 2514 2621 llai1 diroff++; 2515 2621 llai1 if (soff <= 1) { 2516 2621 llai1 this_reclen = DIRENT64_RECLEN(2); 2517 2621 llai1 if (alloc_count < outcount + this_reclen) { 2518 2621 llai1 error = EINVAL; 2519 2621 llai1 goto done; 2520 2621 llai1 } 2521 2621 llai1 2522 2621 llai1 dp->d_reclen = (ushort_t)this_reclen; 2523 2621 llai1 dp->d_ino = (ino64_t)ddv->sdev_dotdot->sdev_ino; 2524 2621 llai1 dp->d_off = (off64_t)2; 2525 2621 llai1 2526 2621 llai1 (void) strncpy(dp->d_name, "..", 2527 2621 llai1 DIRENT64_NAMELEN(this_reclen)); 2528 2621 llai1 outcount += dp->d_reclen; 2529 2621 llai1 2530 2621 llai1 dp = nextdp(dp); 2531 2621 llai1 } 2532 2621 llai1 2533 2621 llai1 2534 2621 llai1 /* gets the cache */ 2535 2621 llai1 diroff++; 2536 6260 jg for (dv = SDEV_FIRST_ENTRY(ddv); dv; 2537 6260 jg dv = SDEV_NEXT_ENTRY(ddv, dv), diroff++) { 2538 2621 llai1 sdcmn_err3(("sdev_readdir: diroff %lld soff %lld for '%s' \n", 2539 2621 llai1 diroff, soff, dv->sdev_name)); 2540 2621 llai1 2541 2621 llai1 /* bypassing pre-matured nodes */ 2542 2621 llai1 if (diroff < soff || (dv->sdev_state != SDEV_READY)) { 2543 2621 llai1 sdcmn_err3(("sdev_readdir: pre-mature node " 2544 10588 Eric "%s %d\n", dv->sdev_name, dv->sdev_state)); 2545 2621 llai1 continue; 2546 2621 llai1 } 2547 2621 llai1 2548 2621 llai1 /* 2549 2621 llai1 * Check validity of node 2550 2621 llai1 */ 2551 2621 llai1 if (vtor) { 2552 2621 llai1 switch (vtor(dv)) { 2553 2621 llai1 case SDEV_VTOR_VALID: 2554 2621 llai1 break; 2555 2621 llai1 case SDEV_VTOR_INVALID: 2556 2621 llai1 case SDEV_VTOR_SKIP: 2557 2621 llai1 continue; 2558 2621 llai1 default: 2559 2621 llai1 cmn_err(CE_PANIC, 2560 2621 llai1 "dev fs: validator failed: %s(%p)\n", 2561 2621 llai1 dv->sdev_name, (void *)dv); 2562 2621 llai1 break; 2563 2621 llai1 /*NOTREACHED*/ 2564 2621 llai1 } 2565 2621 llai1 } 2566 2621 llai1 2567 2621 llai1 namelen = strlen(dv->sdev_name); 2568 2621 llai1 reclen = DIRENT64_RECLEN(namelen); 2569 2621 llai1 if (outcount + reclen > alloc_count) { 2570 2621 llai1 goto full; 2571 2621 llai1 } 2572 2621 llai1 dp->d_reclen = (ushort_t)reclen; 2573 2621 llai1 dp->d_ino = (ino64_t)dv->sdev_ino; 2574 2621 llai1 dp->d_off = (off64_t)diroff + 1; 2575 2621 llai1 (void) strncpy(dp->d_name, dv->sdev_name, 2576 2621 llai1 DIRENT64_NAMELEN(reclen)); 2577 2621 llai1 outcount += reclen; 2578 2621 llai1 dp = nextdp(dp); 2579 2621 llai1 } 2580 2621 llai1 2581 2621 llai1 full: 2582 2621 llai1 sdcmn_err4(("sdev_readdir: moving %lu bytes: " 2583 2621 llai1 "diroff %lld, soff %lld, dv %p\n", outcount, diroff, soff, 2584 2621 llai1 (void *)dv)); 2585 2621 llai1 2586 2621 llai1 if (outcount) 2587 2621 llai1 error = uiomove(outbuf, outcount, UIO_READ, uiop); 2588 2621 llai1 2589 2621 llai1 if (!error) { 2590 3133 jg uiop->uio_loffset = diroff; 2591 2621 llai1 if (eofp) 2592 2621 llai1 *eofp = dv ? 0 : 1; 2593 2621 llai1 } 2594 2621 llai1 2595 2621 llai1 2596 2621 llai1 if (ddv->sdev_attrvp) { 2597 2621 llai1 gethrestime(&now); 2598 2621 llai1 attr.va_ctime = now; 2599 2621 llai1 attr.va_atime = now; 2600 2621 llai1 attr.va_mask = AT_CTIME|AT_ATIME; 2601 2621 llai1 2602 2621 llai1 (void) VOP_SETATTR(ddv->sdev_attrvp, &attr, 0, kcred, NULL); 2603 2621 llai1 } 2604 2621 llai1 done: 2605 2621 llai1 kmem_free(outbuf, alloc_count); 2606 2621 llai1 return (error); 2607 2621 llai1 } 2608 2621 llai1 2609 2621 llai1 static int 2610 2621 llai1 sdev_modctl_lookup(const char *path, vnode_t **r_vp) 2611 2621 llai1 { 2612 2621 llai1 vnode_t *vp; 2613 2621 llai1 vnode_t *cvp; 2614 2621 llai1 struct sdev_node *svp; 2615 2621 llai1 char *nm; 2616 2621 llai1 struct pathname pn; 2617 2621 llai1 int error; 2618 2621 llai1 int persisted = 0; 2619 2621 llai1 2620 7988 Jerry ASSERT(INGLOBALZONE(curproc)); 2621 7988 Jerry 2622 2621 llai1 if (error = pn_get((char *)path, UIO_SYSSPACE, &pn)) 2623 2621 llai1 return (error); 2624 2621 llai1 nm = kmem_alloc(MAXNAMELEN, KM_SLEEP); 2625 2621 llai1 2626 2621 llai1 vp = rootdir; 2627 2621 llai1 VN_HOLD(vp); 2628 2621 llai1 2629 2621 llai1 while (pn_pathleft(&pn)) { 2630 7988 Jerry ASSERT(vp->v_type == VDIR || vp->v_type == VLNK); 2631 2621 llai1 (void) pn_getcomponent(&pn, nm); 2632 7988 Jerry 2633 7988 Jerry /* 2634 7988 Jerry * Deal with the .. special case where we may be 2635 7988 Jerry * traversing up across a mount point, to the 2636 7988 Jerry * root of this filesystem or global root. 2637 7988 Jerry */ 2638 7988 Jerry if (nm[0] == '.' && nm[1] == '.' && nm[2] == 0) { 2639 7988 Jerry checkforroot: 2640 7988 Jerry if (VN_CMP(vp, rootdir)) { 2641 7988 Jerry nm[1] = 0; 2642 7988 Jerry } else if (vp->v_flag & VROOT) { 2643 7988 Jerry vfs_t *vfsp; 2644 7988 Jerry cvp = vp; 2645 7988 Jerry vfsp = cvp->v_vfsp; 2646 7988 Jerry vfs_rlock_wait(vfsp); 2647 7988 Jerry vp = cvp->v_vfsp->vfs_vnodecovered; 2648 7988 Jerry if (vp == NULL || 2649 7988 Jerry (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 2650 7988 Jerry vfs_unlock(vfsp); 2651 7988 Jerry VN_RELE(cvp); 2652 7988 Jerry error = EIO; 2653 7988 Jerry break; 2654 7988 Jerry } 2655 7988 Jerry VN_HOLD(vp); 2656 7988 Jerry vfs_unlock(vfsp); 2657 7988 Jerry VN_RELE(cvp); 2658 7988 Jerry cvp = NULL; 2659 7988 Jerry goto checkforroot; 2660 7988 Jerry } 2661 7988 Jerry } 2662 7988 Jerry 2663 5331 amw error = VOP_LOOKUP(vp, nm, &cvp, NULL, 0, NULL, kcred, NULL, 2664 5331 amw NULL, NULL); 2665 7988 Jerry if (error) { 2666 7988 Jerry VN_RELE(vp); 2667 2621 llai1 break; 2668 7988 Jerry } 2669 2621 llai1 2670 2621 llai1 /* traverse mount points encountered on our journey */ 2671 2621 llai1 if (vn_ismntpt(cvp) && (error = traverse(&cvp)) != 0) { 2672 7988 Jerry VN_RELE(vp); 2673 2621 llai1 VN_RELE(cvp); 2674 2621 llai1 break; 2675 2621 llai1 } 2676 7988 Jerry 2677 7988 Jerry /* 2678 7988 Jerry * symbolic link, can be either relative and absolute 2679 7988 Jerry */ 2680 7988 Jerry if ((cvp->v_type == VLNK) && pn_pathleft(&pn)) { 2681 7988 Jerry struct pathname linkpath; 2682 7988 Jerry pn_alloc(&linkpath); 2683 7988 Jerry if (error = pn_getsymlink(cvp, &linkpath, kcred)) { 2684 7988 Jerry pn_free(&linkpath); 2685 7988 Jerry break; 2686 7988 Jerry } 2687 7988 Jerry if (pn_pathleft(&linkpath) == 0) 2688 7988 Jerry (void) pn_set(&linkpath, "."); 2689 7988 Jerry error = pn_insert(&pn, &linkpath, strlen(nm)); 2690 7988 Jerry pn_free(&linkpath); 2691 7988 Jerry if (pn.pn_pathlen == 0) { 2692 7988 Jerry VN_RELE(vp); 2693 7988 Jerry return (ENOENT); 2694 7988 Jerry } 2695 7988 Jerry if (pn.pn_path[0] == '/') { 2696 7988 Jerry pn_skipslash(&pn); 2697 7988 Jerry VN_RELE(vp); 2698 7988 Jerry VN_RELE(cvp); 2699 7988 Jerry vp = rootdir; 2700 7988 Jerry VN_HOLD(vp); 2701 7988 Jerry } else { 2702 7988 Jerry VN_RELE(cvp); 2703 7988 Jerry } 2704 7988 Jerry continue; 2705 7988 Jerry } 2706 7988 Jerry 2707 7988 Jerry VN_RELE(vp); 2708 2621 llai1 2709 2621 llai1 /* 2710 2621 llai1 * Direct the operation to the persisting filesystem 2711 2621 llai1 * underlying /dev. Bail if we encounter a 2712 2621 llai1 * non-persistent dev entity here. 2713 2621 llai1 */ 2714 2621 llai1 if (cvp->v_vfsp->vfs_fstype == devtype) { 2715 2621 llai1 2716 2621 llai1 if ((VTOSDEV(cvp)->sdev_flags & SDEV_PERSIST) == 0) { 2717 2621 llai1 error = ENOENT; 2718 2621 llai1 VN_RELE(cvp); 2719 2621 llai1 break; 2720 2621 llai1 } 2721 2621 llai1 2722 2621 llai1 if (VTOSDEV(cvp) == NULL) { 2723 2621 llai1 error = ENOENT; 2724 2621 llai1 VN_RELE(cvp); 2725 2621 llai1 break; 2726 2621 llai1 } 2727 2621 llai1 svp = VTOSDEV(cvp); 2728 2621 llai1 if ((vp = svp->sdev_attrvp) == NULL) { 2729 2621 llai1 error = ENOENT; 2730 2621 llai1 VN_RELE(cvp); 2731 2621 llai1 break; 2732 2621 llai1 } 2733 2621 llai1 persisted = 1; 2734 2621 llai1 VN_HOLD(vp); 2735 2621 llai1 VN_RELE(cvp); 2736 2621 llai1 cvp = vp; 2737 2621 llai1 } 2738 2621 llai1 2739 2621 llai1 vp = cvp; 2740 2621 llai1 pn_skipslash(&pn); 2741 2621 llai1 } 2742 2621 llai1 2743 2621 llai1 kmem_free(nm, MAXNAMELEN); 2744 2621 llai1 pn_free(&pn); 2745 2621 llai1 2746 2621 llai1 if (error) 2747 2621 llai1 return (error); 2748 2621 llai1 2749 2621 llai1 /* 2750 2621 llai1 * Only return persisted nodes in the filesystem underlying /dev. 2751 2621 llai1 */ 2752 2621 llai1 if (!persisted) { 2753 2621 llai1 VN_RELE(vp); 2754 2621 llai1 return (ENOENT); 2755 2621 llai1 } 2756 2621 llai1 2757 2621 llai1 *r_vp = vp; 2758 2621 llai1 return (0); 2759 2621 llai1 } 2760 2621 llai1 2761 2621 llai1 int 2762 2621 llai1 sdev_modctl_readdir(const char *dir, char ***dirlistp, 2763 6065 cth int *npathsp, int *npathsp_alloc, int checking_empty) 2764 2621 llai1 { 2765 2621 llai1 char **pathlist = NULL; 2766 2621 llai1 char **newlist = NULL; 2767 2621 llai1 int npaths = 0; 2768 2621 llai1 int npaths_alloc = 0; 2769 2621 llai1 dirent64_t *dbuf = NULL; 2770 2621 llai1 int n; 2771 2621 llai1 char *s; 2772 2621 llai1 int error; 2773 2621 llai1 vnode_t *vp; 2774 2621 llai1 int eof; 2775 2621 llai1 struct iovec iov; 2776 2621 llai1 struct uio uio; 2777 2621 llai1 struct dirent64 *dp; 2778 2621 llai1 size_t dlen; 2779 2621 llai1 size_t dbuflen; 2780 2621 llai1 int ndirents = 64; 2781 2621 llai1 char *nm; 2782 2621 llai1 2783 2621 llai1 error = sdev_modctl_lookup(dir, &vp); 2784 2621 llai1 sdcmn_err11(("modctl readdir: %s by %s: %s\n", 2785 2621 llai1 dir, curproc->p_user.u_comm, 2786 2621 llai1 (error == 0) ? "ok" : "failed")); 2787 2621 llai1 if (error) 2788 2621 llai1 return (error); 2789 2621 llai1 2790 2621 llai1 dlen = ndirents * (sizeof (*dbuf)); 2791 2621 llai1 dbuf = kmem_alloc(dlen, KM_SLEEP); 2792 2621 llai1 2793 2621 llai1 uio.uio_iov = &iov; 2794 2621 llai1 uio.uio_iovcnt = 1; 2795 2621 llai1 uio.uio_segflg = UIO_SYSSPACE; 2796 2621 llai1 uio.uio_fmode = 0; 2797 2621 llai1 uio.uio_extflg = UIO_COPY_CACHED; 2798 2621 llai1 uio.uio_loffset = 0; 2799 2621 llai1 uio.uio_llimit = MAXOFFSET_T; 2800 2621 llai1 2801 2621 llai1 eof = 0; 2802 2621 llai1 error = 0; 2803 2621 llai1 while (!error && !eof) { 2804 2621 llai1 uio.uio_resid = dlen; 2805 2621 llai1 iov.iov_base = (char *)dbuf; 2806 2621 llai1 iov.iov_len = dlen; 2807 2621 llai1 2808 2621 llai1 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 2809 5331 amw error = VOP_READDIR(vp, &uio, kcred, &eof, NULL, 0); 2810 2621 llai1 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 2811 2621 llai1 2812 2621 llai1 dbuflen = dlen - uio.uio_resid; 2813 2621 llai1 2814 2621 llai1 if (error || dbuflen == 0) 2815 2621 llai1 break; 2816 2621 llai1 2817 2621 llai1 for (dp = dbuf; ((intptr_t)dp < (intptr_t)dbuf + dbuflen); 2818 6065 cth dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen)) { 2819 2621 llai1 2820 2621 llai1 nm = dp->d_name; 2821 2621 llai1 2822 2621 llai1 if (strcmp(nm, ".") == 0 || strcmp(nm, "..") == 0) 2823 2621 llai1 continue; 2824 2621 llai1 if (npaths == npaths_alloc) { 2825 2621 llai1 npaths_alloc += 64; 2826 2621 llai1 newlist = (char **) 2827 2621 llai1 kmem_zalloc((npaths_alloc + 1) * 2828 6065 cth sizeof (char *), KM_SLEEP); 2829 2621 llai1 if (pathlist) { 2830 2621 llai1 bcopy(pathlist, newlist, 2831 2621 llai1 npaths * sizeof (char *)); 2832 2621 llai1 kmem_free(pathlist, 2833 2621 llai1 (npaths + 1) * sizeof (char *)); 2834 2621 llai1 } 2835 2621 llai1 pathlist = newlist; 2836 2621 llai1 } 2837 2621 llai1 n = strlen(nm) + 1; 2838 2621 llai1 s = kmem_alloc(n, KM_SLEEP); 2839 2621 llai1 bcopy(nm, s, n); 2840 2621 llai1 pathlist[npaths++] = s; 2841 2621 llai1 sdcmn_err11((" %s/%s\n", dir, s)); 2842 6065 cth 2843 6065 cth /* if checking empty, one entry is as good as many */ 2844 6065 cth if (checking_empty) { 2845 6065 cth eof = 1; 2846 6065 cth break; 2847 6065 cth } 2848 2621 llai1 } 2849 2621 llai1 } 2850 2621 llai1 2851 2621 llai1 exit: 2852 2621 llai1 VN_RELE(vp); 2853 2621 llai1 2854 2621 llai1 if (dbuf) 2855 2621 llai1 kmem_free(dbuf, dlen); 2856 2621 llai1 2857 2621 llai1 if (error) 2858 2621 llai1 return (error); 2859 2621 llai1 2860 2621 llai1 *dirlistp = pathlist; 2861 2621 llai1 *npathsp = npaths; 2862 2621 llai1 *npathsp_alloc = npaths_alloc; 2863 2621 llai1 2864 2621 llai1 return (0); 2865 2621 llai1 } 2866 2621 llai1 2867 2621 llai1 void 2868 2621 llai1 sdev_modctl_readdir_free(char **pathlist, int npaths, int npaths_alloc) 2869 2621 llai1 { 2870 2621 llai1 int i, n; 2871 2621 llai1 2872 2621 llai1 for (i = 0; i < npaths; i++) { 2873 2621 llai1 n = strlen(pathlist[i]) + 1; 2874 2621 llai1 kmem_free(pathlist[i], n); 2875 2621 llai1 } 2876 2621 llai1 2877 2621 llai1 kmem_free(pathlist, (npaths_alloc + 1) * sizeof (char *)); 2878 2621 llai1 } 2879 2621 llai1 2880 2621 llai1 int 2881 2621 llai1 sdev_modctl_devexists(const char *path) 2882 2621 llai1 { 2883 2621 llai1 vnode_t *vp; 2884 2621 llai1 int error; 2885 2621 llai1 2886 2621 llai1 error = sdev_modctl_lookup(path, &vp); 2887 2621 llai1 sdcmn_err11(("modctl dev exists: %s by %s: %s\n", 2888 2621 llai1 path, curproc->p_user.u_comm, 2889 2621 llai1 (error == 0) ? "ok" : "failed")); 2890 2621 llai1 if (error == 0) 2891 2621 llai1 VN_RELE(vp); 2892 2621 llai1 2893 2621 llai1 return (error); 2894 2621 llai1 } 2895 2621 llai1 2896 2621 llai1 extern int sdev_vnodeops_tbl_size; 2897 2621 llai1 2898 2621 llai1 /* 2899 2621 llai1 * construct a new template with overrides from vtab 2900 2621 llai1 */ 2901 2621 llai1 static fs_operation_def_t * 2902 2621 llai1 sdev_merge_vtab(const fs_operation_def_t tab[]) 2903 2621 llai1 { 2904 2621 llai1 fs_operation_def_t *new; 2905 2621 llai1 const fs_operation_def_t *tab_entry; 2906 2621 llai1 2907 2621 llai1 /* make a copy of standard vnode ops table */ 2908 2621 llai1 new = kmem_alloc(sdev_vnodeops_tbl_size, KM_SLEEP); 2909 2621 llai1 bcopy((void *)sdev_vnodeops_tbl, new, sdev_vnodeops_tbl_size); 2910 2621 llai1 2911 2621 llai1 /* replace the overrides from tab */ 2912 2621 llai1 for (tab_entry = tab; tab_entry->name != NULL; tab_entry++) { 2913 2621 llai1 fs_operation_def_t *std_entry = new; 2914 2621 llai1 while (std_entry->name) { 2915 2621 llai1 if (strcmp(tab_entry->name, std_entry->name) == 0) { 2916 2621 llai1 std_entry->func = tab_entry->func; 2917 2621 llai1 break; 2918 2621 llai1 } 2919 2621 llai1 std_entry++; 2920 2621 llai1 } 2921 2621 llai1 if (std_entry->name == NULL) 2922 2621 llai1 cmn_err(CE_NOTE, "sdev_merge_vtab: entry %s unused.", 2923 2621 llai1 tab_entry->name); 2924 2621 llai1 } 2925 2621 llai1 2926 2621 llai1 return (new); 2927 2621 llai1 } 2928 2621 llai1 2929 2621 llai1 /* free memory allocated by sdev_merge_vtab */ 2930 2621 llai1 static void 2931 2621 llai1 sdev_free_vtab(fs_operation_def_t *new) 2932 2621 llai1 { 2933 2621 llai1 kmem_free(new, sdev_vnodeops_tbl_size); 2934 2621 llai1 } 2935 2621 llai1 2936 2621 llai1 /* 2937 2621 llai1 * a generic setattr() function 2938 2621 llai1 * 2939 2621 llai1 * note: flags only supports AT_UID and AT_GID. 2940 2621 llai1 * Future enhancements can be done for other types, e.g. AT_MODE 2941 2621 llai1 */ 2942 2621 llai1 int 2943 2621 llai1 devname_setattr_func(struct vnode *vp, struct vattr *vap, int flags, 2944 2621 llai1 struct cred *cred, int (*callback)(struct sdev_node *, struct vattr *, 2945 2621 llai1 int), int protocol) 2946 2621 llai1 { 2947 2621 llai1 struct sdev_node *dv = VTOSDEV(vp); 2948 2621 llai1 struct sdev_node *parent = dv->sdev_dotdot; 2949 2621 llai1 struct vattr *get; 2950 2621 llai1 uint_t mask = vap->va_mask; 2951 2621 llai1 int error; 2952 2621 llai1 2953 2621 llai1 /* some sanity checks */ 2954 2621 llai1 if (vap->va_mask & AT_NOSET) 2955 2621 llai1 return (EINVAL); 2956 2621 llai1 2957 2621 llai1 if (vap->va_mask & AT_SIZE) { 2958 2621 llai1 if (vp->v_type == VDIR) { 2959 2621 llai1 return (EISDIR); 2960 2621 llai1 } 2961 2621 llai1 } 2962 2621 llai1 2963 2621 llai1 /* no need to set attribute, but do not fail either */ 2964 2621 llai1 ASSERT(parent); 2965 2621 llai1 rw_enter(&parent->sdev_contents, RW_READER); 2966 2621 llai1 if (dv->sdev_state == SDEV_ZOMBIE) { 2967 2621 llai1 rw_exit(&parent->sdev_contents); 2968 2621 llai1 return (0); 2969 2621 llai1 } 2970 2621 llai1 2971 2621 llai1 /* If backing store exists, just set it. */ 2972 2621 llai1 if (dv->sdev_attrvp) { 2973 2621 llai1 rw_exit(&parent->sdev_contents); 2974 2621 llai1 return (VOP_SETATTR(dv->sdev_attrvp, vap, flags, cred, NULL)); 2975 2621 llai1 } 2976 2621 llai1 2977 2621 llai1 /* 2978 2621 llai1 * Otherwise, for nodes with the persistence attribute, create it. 2979 2621 llai1 */ 2980 2621 llai1 ASSERT(dv->sdev_attr); 2981 2621 llai1 if (SDEV_IS_PERSIST(dv) || 2982 2621 llai1 ((vap->va_mask & ~AT_TIMES) != 0 && !SDEV_IS_DYNAMIC(dv))) { 2983 2621 llai1 sdev_vattr_merge(dv, vap); 2984 2621 llai1 rw_enter(&dv->sdev_contents, RW_WRITER); 2985 2621 llai1 error = sdev_shadow_node(dv, cred); 2986 2621 llai1 rw_exit(&dv->sdev_contents); 2987 2621 llai1 rw_exit(&parent->sdev_contents); 2988 2621 llai1 2989 2621 llai1 if (error) 2990 2621 llai1 return (error); 2991 2621 llai1 return (VOP_SETATTR(dv->sdev_attrvp, vap, flags, cred, NULL)); 2992 2621 llai1 } 2993 2621 llai1 2994 2621 llai1 2995 2621 llai1 /* 2996 2621 llai1 * sdev_attr was allocated in sdev_mknode 2997 2621 llai1 */ 2998 2621 llai1 rw_enter(&dv->sdev_contents, RW_WRITER); 2999 5331 amw error = secpolicy_vnode_setattr(cred, vp, vap, 3000 5331 amw dv->sdev_attr, flags, sdev_unlocked_access, dv); 3001 2621 llai1 if (error) { 3002 2621 llai1 rw_exit(&dv->sdev_contents); 3003 2621 llai1 rw_exit(&parent->sdev_contents); 3004 2621 llai1 return (error); 3005 2621 llai1 } 3006 2621 llai1 3007 2621 llai1 get = dv->sdev_attr; 3008 2621 llai1 if (mask & AT_MODE) { 3009 2621 llai1 get->va_mode &= S_IFMT; 3010 2621