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