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