1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25 /*
26 * Copyright (c) 2012 by Delphix. All rights reserved.
27 * Copyright 2017 Joyent, Inc.
28 */
29
30 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
31 /* All Rights Reserved */
32
33 /*
34 * University Copyright- Copyright (c) 1982, 1986, 1988
35 * The Regents of the University of California
36 * All Rights Reserved
37 *
38 * University Acknowledgment- Portions of this document are derived from
39 * software developed by the University of California, Berkeley, and its
40 * contributors.
41 */
42
43
44 #include <sys/types.h>
45 #include <sys/t_lock.h>
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/buf.h>
49 #include <sys/conf.h>
50 #include <sys/cred.h>
51 #include <sys/kmem.h>
52 #include <sys/sysmacros.h>
53 #include <sys/vfs.h>
54 #include <sys/vfs_opreg.h>
55 #include <sys/vnode.h>
56 #include <sys/fs/snode.h>
57 #include <sys/fs/fifonode.h>
58 #include <sys/debug.h>
59 #include <sys/errno.h>
60 #include <sys/time.h>
61 #include <sys/file.h>
62 #include <sys/open.h>
63 #include <sys/user.h>
64 #include <sys/termios.h>
65 #include <sys/stream.h>
66 #include <sys/strsubr.h>
67 #include <sys/autoconf.h>
68 #include <sys/esunddi.h>
69 #include <sys/flock.h>
70 #include <sys/modctl.h>
71
72 struct vfs spec_vfs;
73 static dev_t specdev;
74 struct kmem_cache *snode_cache;
75 int spec_debug = 0;
76
77 static struct snode *sfind(dev_t, vtype_t, struct vnode *);
78 static struct vnode *get_cvp(dev_t, vtype_t, struct snode *, int *);
79 static void sinsert(struct snode *);
80
81 struct vnode *
specvp_devfs(struct vnode * realvp,dev_t dev,vtype_t vtyp,struct cred * cr,dev_info_t * dip)82 specvp_devfs(
83 struct vnode *realvp,
84 dev_t dev,
85 vtype_t vtyp,
86 struct cred *cr,
87 dev_info_t *dip)
88 {
89 struct vnode *vp;
90
91 ASSERT(realvp && dip);
92 vp = specvp(realvp, dev, vtyp, cr);
93 ASSERT(vp);
94
95 /* associate a dip hold with the common snode's s_dip pointer */
96 spec_assoc_vp_with_devi(vp, dip);
97 return (vp);
98 }
99
100 /*
101 * Return a shadow special vnode for the given dev.
102 * If no snode exists for this dev create one and put it
103 * in a table hashed by <dev, realvp>. If the snode for
104 * this dev is already in the table return it (ref count is
105 * incremented by sfind). The snode will be flushed from the
106 * table when spec_inactive calls sdelete.
107 *
108 * The fsid is inherited from the real vnode so that clones
109 * can be found.
110 *
111 */
112 struct vnode *
specvp(struct vnode * vp,dev_t dev,vtype_t type,struct cred * cr)113 specvp(
114 struct vnode *vp,
115 dev_t dev,
116 vtype_t type,
117 struct cred *cr)
118 {
119 struct snode *sp;
120 struct snode *nsp;
121 struct snode *csp;
122 struct vnode *svp;
123 struct vattr va;
124 int rc;
125 int used_csp = 0; /* Did we use pre-allocated csp */
126
127 if (vp == NULL)
128 return (NULL);
129 if (vp->v_type == VFIFO)
130 return (fifovp(vp, cr));
131
132 ASSERT(vp->v_type == type);
133 ASSERT(vp->v_rdev == dev);
134
135 /*
136 * Pre-allocate snodes before holding any locks in case we block
137 */
138 nsp = kmem_cache_alloc(snode_cache, KM_SLEEP);
139 csp = kmem_cache_alloc(snode_cache, KM_SLEEP);
140
141 /*
142 * Get the time attributes outside of the stable lock since
143 * this operation may block. Unfortunately, it may not have
144 * been required if the snode is in the cache.
145 */
146 va.va_mask = AT_FSID | AT_TIMES;
147 rc = VOP_GETATTR(vp, &va, 0, cr, NULL); /* XXX may block! */
148
149 mutex_enter(&stable_lock);
150 if ((sp = sfind(dev, type, vp)) == NULL) {
151 struct vnode *cvp;
152
153 sp = nsp; /* Use pre-allocated snode */
154 svp = STOV(sp);
155
156 sp->s_realvp = vp;
157 VN_HOLD(vp);
158 sp->s_commonvp = NULL;
159 sp->s_dev = dev;
160 sp->s_dip = NULL;
161 sp->s_nextr = 0;
162 sp->s_list = NULL;
163 sp->s_plcy = NULL;
164 sp->s_size = 0;
165 sp->s_flag = 0;
166 if (rc == 0) {
167 /*
168 * Set times in snode to those in the vnode.
169 */
170 sp->s_fsid = va.va_fsid;
171 sp->s_atime = va.va_atime.tv_sec;
172 sp->s_mtime = va.va_mtime.tv_sec;
173 sp->s_ctime = va.va_ctime.tv_sec;
174 } else {
175 sp->s_fsid = specdev;
176 sp->s_atime = 0;
177 sp->s_mtime = 0;
178 sp->s_ctime = 0;
179 }
180 sp->s_count = 0;
181 sp->s_mapcnt = 0;
182
183 vn_reinit(svp);
184 svp->v_flag = (vp->v_flag & VROOT);
185 svp->v_vfsp = vp->v_vfsp;
186 VFS_HOLD(svp->v_vfsp);
187 svp->v_type = type;
188 svp->v_rdev = dev;
189 (void) vn_copypath(vp, svp);
190 if (type == VBLK || type == VCHR) {
191 cvp = get_cvp(dev, type, csp, &used_csp);
192 svp->v_stream = cvp->v_stream;
193
194 sp->s_commonvp = cvp;
195 }
196 vn_exists(svp);
197 sinsert(sp);
198 mutex_exit(&stable_lock);
199 if (used_csp == 0) {
200 /* Didn't use pre-allocated snode so free it */
201 kmem_cache_free(snode_cache, csp);
202 }
203 } else {
204 mutex_exit(&stable_lock);
205 /* free unused snode memory */
206 kmem_cache_free(snode_cache, nsp);
207 kmem_cache_free(snode_cache, csp);
208 }
209 return (STOV(sp));
210 }
211
212 /*
213 * Return a special vnode for the given dev; no vnode is supplied
214 * for it to shadow. Always create a new snode and put it in the
215 * table hashed by <dev, NULL>. The snode will be flushed from the
216 * table when spec_inactive() calls sdelete(). The association of
217 * this node with a attached instance of hardware is not made until
218 * spec_open time.
219 *
220 * N.B. Assumes caller takes on responsibility of making sure no one
221 * else is creating a snode for (dev, type) at this time.
222 */
223 struct vnode *
makespecvp(dev_t dev,vtype_t type)224 makespecvp(dev_t dev, vtype_t type)
225 {
226 struct snode *sp;
227 struct vnode *svp, *cvp;
228 time_t now;
229
230 sp = kmem_cache_alloc(snode_cache, KM_SLEEP);
231 svp = STOV(sp);
232 cvp = commonvp(dev, type);
233 now = gethrestime_sec();
234
235 sp->s_realvp = NULL;
236 sp->s_commonvp = cvp;
237 sp->s_dev = dev;
238 sp->s_dip = NULL;
239 sp->s_nextr = 0;
240 sp->s_list = NULL;
241 sp->s_plcy = NULL;
242 sp->s_size = 0;
243 sp->s_flag = 0;
244 sp->s_fsid = specdev;
245 sp->s_atime = now;
246 sp->s_mtime = now;
247 sp->s_ctime = now;
248 sp->s_count = 0;
249 sp->s_mapcnt = 0;
250
251 vn_reinit(svp);
252 svp->v_vfsp = &spec_vfs;
253 svp->v_stream = cvp->v_stream;
254 svp->v_type = type;
255 svp->v_rdev = dev;
256
257 vn_exists(svp);
258 mutex_enter(&stable_lock);
259 sinsert(sp);
260 mutex_exit(&stable_lock);
261
262 return (svp);
263 }
264
265
266 /*
267 * This function is called from spec_assoc_vp_with_devi(). That function
268 * associates a "new" dip with a common snode, releasing (any) old dip
269 * in the process. This function (spec_assoc_fence()) looks at the "new dip"
270 * and determines whether the snode should be fenced of or not. As the table
271 * below indicates, the value of old-dip is a don't care for all cases.
272 *
273 * old-dip new-dip common-snode
274 * =========================================
275 * Don't care NULL unfence
276 * Don't care retired fence
277 * Don't care not-retired unfence
278 *
279 * Since old-dip value is a "don't care", it is not passed into this function.
280 */
281 static void
spec_assoc_fence(dev_info_t * ndip,vnode_t * vp)282 spec_assoc_fence(dev_info_t *ndip, vnode_t *vp)
283 {
284 int fence;
285 struct snode *csp;
286
287 ASSERT(vp);
288 ASSERT(vn_matchops(vp, spec_getvnodeops()));
289
290 fence = 0;
291 if (ndip != NULL) {
292 mutex_enter(&DEVI(ndip)->devi_lock);
293 if (DEVI(ndip)->devi_flags & DEVI_RETIRED)
294 fence = 1;
295 mutex_exit(&DEVI(ndip)->devi_lock);
296 }
297
298 csp = VTOCS(vp);
299 ASSERT(csp);
300
301 /* SFENCED flag only set on common snode */
302 mutex_enter(&csp->s_lock);
303 if (fence)
304 csp->s_flag |= SFENCED;
305 else
306 csp->s_flag &= ~SFENCED;
307 mutex_exit(&csp->s_lock);
308
309 FENDBG((CE_NOTE, "%sfenced common snode (%p) for new dip=%p",
310 fence ? "" : "un", (void *)csp, (void *)ndip));
311 }
312
313 /*
314 * Associate the common snode with a devinfo node. This is called from:
315 *
316 * 1) specvp_devfs to associate a specfs node with the dip attached
317 * by devfs.
318 *
319 * 2) spec_open after path reconstruction and attach.
320 *
321 * 3) From dacf processing to associate a makespecvp node with
322 * the dip that dacf postattach processing is being performed on.
323 * This association is made prior to open to avoid recursion issues.
324 *
325 * 4) From ddi_assoc_queue_with_devi to change vnode association as part of
326 * DL_ATTACH/DL_DETACH processing (SDIPSET already set). The call
327 * from ddi_assoc_queue_with_devi may specify a NULL dip.
328 *
329 * We put an extra hold on the devinfo node passed in as we establish it as
330 * the new s_dip pointer. Any hold associated with the prior s_dip pointer
331 * is released. The new hold will stay active until another call to
332 * spec_assoc_vp_with_devi or until the common snode is destroyed by
333 * spec_inactive after the last VN_RELE of the common node. This devinfo hold
334 * transfers across a clone open except in the clone_dev case, where the clone
335 * driver is no longer required after open.
336 *
337 * When SDIPSET is set and s_dip is NULL, the vnode has an association with
338 * the driver even though there is currently no association with a specific
339 * hardware instance.
340 */
341 void
spec_assoc_vp_with_devi(struct vnode * vp,dev_info_t * dip)342 spec_assoc_vp_with_devi(struct vnode *vp, dev_info_t *dip)
343 {
344 struct snode *csp;
345 dev_info_t *olddip;
346
347 ASSERT(vp);
348
349 /*
350 * Don't establish a NULL association for a vnode associated with the
351 * clone driver. The qassociate(, -1) call from a streams driver's
352 * open implementation to indicate support for qassociate has the
353 * side-effect of this type of spec_assoc_vp_with_devi call. This
354 * call should not change the the association of the pre-clone
355 * vnode associated with the clone driver, the post-clone newdev
356 * association will be established later by spec_clone().
357 */
358 if ((dip == NULL) && (getmajor(vp->v_rdev) == clone_major))
359 return;
360
361 /* hold the new */
362 if (dip)
363 e_ddi_hold_devi(dip);
364
365 csp = VTOS(VTOS(vp)->s_commonvp);
366 mutex_enter(&csp->s_lock);
367 olddip = csp->s_dip;
368 csp->s_dip = dip;
369 csp->s_flag |= SDIPSET;
370
371 /* If association changes then invalidate cached size */
372 if (olddip != dip)
373 csp->s_flag &= ~SSIZEVALID;
374 mutex_exit(&csp->s_lock);
375
376 spec_assoc_fence(dip, vp);
377
378 /* release the old */
379 if (olddip)
380 ddi_release_devi(olddip);
381 }
382
383 /*
384 * Return the held dip associated with the specified snode.
385 */
386 dev_info_t *
spec_hold_devi_by_vp(struct vnode * vp)387 spec_hold_devi_by_vp(struct vnode *vp)
388 {
389 struct snode *csp;
390 dev_info_t *dip;
391
392 ASSERT(vn_matchops(vp, spec_getvnodeops()));
393
394 csp = VTOS(VTOS(vp)->s_commonvp);
395 dip = csp->s_dip;
396 if (dip)
397 e_ddi_hold_devi(dip);
398 return (dip);
399 }
400
401 /*
402 * Find a special vnode that refers to the given device
403 * of the given type. Never return a "common" vnode.
404 * Return NULL if a special vnode does not exist.
405 * HOLD the vnode before returning it.
406 */
407 struct vnode *
specfind(dev_t dev,vtype_t type)408 specfind(dev_t dev, vtype_t type)
409 {
410 struct snode *st;
411 struct vnode *nvp;
412
413 mutex_enter(&stable_lock);
414 st = stable[STABLEHASH(dev)];
415 while (st != NULL) {
416 if (st->s_dev == dev) {
417 nvp = STOV(st);
418 if (nvp->v_type == type && st->s_commonvp != nvp) {
419 VN_HOLD(nvp);
420 /* validate vnode is visible in the zone */
421 if (nvp->v_path != NULL &&
422 ZONE_PATH_VISIBLE(nvp->v_path, curzone)) {
423 mutex_exit(&stable_lock);
424 return (nvp);
425 }
426 VN_RELE(nvp);
427 }
428 }
429 st = st->s_next;
430 }
431 mutex_exit(&stable_lock);
432 return (NULL);
433 }
434
435 /*
436 * Loop through the snode cache looking for snodes referencing dip.
437 *
438 * This function determines if a devinfo node is "BUSY" from the perspective
439 * of having an active vnode associated with the device, which represents a
440 * dependency on the device's services. This function is needed because a
441 * devinfo node can have a non-zero devi_ref and still NOT be "BUSY" when,
442 * for instance, the framework is manipulating the node (has an open
443 * ndi_hold_devi).
444 *
445 * Returns:
446 * DEVI_REFERENCED - if dip is referenced
447 * DEVI_NOT_REFERENCED - if dip is not referenced
448 */
449 int
devi_stillreferenced(dev_info_t * dip)450 devi_stillreferenced(dev_info_t *dip)
451 {
452 struct snode *sp;
453 int i;
454
455 /* if no hold then there can't be an snode with s_dip == dip */
456 if (e_ddi_devi_holdcnt(dip) == 0)
457 return (DEVI_NOT_REFERENCED);
458
459 mutex_enter(&stable_lock);
460 for (i = 0; i < STABLESIZE; i++) {
461 for (sp = stable[i]; sp != NULL; sp = sp->s_next) {
462 if (sp->s_dip == dip) {
463 mutex_exit(&stable_lock);
464 return (DEVI_REFERENCED);
465 }
466 }
467 }
468 mutex_exit(&stable_lock);
469 return (DEVI_NOT_REFERENCED);
470 }
471
472 /*
473 * Given an snode, returns the open count and the dip
474 * associated with that snode
475 * Assumes the caller holds the appropriate locks
476 * to prevent snode and/or dip from going away.
477 * Returns:
478 * -1 No associated dip
479 * >= 0 Number of opens.
480 */
481 int
spec_devi_open_count(struct snode * sp,dev_info_t ** dipp)482 spec_devi_open_count(struct snode *sp, dev_info_t **dipp)
483 {
484 dev_info_t *dip;
485 uint_t count;
486 struct vnode *vp;
487
488 ASSERT(sp);
489 ASSERT(dipp);
490
491 vp = STOV(sp);
492
493 *dipp = NULL;
494
495 /*
496 * We are only interested in common snodes. Only common snodes
497 * get their s_count fields bumped up on opens.
498 */
499 if (sp->s_commonvp != vp || (dip = sp->s_dip) == NULL)
500 return (-1);
501
502 mutex_enter(&sp->s_lock);
503 count = sp->s_count + sp->s_mapcnt;
504 if (sp->s_flag & SLOCKED)
505 count++;
506 mutex_exit(&sp->s_lock);
507
508 *dipp = dip;
509
510 return (count);
511 }
512
513 /*
514 * Given a device vnode, return the common
515 * vnode associated with it.
516 */
517 struct vnode *
common_specvp(struct vnode * vp)518 common_specvp(struct vnode *vp)
519 {
520 struct snode *sp;
521
522 if ((vp->v_type != VBLK) && (vp->v_type != VCHR) ||
523 !vn_matchops(vp, spec_getvnodeops()))
524 return (vp);
525 sp = VTOS(vp);
526 return (sp->s_commonvp);
527 }
528
529 /*
530 * Returns a special vnode for the given dev. The vnode is the
531 * one which is "common" to all the snodes which represent the
532 * same device.
533 * Similar to commonvp() but doesn't acquire the stable_lock, and
534 * may use a pre-allocated snode provided by caller.
535 */
536 static struct vnode *
get_cvp(dev_t dev,vtype_t type,struct snode * nsp,int * used_nsp)537 get_cvp(
538 dev_t dev,
539 vtype_t type,
540 struct snode *nsp, /* pre-allocated snode */
541 int *used_nsp) /* flag indicating if we use nsp */
542 {
543 struct snode *sp;
544 struct vnode *svp;
545
546 ASSERT(MUTEX_HELD(&stable_lock));
547 if ((sp = sfind(dev, type, NULL)) == NULL) {
548 sp = nsp; /* Use pre-allocated snode */
549 *used_nsp = 1; /* return value */
550 svp = STOV(sp);
551
552 sp->s_realvp = NULL;
553 sp->s_commonvp = svp; /* points to itself */
554 sp->s_dev = dev;
555 sp->s_dip = NULL;
556 sp->s_nextr = 0;
557 sp->s_list = NULL;
558 sp->s_plcy = NULL;
559 sp->s_size = UNKNOWN_SIZE;
560 sp->s_flag = 0;
561 sp->s_fsid = specdev;
562 sp->s_atime = 0;
563 sp->s_mtime = 0;
564 sp->s_ctime = 0;
565 sp->s_count = 0;
566 sp->s_mapcnt = 0;
567
568 vn_reinit(svp);
569 svp->v_vfsp = &spec_vfs;
570 svp->v_type = type;
571 svp->v_rdev = dev;
572 vn_exists(svp);
573 sinsert(sp);
574 } else
575 *used_nsp = 0;
576 return (STOV(sp));
577 }
578
579 /*
580 * Returns a special vnode for the given dev. The vnode is the
581 * one which is "common" to all the snodes which represent the
582 * same device. For use ONLY by SPECFS.
583 */
584 struct vnode *
commonvp(dev_t dev,vtype_t type)585 commonvp(dev_t dev, vtype_t type)
586 {
587 struct snode *sp, *nsp;
588 struct vnode *svp;
589
590 /* Pre-allocate snode in case we might block */
591 nsp = kmem_cache_alloc(snode_cache, KM_SLEEP);
592
593 mutex_enter(&stable_lock);
594 if ((sp = sfind(dev, type, NULL)) == NULL) {
595 sp = nsp; /* Use pre-alloced snode */
596 svp = STOV(sp);
597
598 sp->s_realvp = NULL;
599 sp->s_commonvp = svp; /* points to itself */
600 sp->s_dev = dev;
601 sp->s_dip = NULL;
602 sp->s_nextr = 0;
603 sp->s_list = NULL;
604 sp->s_plcy = NULL;
605 sp->s_size = UNKNOWN_SIZE;
606 sp->s_flag = 0;
607 sp->s_fsid = specdev;
608 sp->s_atime = 0;
609 sp->s_mtime = 0;
610 sp->s_ctime = 0;
611 sp->s_count = 0;
612 sp->s_mapcnt = 0;
613
614 vn_reinit(svp);
615 svp->v_vfsp = &spec_vfs;
616 svp->v_type = type;
617 svp->v_rdev = dev;
618 vn_exists(svp);
619 sinsert(sp);
620 mutex_exit(&stable_lock);
621 } else {
622 mutex_exit(&stable_lock);
623 /* Didn't need the pre-allocated snode */
624 kmem_cache_free(snode_cache, nsp);
625 }
626 return (STOV(sp));
627 }
628
629 /*
630 * Snode lookup stuff.
631 * These routines maintain a table of snodes hashed by dev so
632 * that the snode for an dev can be found if it already exists.
633 */
634 struct snode *stable[STABLESIZE];
635 int stablesz = STABLESIZE;
636 kmutex_t stable_lock;
637
638 /*
639 * Put a snode in the table.
640 */
641 static void
sinsert(struct snode * sp)642 sinsert(struct snode *sp)
643 {
644 ASSERT(MUTEX_HELD(&stable_lock));
645 sp->s_next = stable[STABLEHASH(sp->s_dev)];
646 stable[STABLEHASH(sp->s_dev)] = sp;
647 }
648
649 /*
650 * Remove an snode from the hash table.
651 * The realvp is not released here because spec_inactive() still
652 * needs it to do a spec_fsync().
653 */
654 void
sdelete(struct snode * sp)655 sdelete(struct snode *sp)
656 {
657 struct snode *st;
658 struct snode *stprev = NULL;
659
660 ASSERT(MUTEX_HELD(&stable_lock));
661 st = stable[STABLEHASH(sp->s_dev)];
662 while (st != NULL) {
663 if (st == sp) {
664 if (stprev == NULL)
665 stable[STABLEHASH(sp->s_dev)] = st->s_next;
666 else
667 stprev->s_next = st->s_next;
668 break;
669 }
670 stprev = st;
671 st = st->s_next;
672 }
673 }
674
675 /*
676 * Lookup an snode by <dev, type, vp>.
677 * ONLY looks for snodes with non-NULL s_realvp members and
678 * common snodes (with s_commonvp pointing to its vnode).
679 *
680 * If vp is NULL, only return commonvp. Otherwise return
681 * shadow vp with both shadow and common vp's VN_HELD.
682 */
683 static struct snode *
sfind(dev_t dev,vtype_t type,struct vnode * vp)684 sfind(
685 dev_t dev,
686 vtype_t type,
687 struct vnode *vp)
688 {
689 struct snode *st;
690 struct vnode *svp;
691
692 ASSERT(MUTEX_HELD(&stable_lock));
693 st = stable[STABLEHASH(dev)];
694 while (st != NULL) {
695 svp = STOV(st);
696 if (st->s_dev == dev && svp->v_type == type &&
697 VN_CMP(st->s_realvp, vp) &&
698 (vp != NULL || st->s_commonvp == svp) &&
699 (vp == NULL || st->s_realvp->v_vfsp == vp->v_vfsp)) {
700 VN_HOLD(svp);
701 return (st);
702 }
703 st = st->s_next;
704 }
705 return (NULL);
706 }
707
708 /*
709 * Mark the accessed, updated, or changed times in an snode
710 * with the current time.
711 */
712 void
smark(struct snode * sp,int flag)713 smark(struct snode *sp, int flag)
714 {
715 time_t now = gethrestime_sec();
716
717 /* check for change to avoid unnecessary locking */
718 ASSERT((flag & ~(SACC|SUPD|SCHG)) == 0);
719 if (((flag & sp->s_flag) != flag) ||
720 ((flag & SACC) && (sp->s_atime != now)) ||
721 ((flag & SUPD) && (sp->s_mtime != now)) ||
722 ((flag & SCHG) && (sp->s_ctime != now))) {
723 /* lock and update */
724 mutex_enter(&sp->s_lock);
725 sp->s_flag |= flag;
726 if (flag & SACC)
727 sp->s_atime = now;
728 if (flag & SUPD)
729 sp->s_mtime = now;
730 if (flag & SCHG)
731 sp->s_ctime = now;
732 mutex_exit(&sp->s_lock);
733 }
734 }
735
736 /*
737 * Return the maximum file offset permitted for this device.
738 * -1 means unrestricted. SLOFFSET is associated with D_64BIT.
739 *
740 * On a 32-bit kernel this will limit:
741 * o D_64BIT devices to SPEC_MAXOFFSET_T.
742 * o non-D_64BIT character drivers to a 32-bit offset (MAXOFF_T).
743 */
744 offset_t
spec_maxoffset(struct vnode * vp)745 spec_maxoffset(struct vnode *vp)
746 {
747 struct snode *sp = VTOS(vp);
748 struct snode *csp = VTOS(sp->s_commonvp);
749
750 if (vp->v_stream)
751 return ((offset_t)-1);
752 else if (csp->s_flag & SANYOFFSET) /* D_U64BIT */
753 return ((offset_t)-1);
754 #ifdef _ILP32
755 if (csp->s_flag & SLOFFSET) /* D_64BIT */
756 return (SPEC_MAXOFFSET_T);
757 #endif /* _ILP32 */
758 return (MAXOFF_T);
759 }
760
761 /*ARGSUSED*/
762 static int
snode_constructor(void * buf,void * cdrarg,int kmflags)763 snode_constructor(void *buf, void *cdrarg, int kmflags)
764 {
765 struct snode *sp = buf;
766 struct vnode *vp;
767
768 vp = sp->s_vnode = vn_alloc(kmflags);
769 if (vp == NULL) {
770 return (-1);
771 }
772 vn_setops(vp, spec_getvnodeops());
773 vp->v_data = sp;
774
775 mutex_init(&sp->s_lock, NULL, MUTEX_DEFAULT, NULL);
776 cv_init(&sp->s_cv, NULL, CV_DEFAULT, NULL);
777 return (0);
778 }
779
780 /*ARGSUSED1*/
781 static void
snode_destructor(void * buf,void * cdrarg)782 snode_destructor(void *buf, void *cdrarg)
783 {
784 struct snode *sp = buf;
785 struct vnode *vp = STOV(sp);
786
787 mutex_destroy(&sp->s_lock);
788 cv_destroy(&sp->s_cv);
789
790 vn_free(vp);
791 }
792
793
794 int
specinit(int fstype,char * name)795 specinit(int fstype, char *name)
796 {
797 static const fs_operation_def_t spec_vfsops_template[] = {
798 VFSNAME_SYNC, { .vfs_sync = spec_sync },
799 NULL, NULL
800 };
801 extern struct vnodeops *spec_vnodeops;
802 extern const fs_operation_def_t spec_vnodeops_template[];
803 struct vfsops *spec_vfsops;
804 int error;
805 dev_t dev;
806
807 /*
808 * Associate vfs and vnode operations.
809 */
810 error = vfs_setfsops(fstype, spec_vfsops_template, &spec_vfsops);
811 if (error != 0) {
812 cmn_err(CE_WARN, "specinit: bad vfs ops template");
813 return (error);
814 }
815
816 error = vn_make_ops(name, spec_vnodeops_template, &spec_vnodeops);
817 if (error != 0) {
818 (void) vfs_freevfsops_by_type(fstype);
819 cmn_err(CE_WARN, "specinit: bad vnode ops template");
820 return (error);
821 }
822
823 mutex_init(&stable_lock, NULL, MUTEX_DEFAULT, NULL);
824 mutex_init(&spec_syncbusy, NULL, MUTEX_DEFAULT, NULL);
825
826 /*
827 * Create snode cache
828 */
829 snode_cache = kmem_cache_create("snode_cache", sizeof (struct snode),
830 0, snode_constructor, snode_destructor, NULL, NULL, NULL, 0);
831
832 /*
833 * Associate vfs operations with spec_vfs
834 */
835 VFS_INIT(&spec_vfs, spec_vfsops, (caddr_t)NULL);
836 if ((dev = getudev()) == -1)
837 dev = 0;
838 specdev = makedevice(dev, 0);
839 return (0);
840 }
841
842 int
device_close(struct vnode * vp,int flag,struct cred * cr)843 device_close(struct vnode *vp, int flag, struct cred *cr)
844 {
845 struct snode *sp = VTOS(vp);
846 enum vtype type = vp->v_type;
847 struct vnode *cvp;
848 dev_t dev;
849 int error;
850
851 dev = sp->s_dev;
852 cvp = sp->s_commonvp;
853
854 switch (type) {
855
856 case VCHR:
857 if (vp->v_stream) {
858 if (cvp->v_stream != NULL)
859 error = strclose(cvp, flag, cr);
860 vp->v_stream = NULL;
861 } else
862 error = dev_close(dev, flag, OTYP_CHR, cr);
863 break;
864
865 case VBLK:
866 /*
867 * On last close a block device we must
868 * invalidate any in-core blocks so that we
869 * can, for example, change floppy disks.
870 */
871 (void) spec_putpage(cvp, (offset_t)0,
872 (size_t)0, B_INVAL|B_FORCE, cr, NULL);
873 bflush(dev);
874 binval(dev);
875 error = dev_close(dev, flag, OTYP_BLK, cr);
876 break;
877 default:
878 panic("device_close: not a device");
879 /*NOTREACHED*/
880 }
881
882 return (error);
883 }
884
885 struct vnode *
makectty(vnode_t * ovp)886 makectty(vnode_t *ovp)
887 {
888 vnode_t *vp;
889
890 if (vp = makespecvp(ovp->v_rdev, VCHR)) {
891 struct snode *sp;
892 struct snode *csp;
893 struct vnode *cvp;
894
895 sp = VTOS(vp);
896 cvp = sp->s_commonvp;
897 csp = VTOS(cvp);
898 mutex_enter(&csp->s_lock);
899 csp->s_count++;
900 mutex_exit(&csp->s_lock);
901 }
902
903 return (vp);
904 }
905
906 void
spec_snode_walk(int (* callback)(struct snode * sp,void * arg),void * arg)907 spec_snode_walk(int (*callback)(struct snode *sp, void *arg), void *arg)
908 {
909 struct snode *sp;
910 int i;
911
912 ASSERT(callback);
913
914 mutex_enter(&stable_lock);
915 for (i = 0; i < STABLESIZE; i++) {
916 for (sp = stable[i]; sp; sp = sp->s_next) {
917 if (callback(sp, arg) != DDI_WALK_CONTINUE)
918 goto out;
919 }
920 }
921 out:
922 mutex_exit(&stable_lock);
923 }
924
925 int
spec_is_clone(vnode_t * vp)926 spec_is_clone(vnode_t *vp)
927 {
928 struct snode *sp;
929
930 if (vn_matchops(vp, spec_getvnodeops())) {
931 sp = VTOS(vp);
932 return ((sp->s_flag & SCLONE) ? 1 : 0);
933 }
934
935 return (0);
936 }
937
938 int
spec_is_selfclone(vnode_t * vp)939 spec_is_selfclone(vnode_t *vp)
940 {
941 struct snode *sp;
942
943 if (vn_matchops(vp, spec_getvnodeops())) {
944 sp = VTOS(vp);
945 return ((sp->s_flag & SSELFCLONE) ? 1 : 0);
946 }
947
948 return (0);
949 }
950
951 /*
952 * We may be invoked with a NULL vp in which case we fence off
953 * all snodes associated with dip
954 */
955 int
spec_fence_snode(dev_info_t * dip,struct vnode * vp)956 spec_fence_snode(dev_info_t *dip, struct vnode *vp)
957 {
958 struct snode *sp;
959 struct snode *csp;
960 int retired;
961 int i;
962 char *path;
963 int emitted;
964
965 ASSERT(dip);
966
967 retired = 0;
968 mutex_enter(&DEVI(dip)->devi_lock);
969 if (DEVI(dip)->devi_flags & DEVI_RETIRED)
970 retired = 1;
971 mutex_exit(&DEVI(dip)->devi_lock);
972
973 if (!retired)
974 return (0);
975
976 path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
977 (void) ddi_pathname(dip, path);
978
979
980 if (vp != NULL) {
981 ASSERT(vn_matchops(vp, spec_getvnodeops()));
982 csp = VTOCS(vp);
983 ASSERT(csp);
984 mutex_enter(&csp->s_lock);
985 csp->s_flag |= SFENCED;
986 mutex_exit(&csp->s_lock);
987 FENDBG((CE_NOTE, "fenced off snode(%p) for dip: %s",
988 (void *)csp, path));
989 kmem_free(path, MAXPATHLEN);
990 return (0);
991 }
992
993 emitted = 0;
994 mutex_enter(&stable_lock);
995 for (i = 0; i < STABLESIZE; i++) {
996 for (sp = stable[i]; sp != NULL; sp = sp->s_next) {
997 ASSERT(sp->s_commonvp);
998 csp = VTOS(sp->s_commonvp);
999 if (csp->s_dip == dip) {
1000 /* fence off the common snode */
1001 mutex_enter(&csp->s_lock);
1002 csp->s_flag |= SFENCED;
1003 mutex_exit(&csp->s_lock);
1004 if (!emitted) {
1005 FENDBG((CE_NOTE, "fenced 1 of N"));
1006 emitted++;
1007 }
1008 }
1009 }
1010 }
1011 mutex_exit(&stable_lock);
1012
1013 FENDBG((CE_NOTE, "fenced off all snodes for dip: %s", path));
1014 kmem_free(path, MAXPATHLEN);
1015
1016 return (0);
1017 }
1018
1019
1020 int
spec_unfence_snode(dev_info_t * dip)1021 spec_unfence_snode(dev_info_t *dip)
1022 {
1023 struct snode *sp;
1024 struct snode *csp;
1025 int i;
1026 char *path;
1027 int emitted;
1028
1029 ASSERT(dip);
1030
1031 path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1032 (void) ddi_pathname(dip, path);
1033
1034 emitted = 0;
1035 mutex_enter(&stable_lock);
1036 for (i = 0; i < STABLESIZE; i++) {
1037 for (sp = stable[i]; sp != NULL; sp = sp->s_next) {
1038 ASSERT(sp->s_commonvp);
1039 csp = VTOS(sp->s_commonvp);
1040 ASSERT(csp);
1041 if (csp->s_dip == dip) {
1042 /* unfence the common snode */
1043 mutex_enter(&csp->s_lock);
1044 csp->s_flag &= ~SFENCED;
1045 mutex_exit(&csp->s_lock);
1046 if (!emitted) {
1047 FENDBG((CE_NOTE, "unfenced 1 of N"));
1048 emitted++;
1049 }
1050 }
1051 }
1052 }
1053 mutex_exit(&stable_lock);
1054
1055 FENDBG((CE_NOTE, "unfenced all snodes for dip: %s", path));
1056 kmem_free(path, MAXPATHLEN);
1057
1058 return (0);
1059 }
1060
1061 void
spec_size_invalidate(dev_t dev,vtype_t type)1062 spec_size_invalidate(dev_t dev, vtype_t type)
1063 {
1064
1065 struct snode *csp;
1066
1067 mutex_enter(&stable_lock);
1068 if ((csp = sfind(dev, type, NULL)) != NULL) {
1069 mutex_enter(&csp->s_lock);
1070 csp->s_flag &= ~SSIZEVALID;
1071 VN_RELE_ASYNC(STOV(csp), system_taskq);
1072 mutex_exit(&csp->s_lock);
1073 }
1074 mutex_exit(&stable_lock);
1075 }
1076