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_vtops.c
+++ new/usr/src/uts/common/fs/dev/sdev_vtops.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) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 /*
26 26 * vnode ops for the /dev/vt directory
27 27 */
28 28
29 29 #include <sys/types.h>
30 30 #include <sys/param.h>
31 31 #include <sys/sysmacros.h>
32 32 #include <sys/sunndi.h>
33 33 #include <fs/fs_subr.h>
34 34 #include <sys/fs/dv_node.h>
35 35 #include <sys/fs/sdev_impl.h>
36 36 #include <sys/policy.h>
37 37 #include <sys/stat.h>
38 38 #include <sys/vfs_opreg.h>
39 39 #include <sys/tty.h>
40 40 #include <sys/vt_impl.h>
41 41 #include <sys/note.h>
42 42
43 43 /* warlock in this file only cares about variables shared by vt and devfs */
44 44 _NOTE(SCHEME_PROTECTS_DATA("Do not care", sdev_node vattr vnode))
45 45
46 46 #define DEVVT_UID_DEFAULT SDEV_UID_DEFAULT
47 47 #define DEVVT_GID_DEFAULT (0)
48 48 #define DEVVT_DEVMODE_DEFAULT (0600)
49 49 #define DEVVT_ACTIVE_NAME "active"
50 50 #define DEVVT_CONSUSER_NAME "console_user"
51 51
52 52 #define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
53 53
54 54 /* attributes for VT nodes */
55 55 static vattr_t devvt_vattr = {
56 56 AT_TYPE|AT_MODE|AT_UID|AT_GID, /* va_mask */
57 57 VCHR, /* va_type */
58 58 S_IFCHR | DEVVT_DEVMODE_DEFAULT, /* va_mode */
59 59 DEVVT_UID_DEFAULT, /* va_uid */
60 60 DEVVT_GID_DEFAULT, /* va_gid */
61 61 0 /* 0 hereafter */
62 62 };
63 63
64 64 struct vnodeops *devvt_vnodeops;
65 65
66 66 struct vnodeops *
67 67 devvt_getvnodeops(void)
68 68 {
69 69 return (devvt_vnodeops);
70 70 }
71 71
72 72 static int
73 73 devvt_str2minor(const char *nm, minor_t *mp)
74 74 {
75 75 long uminor = 0;
76 76 char *endptr = NULL;
77 77
78 78 if (nm == NULL || !isdigit(*nm))
79 79 return (EINVAL);
80 80
81 81 *mp = 0;
82 82 if (ddi_strtol(nm, &endptr, 10, &uminor) != 0 ||
83 83 *endptr != '\0' || uminor < 0) {
84 84 return (EINVAL);
85 85 }
86 86
87 87 *mp = (minor_t)uminor;
88 88 return (0);
89 89 }
90 90
91 91 /*
92 92 * Validate that a node is up-to-date and correct.
93 93 * A validator may not update the node state or
94 94 * contents as a read lock permits entry by
95 95 * multiple threads.
96 96 */
97 97 int
98 98 devvt_validate(struct sdev_node *dv)
99 99 {
100 100 minor_t min;
101 101 char *nm = dv->sdev_name;
102 102 int rval;
103 103
104 104 ASSERT(dv->sdev_state == SDEV_READY);
105 105 ASSERT(RW_LOCK_HELD(&(dv->sdev_dotdot)->sdev_contents));
106 106
107 107 /* validate only READY nodes */
108 108 if (dv->sdev_state != SDEV_READY) {
109 109 sdcmn_err(("dev fs: skipping: node not ready %s(%p)",
110 110 nm, (void *)dv));
111 111 return (SDEV_VTOR_SKIP);
112 112 }
113 113
114 114 if (vt_wc_attached() == (major_t)-1)
115 115 return (SDEV_VTOR_INVALID);
116 116
117 117 if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
118 118 char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
119 119 (void) vt_getactive(link, MAXPATHLEN);
120 120 rval = (strcmp(link, dv->sdev_symlink) == 0) ?
121 121 SDEV_VTOR_VALID : SDEV_VTOR_STALE;
122 122 kmem_free(link, MAXPATHLEN);
123 123 return (rval);
124 124 }
125 125
126 126 if (strcmp(nm, DEVVT_CONSUSER_NAME) == 0) {
127 127 char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
128 128 (void) vt_getconsuser(link, MAXPATHLEN);
129 129 rval = (strcmp(link, dv->sdev_symlink) == 0) ?
130 130 SDEV_VTOR_VALID : SDEV_VTOR_STALE;
131 131 kmem_free(link, MAXPATHLEN);
132 132 return (rval);
133 133 }
134 134
135 135 if (devvt_str2minor(nm, &min) != 0) {
136 136 return (SDEV_VTOR_INVALID);
137 137 }
138 138
139 139 if (vt_minor_valid(min) == B_FALSE)
140 140 return (SDEV_VTOR_INVALID);
141 141
142 142 return (SDEV_VTOR_VALID);
143 143 }
144 144
145 145 /*
146 146 * This callback is invoked from devname_lookup_func() to create
147 147 * a entry when the node is not found in the cache.
148 148 */
149 149 /*ARGSUSED*/
150 150 static int
151 151 devvt_create_rvp(struct sdev_node *ddv, char *nm,
152 152 void **arg, cred_t *cred, void *whatever, char *whichever)
153 153 {
154 154 minor_t min;
155 155 major_t maj;
156 156 struct vattr *vap = (struct vattr *)arg;
157 157
158 158 if ((maj = vt_wc_attached()) == (major_t)-1)
159 159 return (SDEV_VTOR_INVALID);
160 160
161 161 if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
162 162 (void) vt_getactive((char *)*arg, MAXPATHLEN);
163 163 return (0);
164 164 }
165 165
166 166 if (strcmp(nm, DEVVT_CONSUSER_NAME) == 0) {
167 167 (void) vt_getconsuser((char *)*arg, MAXPATHLEN);
168 168 return (0);
169 169 }
170 170 if (devvt_str2minor(nm, &min) != 0)
171 171 return (-1);
172 172
173 173 if (vt_minor_valid(min) == B_FALSE)
174 174 return (-1);
175 175
176 176 *vap = devvt_vattr;
177 177 vap->va_rdev = makedevice(maj, min);
178 178
179 179 return (0);
180 180 }
181 181
182 182 /*ARGSUSED3*/
183 183 static int
184 184 devvt_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
185 185 struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
186 186 caller_context_t *ct, int *direntflags, pathname_t *realpnp)
187 187 {
188 188 struct sdev_node *sdvp = VTOSDEV(dvp);
189 189 struct sdev_node *dv;
190 190 struct vnode *rvp = NULL;
191 191 int type, error;
192 192
193 193 if ((strcmp(nm, DEVVT_ACTIVE_NAME) == 0) ||
194 194 (strcmp(nm, DEVVT_CONSUSER_NAME) == 0)) {
195 195 type = SDEV_VLINK;
196 196 } else {
197 197 type = SDEV_VATTR;
198 198 }
199 199
200 200 /* Give warlock a more clear call graph */
201 201 #ifndef __lock_lint
202 202 error = devname_lookup_func(sdvp, nm, vpp, cred,
203 203 devvt_create_rvp, type);
204 204 #else
205 205 devvt_create_rvp(0, 0, 0, 0, 0, 0);
206 206 #endif
207 207
208 208 if (error == 0) {
209 209 switch ((*vpp)->v_type) {
210 210 case VCHR:
211 211 dv = VTOSDEV(VTOS(*vpp)->s_realvp);
212 212 ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS);
213 213 break;
214 214 case VDIR:
215 215 case VLNK:
216 216 dv = VTOSDEV(*vpp);
217 217 break;
218 218 default:
219 219 cmn_err(CE_PANIC, "devvt_lookup: Unsupported node "
220 220 "type: %p: %d", (void *)(*vpp), (*vpp)->v_type);
221 221 break;
222 222 }
223 223 ASSERT(SDEV_HELD(dv));
224 224 }
225 225
226 226 return (error);
227 227 }
228 228
229 229 static void
230 230 devvt_create_snode(struct sdev_node *ddv, char *nm, struct cred *cred, int type)
231 231 {
232 232 int error;
233 233 struct sdev_node *sdv = NULL;
234 234 struct vattr vattr;
235 235 struct vattr *vap = &vattr;
236 236 major_t maj;
237 237 minor_t min;
238 238
239 239 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
240 240
241 241 if ((maj = vt_wc_attached()) == (major_t)-1)
242 242 return;
243 243
244 244 if (strcmp(nm, DEVVT_ACTIVE_NAME) != 0 &&
245 245 strcmp(nm, DEVVT_CONSUSER_NAME) != 0 &&
246 246 devvt_str2minor(nm, &min) != 0)
247 247 return;
248 248
249 249 error = sdev_mknode(ddv, nm, &sdv, NULL, NULL, NULL, cred, SDEV_INIT);
250 250 if (error || !sdv) {
251 251 return;
252 252 }
253 253
254 254 mutex_enter(&sdv->sdev_lookup_lock);
255 255 SDEV_BLOCK_OTHERS(sdv, SDEV_LOOKUP);
256 256 mutex_exit(&sdv->sdev_lookup_lock);
257 257
258 258 if (type & SDEV_VATTR) {
259 259 *vap = devvt_vattr;
260 260 vap->va_rdev = makedevice(maj, min);
261 261 error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
262 262 NULL, cred, SDEV_READY);
263 263 } else if (type & SDEV_VLINK) {
264 264 char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
265 265
266 266 (void) vt_getactive(link, MAXPATHLEN);
267 267 *vap = sdev_vattr_lnk;
268 268 vap->va_size = strlen(link);
269 269 error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
270 270 (void *)link, cred, SDEV_READY);
271 271
272 272 kmem_free(link, MAXPATHLEN);
273 273 }
274 274
275 275 if (error != 0) {
276 276 SDEV_RELE(sdv);
277 277 return;
278 278 }
279 279
280 280 mutex_enter(&sdv->sdev_lookup_lock);
281 281 SDEV_UNBLOCK_OTHERS(sdv, SDEV_LOOKUP);
282 282 mutex_exit(&sdv->sdev_lookup_lock);
283 283
284 284 }
285 285
286 286 static void
287 287 devvt_rebuild_stale_link(struct sdev_node *ddv, struct sdev_node *dv)
288 288 {
289 289 char *link;
290 290
291 291 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
292 292
293 293 ASSERT((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == 0) ||
294 294 (strcmp(dv->sdev_name, DEVVT_CONSUSER_NAME) == 0));
295 295
296 296 link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
297 297 if (strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == 0) {
298 298 (void) vt_getactive(link, MAXPATHLEN);
299 299 } else if (strcmp(dv->sdev_name, DEVVT_CONSUSER_NAME) == 0) {
300 300 (void) vt_getconsuser(link, MAXPATHLEN);
301 301 }
302 302
303 303 if (strcmp(link, dv->sdev_symlink) != 0) {
304 304 strfree(dv->sdev_symlink);
305 305 dv->sdev_symlink = strdup(link);
306 306 dv->sdev_attr->va_size = strlen(link);
307 307 }
308 308 kmem_free(link, MAXPATHLEN);
309 309 }
310 310
311 311 /*
312 312 * First step in refreshing directory contents.
313 313 * Remove each invalid entry and rebuild the link
314 314 * reference for each stale entry.
315 315 */
316 316 static void
317 317 devvt_prunedir(struct sdev_node *ddv)
318 318 {
319 319 struct vnode *vp;
320 320 struct sdev_node *dv, *next = NULL;
321 321 int (*vtor)(struct sdev_node *) = NULL;
322 322
323 323 ASSERT(ddv->sdev_flags & SDEV_VTOR);
324 324
325 325 vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv);
326 326 ASSERT(vtor);
327 327
328 328 for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) {
329 329 next = SDEV_NEXT_ENTRY(ddv, dv);
330 330
331 331 switch (vtor(dv)) {
332 332 case SDEV_VTOR_VALID:
333 333 break;
334 334 case SDEV_VTOR_SKIP:
335 335 break;
336 336 case SDEV_VTOR_INVALID:
337 337 vp = SDEVTOV(dv);
338 338 if (vp->v_count != 0)
339 339 break;
340 340 /* remove the cached node */
341 341 SDEV_HOLD(dv);
342 342 (void) sdev_cache_update(ddv, &dv,
343 343 dv->sdev_name, SDEV_CACHE_DELETE);
344 344 SDEV_RELE(dv);
345 345 break;
346 346 case SDEV_VTOR_STALE:
347 347 devvt_rebuild_stale_link(ddv, dv);
348 348 break;
349 349 }
350 350 }
351 351 }
352 352
353 353 static void
354 354 devvt_cleandir(struct vnode *dvp, struct cred *cred)
355 355 {
356 356 struct sdev_node *sdvp = VTOSDEV(dvp);
357 357 struct sdev_node *dv, *next = NULL;
358 358 int min, cnt;
359 359 char found = 0;
360 360
361 361 mutex_enter(&vc_lock);
362 362 cnt = VC_INSTANCES_COUNT;
363 363 mutex_exit(&vc_lock);
364 364
365 365 /* We have to fool warlock this way, otherwise it will complain */
366 366 #ifndef __lock_lint
367 367 if (rw_tryupgrade(&sdvp->sdev_contents) == NULL) {
368 368 rw_exit(&sdvp->sdev_contents);
369 369 rw_enter(&sdvp->sdev_contents, RW_WRITER);
370 370 }
371 371 #else
372 372 rw_enter(&sdvp->sdev_contents, RW_WRITER);
373 373 #endif
374 374
375 375 /* 1. prune invalid nodes and rebuild stale symlinks */
376 376 devvt_prunedir(sdvp);
377 377
378 378 /* 2. create missing nodes */
379 379 for (min = 0; min < cnt; min++) {
380 380 char nm[16];
381 381
382 382 if (vt_minor_valid(min) == B_FALSE)
383 383 continue;
384 384
385 385 (void) snprintf(nm, sizeof (nm), "%d", min);
386 386 found = 0;
387 387 for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
388 388 next = SDEV_NEXT_ENTRY(sdvp, dv);
389 389
390 390 /* validate only ready nodes */
391 391 if (dv->sdev_state != SDEV_READY)
392 392 continue;
393 393 if (strcmp(nm, dv->sdev_name) == 0) {
394 394 found = 1;
395 395 break;
396 396 }
397 397 }
398 398 if (!found) {
399 399 devvt_create_snode(sdvp, nm, cred, SDEV_VATTR);
400 400 }
401 401 }
402 402
403 403 /* 3. create active link node and console user link node */
404 404 found = 0;
405 405 for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
406 406 next = SDEV_NEXT_ENTRY(sdvp, dv);
407 407
408 408 /* validate only ready nodes */
409 409 if (dv->sdev_state != SDEV_READY)
410 410 continue;
411 411 if ((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == NULL))
412 412 found |= 0x01;
413 413 if ((strcmp(dv->sdev_name, DEVVT_CONSUSER_NAME) == NULL))
414 414 found |= 0x02;
415 415
416 416 if ((found & 0x01) && (found & 0x02))
417 417 break;
418 418 }
419 419 if (!(found & 0x01))
420 420 devvt_create_snode(sdvp, DEVVT_ACTIVE_NAME, cred, SDEV_VLINK);
421 421 if (!(found & 0x02))
422 422 devvt_create_snode(sdvp, DEVVT_CONSUSER_NAME, cred, SDEV_VLINK);
423 423
424 424 #ifndef __lock_lint
425 425 rw_downgrade(&sdvp->sdev_contents);
426 426 #else
427 427 rw_exit(&sdvp->sdev_contents);
428 428 #endif
429 429 }
430 430
431 431 /*ARGSUSED4*/
432 432 static int
433 433 devvt_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
434 434 int *eofp, caller_context_t *ct, int flags)
435 435 {
436 436 if (uiop->uio_offset == 0) {
437 437 devvt_cleandir(dvp, cred);
438 438 }
439 439
440 440 return (devname_readdir_func(dvp, uiop, cred, eofp, 0));
441 441 }
442 442
443 443 /*
444 444 * We allow create to find existing nodes
445 445 * - if the node doesn't exist - EROFS
446 446 * - creating an existing dir read-only succeeds, otherwise EISDIR
447 447 * - exclusive creates fail - EEXIST
448 448 */
449 449 /*ARGSUSED2*/
450 450 static int
451 451 devvt_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
452 452 int mode, struct vnode **vpp, struct cred *cred, int flag,
453 453 caller_context_t *ct, vsecattr_t *vsecp)
454 454 {
455 455 int error;
456 456 struct vnode *vp;
457 457
458 458 *vpp = NULL;
459 459
460 460 if ((error = devvt_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL,
461 461 NULL)) != 0) {
462 462 if (error == ENOENT)
463 463 error = EROFS;
464 464 return (error);
465 465 }
466 466
467 467 if (excl == EXCL)
468 468 error = EEXIST;
469 469 else if (vp->v_type == VDIR && (mode & VWRITE))
470 470 error = EISDIR;
471 471 else
472 472 error = VOP_ACCESS(vp, mode, 0, cred, ct);
↓ open down ↓ |
472 lines elided |
↑ open up ↑ |
473 473
474 474 if (error) {
475 475 VN_RELE(vp);
476 476 } else
477 477 *vpp = vp;
478 478
479 479 return (error);
480 480 }
481 481
482 482 const fs_operation_def_t devvt_vnodeops_tbl[] = {
483 - VOPNAME_READDIR, { .vop_readdir = devvt_readdir },
484 - VOPNAME_LOOKUP, { .vop_lookup = devvt_lookup },
485 - VOPNAME_CREATE, { .vop_create = devvt_create },
486 - VOPNAME_REMOVE, { .error = fs_nosys },
487 - VOPNAME_MKDIR, { .error = fs_nosys },
488 - VOPNAME_RMDIR, { .error = fs_nosys },
489 - VOPNAME_SYMLINK, { .error = fs_nosys },
490 - VOPNAME_SETSECATTR, { .error = fs_nosys },
491 - NULL, NULL
483 + { VOPNAME_READDIR, { .vop_readdir = devvt_readdir } },
484 + { VOPNAME_LOOKUP, { .vop_lookup = devvt_lookup } },
485 + { VOPNAME_CREATE, { .vop_create = devvt_create } },
486 + { VOPNAME_REMOVE, { .error = fs_nosys } },
487 + { VOPNAME_MKDIR, { .error = fs_nosys } },
488 + { VOPNAME_RMDIR, { .error = fs_nosys } },
489 + { VOPNAME_SYMLINK, { .error = fs_nosys } },
490 + { VOPNAME_SETSECATTR, { .error = fs_nosys } },
491 + { NULL, { NULL } }
492 492 };
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX