move to rev 7; new include location; syntax niggles
[unix-history] / usr / src / sys / miscfs / specfs / spec_vnops.c
CommitLineData
a1d35437
KM
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
dbf0c423 5 * %sccs.include.redist.c%
a1d35437 6 *
cf275db0 7 * @(#)spec_vnops.c 7.47 (Berkeley) %G%
a1d35437
KM
8 */
9
17c64659
KB
10#include <sys/param.h>
11#include <sys/proc.h>
12#include <sys/systm.h>
13#include <sys/kernel.h>
14#include <sys/conf.h>
15#include <sys/buf.h>
16#include <sys/mount.h>
17#include <sys/namei.h>
18#include <sys/vnode.h>
19#include <sys/specdev.h>
20#include <sys/stat.h>
21#include <sys/errno.h>
22#include <sys/ioctl.h>
23#include <sys/file.h>
24#include <sys/disklabel.h>
a1d35437 25
ccee3c59
MK
26/* symbolic sleep message strings for devices */
27char devopn[] = "devopn";
28char devio[] = "devio";
29char devwait[] = "devwait";
30char devin[] = "devin";
31char devout[] = "devout";
32char devioc[] = "devioc";
33char devcls[] = "devcls";
34
9342689a
JH
35int (**spec_vnodeop_p)();
36struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
37 { &vop_default_desc, vn_default_error },
38 { &vop_lookup_desc, spec_lookup }, /* lookup */
39 { &vop_create_desc, spec_create }, /* create */
40 { &vop_mknod_desc, spec_mknod }, /* mknod */
41 { &vop_open_desc, spec_open }, /* open */
42 { &vop_close_desc, spec_close }, /* close */
43 { &vop_access_desc, spec_access }, /* access */
44 { &vop_getattr_desc, spec_getattr }, /* getattr */
45 { &vop_setattr_desc, spec_setattr }, /* setattr */
46 { &vop_read_desc, spec_read }, /* read */
47 { &vop_write_desc, spec_write }, /* write */
48 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
49 { &vop_select_desc, spec_select }, /* select */
50 { &vop_mmap_desc, spec_mmap }, /* mmap */
51 { &vop_fsync_desc, spec_fsync }, /* fsync */
52 { &vop_seek_desc, spec_seek }, /* seek */
53 { &vop_remove_desc, spec_remove }, /* remove */
54 { &vop_link_desc, spec_link }, /* link */
55 { &vop_rename_desc, spec_rename }, /* rename */
56 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
57 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
58 { &vop_symlink_desc, spec_symlink }, /* symlink */
59 { &vop_readdir_desc, spec_readdir }, /* readdir */
60 { &vop_readlink_desc, spec_readlink }, /* readlink */
61 { &vop_abortop_desc, spec_abortop }, /* abortop */
62 { &vop_inactive_desc, spec_inactive }, /* inactive */
63 { &vop_reclaim_desc, spec_reclaim }, /* reclaim */
64 { &vop_lock_desc, spec_lock }, /* lock */
65 { &vop_unlock_desc, spec_unlock }, /* unlock */
66 { &vop_bmap_desc, spec_bmap }, /* bmap */
67 { &vop_strategy_desc, spec_strategy }, /* strategy */
68 { &vop_print_desc, spec_print }, /* print */
69 { &vop_islocked_desc, spec_islocked }, /* islocked */
70 { &vop_advlock_desc, spec_advlock }, /* advlock */
71 { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */
9342689a
JH
72 { &vop_valloc_desc, spec_valloc }, /* valloc */
73 { &vop_vfree_desc, spec_vfree }, /* vfree */
74 { &vop_truncate_desc, spec_truncate }, /* truncate */
75 { &vop_update_desc, spec_update }, /* update */
76 { &vop_bwrite_desc, spec_bwrite }, /* bwrite */
77 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
a1d35437 78};
9342689a
JH
79struct vnodeopv_desc spec_vnodeop_opv_desc =
80 { &spec_vnodeop_p, spec_vnodeop_entries };
a1d35437 81
59b0713e
KM
82/*
83 * Trivial lookup routine that always fails.
84 */
6ee99c46 85int
e2afbd7b
KM
86spec_lookup(ap)
87 struct vop_lookup_args /* {
88 struct vnode *a_dvp;
89 struct vnode **a_vpp;
90 struct componentname *a_cnp;
91 } */ *ap;
59b0713e
KM
92{
93
e1b76915 94 *ap->a_vpp = NULL;
59b0713e
KM
95 return (ENOTDIR);
96}
97
a1d35437 98/*
e15ce6a3
MK
99 * Open a special file: Don't allow open if fs is mounted -nodev,
100 * and don't allow opens of block devices that are currently mounted.
101 * Otherwise, call device driver open function.
a1d35437 102 */
3d5d83ff 103/* ARGSUSED */
e2afbd7b
KM
104spec_open(ap)
105 struct vop_open_args /* {
106 struct vnode *a_vp;
107 int a_mode;
108 struct ucred *a_cred;
109 struct proc *a_p;
110 } */ *ap;
a1d35437 111{
406c9a0d
JH
112 register struct vnode *vp = ap->a_vp;
113 dev_t dev = (dev_t)vp->v_rdev;
a1d35437 114 register int maj = major(dev);
5b2e9327 115 int error;
a1d35437 116
406c9a0d 117 if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
786053cd
KM
118 return (ENXIO);
119
406c9a0d 120 switch (vp->v_type) {
a1d35437
KM
121
122 case VCHR:
123 if ((u_int)maj >= nchrdev)
124 return (ENXIO);
406c9a0d 125 VOP_UNLOCK(vp);
e1b76915 126 error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p);
406c9a0d 127 VOP_LOCK(vp);
b3bf09c7 128 return (error);
a1d35437
KM
129
130 case VBLK:
131 if ((u_int)maj >= nblkdev)
132 return (ENXIO);
406c9a0d 133 if (error = ufs_mountedon(vp))
5b2e9327 134 return (error);
e1b76915 135 return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p));
a1d35437
KM
136 }
137 return (0);
138}
139
a1d35437
KM
140/*
141 * Vnode op for read
142 */
fe6cdffe 143/* ARGSUSED */
e2afbd7b
KM
144spec_read(ap)
145 struct vop_read_args /* {
146 struct vnode *a_vp;
147 struct uio *a_uio;
148 int a_ioflag;
149 struct ucred *a_cred;
150 } */ *ap;
a1d35437 151{
406c9a0d
JH
152 register struct vnode *vp = ap->a_vp;
153 register struct uio *uio = ap->a_uio;
154 struct proc *p = uio->uio_procp;
7d4e5ac1 155 struct buf *bp;
2e4bbf7a 156 daddr_t bn, nextbn;
7d4e5ac1
KM
157 long bsize, bscale;
158 struct partinfo dpart;
159 register int n, on;
160 int error = 0;
a1d35437 161
68a834b0 162#ifdef DIAGNOSTIC
406c9a0d 163 if (uio->uio_rw != UIO_READ)
43444338 164 panic("spec_read mode");
406c9a0d 165 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
68a834b0
KM
166 panic("spec_read proc");
167#endif
406c9a0d 168 if (uio->uio_resid == 0)
43444338 169 return (0);
43444338 170
406c9a0d 171 switch (vp->v_type) {
43444338
KM
172
173 case VCHR:
406c9a0d
JH
174 VOP_UNLOCK(vp);
175 error = (*cdevsw[major(vp->v_rdev)].d_read)
176 (vp->v_rdev, uio, ap->a_ioflag);
177 VOP_LOCK(vp);
43444338
KM
178 return (error);
179
180 case VBLK:
406c9a0d 181 if (uio->uio_offset < 0)
43444338 182 return (EINVAL);
7d4e5ac1 183 bsize = BLKDEV_IOSIZE;
406c9a0d 184 if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
8429d022 185 (caddr_t)&dpart, FREAD, p) == 0) {
7d4e5ac1
KM
186 if (dpart.part->p_fstype == FS_BSDFFS &&
187 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
188 bsize = dpart.part->p_frag *
189 dpart.part->p_fsize;
190 }
191 bscale = bsize / DEV_BSIZE;
192 do {
406c9a0d
JH
193 bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
194 on = uio->uio_offset % bsize;
195 n = MIN((unsigned)(bsize - on), uio->uio_resid);
196 if (vp->v_lastr + bscale == bn) {
2e4bbf7a 197 nextbn = bn + bscale;
406c9a0d 198 error = breadn(vp, bn, (int)bsize, &nextbn,
2e4bbf7a
KM
199 (int *)&bsize, 1, NOCRED, &bp);
200 } else
406c9a0d
JH
201 error = bread(vp, bn, (int)bsize, NOCRED, &bp);
202 vp->v_lastr = bn;
7d4e5ac1
KM
203 n = MIN(n, bsize - bp->b_resid);
204 if (error) {
205 brelse(bp);
206 return (error);
207 }
406c9a0d 208 error = uiomove(bp->b_un.b_addr + on, n, uio);
7d4e5ac1
KM
209 if (n + on == bsize)
210 bp->b_flags |= B_AGE;
211 brelse(bp);
406c9a0d 212 } while (error == 0 && uio->uio_resid > 0 && n != 0);
7d4e5ac1 213 return (error);
43444338
KM
214
215 default:
216 panic("spec_read type");
217 }
218 /* NOTREACHED */
a1d35437
KM
219}
220
221/*
222 * Vnode op for write
223 */
fe6cdffe 224/* ARGSUSED */
e2afbd7b
KM
225spec_write(ap)
226 struct vop_write_args /* {
227 struct vnode *a_vp;
228 struct uio *a_uio;
229 int a_ioflag;
230 struct ucred *a_cred;
231 } */ *ap;
a1d35437 232{
406c9a0d
JH
233 register struct vnode *vp = ap->a_vp;
234 register struct uio *uio = ap->a_uio;
235 struct proc *p = uio->uio_procp;
7d4e5ac1
KM
236 struct buf *bp;
237 daddr_t bn;
238 int bsize, blkmask;
239 struct partinfo dpart;
9db58063
KM
240 register int n, on;
241 int error = 0;
a1d35437 242
68a834b0 243#ifdef DIAGNOSTIC
406c9a0d 244 if (uio->uio_rw != UIO_WRITE)
43444338 245 panic("spec_write mode");
406c9a0d 246 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
68a834b0
KM
247 panic("spec_write proc");
248#endif
43444338 249
406c9a0d 250 switch (vp->v_type) {
43444338
KM
251
252 case VCHR:
406c9a0d
JH
253 VOP_UNLOCK(vp);
254 error = (*cdevsw[major(vp->v_rdev)].d_write)
255 (vp->v_rdev, uio, ap->a_ioflag);
256 VOP_LOCK(vp);
43444338
KM
257 return (error);
258
259 case VBLK:
406c9a0d 260 if (uio->uio_resid == 0)
43444338 261 return (0);
406c9a0d 262 if (uio->uio_offset < 0)
43444338 263 return (EINVAL);
7d4e5ac1 264 bsize = BLKDEV_IOSIZE;
406c9a0d 265 if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
8429d022 266 (caddr_t)&dpart, FREAD, p) == 0) {
7d4e5ac1
KM
267 if (dpart.part->p_fstype == FS_BSDFFS &&
268 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
269 bsize = dpart.part->p_frag *
270 dpart.part->p_fsize;
271 }
272 blkmask = (bsize / DEV_BSIZE) - 1;
273 do {
406c9a0d
JH
274 bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
275 on = uio->uio_offset % bsize;
276 n = MIN((unsigned)(bsize - on), uio->uio_resid);
7d4e5ac1 277 if (n == bsize)
406c9a0d 278 bp = getblk(vp, bn, bsize);
7d4e5ac1 279 else
406c9a0d 280 error = bread(vp, bn, bsize, NOCRED, &bp);
7d4e5ac1
KM
281 n = MIN(n, bsize - bp->b_resid);
282 if (error) {
283 brelse(bp);
284 return (error);
285 }
406c9a0d 286 error = uiomove(bp->b_un.b_addr + on, n, uio);
7d4e5ac1
KM
287 if (n + on == bsize) {
288 bp->b_flags |= B_AGE;
289 bawrite(bp);
290 } else
291 bdwrite(bp);
406c9a0d 292 } while (error == 0 && uio->uio_resid > 0 && n != 0);
7d4e5ac1 293 return (error);
43444338
KM
294
295 default:
296 panic("spec_write type");
297 }
298 /* NOTREACHED */
a1d35437
KM
299}
300
301/*
302 * Device ioctl operation.
303 */
3d5d83ff 304/* ARGSUSED */
e2afbd7b
KM
305spec_ioctl(ap)
306 struct vop_ioctl_args /* {
307 struct vnode *a_vp;
308 int a_command;
309 caddr_t a_data;
310 int a_fflag;
311 struct ucred *a_cred;
312 struct proc *a_p;
313 } */ *ap;
a1d35437 314{
e1b76915 315 dev_t dev = ap->a_vp->v_rdev;
a1d35437 316
e1b76915 317 switch (ap->a_vp->v_type) {
a1d35437
KM
318
319 case VCHR:
e1b76915
JH
320 return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
321 ap->a_fflag, ap->a_p));
a1d35437
KM
322
323 case VBLK:
e1b76915 324 if (ap->a_command == 0 && (int)ap->a_data == B_TAPE)
b9a4d0ff
KM
325 if (bdevsw[major(dev)].d_flags & B_TAPE)
326 return (0);
327 else
328 return (1);
e1b76915
JH
329 return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
330 ap->a_fflag, ap->a_p));
a1d35437
KM
331
332 default:
ad27f720 333 panic("spec_ioctl");
a1d35437
KM
334 /* NOTREACHED */
335 }
336}
337
3d5d83ff 338/* ARGSUSED */
e2afbd7b
KM
339spec_select(ap)
340 struct vop_select_args /* {
341 struct vnode *a_vp;
342 int a_which;
343 int a_fflags;
344 struct ucred *a_cred;
345 struct proc *a_p;
346 } */ *ap;
a1d35437 347{
a1d35437
KM
348 register dev_t dev;
349
e1b76915 350 switch (ap->a_vp->v_type) {
a1d35437
KM
351
352 default:
353 return (1); /* XXX */
354
355 case VCHR:
e1b76915
JH
356 dev = ap->a_vp->v_rdev;
357 return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p);
a1d35437
KM
358 }
359}
e2afbd7b
KM
360/*
361 * Synch buffers associated with a block device
362 */
363/* ARGSUSED */
364int
365spec_fsync(ap)
366 struct vop_fsync_args /* {
367 struct vnode *a_vp;
368 struct ucred *a_cred;
369 int a_waitfor;
370 struct proc *a_p;
371 } */ *ap;
372{
373 register struct vnode *vp = ap->a_vp;
374 register struct buf *bp;
375 struct buf *nbp;
376 int s, error, allerror = 0;
377
378 if (vp->v_type == VCHR)
379 return (0);
380 /*
381 * Flush all dirty buffers associated with a block device.
382 */
383loop:
384 s = splbio();
385 for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
386 nbp = bp->b_blockf;
387 if ((bp->b_flags & B_BUSY))
388 continue;
389 if ((bp->b_flags & B_DELWRI) == 0)
390 panic("spec_fsync: not dirty");
391 bremfree(bp);
392 bp->b_flags |= B_BUSY;
393 splx(s);
394 if (error = bawrite(bp))
395 allerror = error;
396 goto loop;
397 }
398 if (ap->a_waitfor == MNT_WAIT) {
399 while (vp->v_numoutput) {
400 vp->v_flag |= VBWAIT;
401 sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
402 }
403#ifdef DIAGNOSTIC
404 if (vp->v_dirtyblkhd) {
405 vprint("spec_fsync: dirty", vp);
406 goto loop;
407 }
408#endif
409 }
410 splx(s);
411 return (allerror);
412}
a1d35437
KM
413
414/*
415 * Just call the device strategy routine
416 */
e2afbd7b
KM
417spec_strategy(ap)
418 struct vop_strategy_args /* {
419 struct buf *a_bp;
420 } */ *ap;
a1d35437 421{
b9a4d0ff 422
e1b76915 423 (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp);
a1d35437
KM
424 return (0);
425}
426
b9a4d0ff
KM
427/*
428 * This is a noop, simply returning what one has been given.
429 */
e2afbd7b
KM
430spec_bmap(ap)
431 struct vop_bmap_args /* {
432 struct vnode *a_vp;
433 daddr_t a_bn;
434 struct vnode **a_vpp;
435 daddr_t *a_bnp;
436 } */ *ap;
b9a4d0ff
KM
437{
438
e1b76915
JH
439 if (ap->a_vpp != NULL)
440 *ap->a_vpp = ap->a_vp;
441 if (ap->a_bnp != NULL)
442 *ap->a_bnp = ap->a_bn;
b9a4d0ff
KM
443 return (0);
444}
445
1c00bf64
KM
446/*
447 * At the moment we do not do any locking.
448 */
ff4fb102 449/* ARGSUSED */
e2afbd7b
KM
450spec_lock(ap)
451 struct vop_lock_args /* {
452 struct vnode *a_vp;
453 } */ *ap;
a1d35437 454{
a1d35437 455
a1d35437
KM
456 return (0);
457}
458
ff4fb102 459/* ARGSUSED */
e2afbd7b
KM
460spec_unlock(ap)
461 struct vop_unlock_args /* {
462 struct vnode *a_vp;
463 } */ *ap;
a1d35437 464{
a1d35437 465
a1d35437
KM
466 return (0);
467}
468
a1d35437
KM
469/*
470 * Device close routine
471 */
3d5d83ff 472/* ARGSUSED */
e2afbd7b
KM
473spec_close(ap)
474 struct vop_close_args /* {
475 struct vnode *a_vp;
476 int a_fflag;
477 struct ucred *a_cred;
478 struct proc *a_p;
479 } */ *ap;
a1d35437 480{
406c9a0d
JH
481 register struct vnode *vp = ap->a_vp;
482 dev_t dev = vp->v_rdev;
e15ce6a3 483 int (*devclose) __P((dev_t, int, int, struct proc *));
e2afbd7b 484 int mode, error;
a1d35437 485
406c9a0d 486 switch (vp->v_type) {
3d5d83ff
KM
487
488 case VCHR:
f4b3ea62
KM
489 /*
490 * If the vnode is locked, then we are in the midst
491 * of forcably closing the device, otherwise we only
492 * close on last reference.
493 */
406c9a0d 494 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
3d5d83ff 495 return (0);
e15ce6a3 496 devclose = cdevsw[major(dev)].d_close;
1c00bf64 497 mode = S_IFCHR;
3d5d83ff
KM
498 break;
499
500 case VBLK:
501 /*
502 * On last close of a block device (that isn't mounted)
503 * we must invalidate any in core blocks, so that
504 * we can, for instance, change floppy disks.
505 */
e2afbd7b
KM
506 if (error = vinvalbuf(vp, 1, ap->a_cred, ap->a_p))
507 return (error);
3d5d83ff 508 /*
f4b3ea62
KM
509 * We do not want to really close the device if it
510 * is still in use unless we are trying to close it
511 * forcibly. Since every use (buffer, vnode, swap, cmap)
3ab57521
KM
512 * holds a reference to the vnode, and because we mark
513 * any other vnodes that alias this device, when the
514 * sum of the reference counts on all the aliased
515 * vnodes descends to one, we are on last close.
3d5d83ff 516 */
406c9a0d 517 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
3d5d83ff 518 return (0);
e15ce6a3 519 devclose = bdevsw[major(dev)].d_close;
1c00bf64 520 mode = S_IFBLK;
3d5d83ff
KM
521 break;
522
523 default:
ad27f720 524 panic("spec_close: not special");
3d5d83ff
KM
525 }
526
e1b76915 527 return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p));
a1d35437
KM
528}
529
b9a4d0ff
KM
530/*
531 * Print out the contents of a special device vnode.
532 */
e2afbd7b
KM
533spec_print(ap)
534 struct vop_print_args /* {
535 struct vnode *a_vp;
536 } */ *ap;
b9a4d0ff
KM
537{
538
e1b76915
JH
539 printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev),
540 minor(ap->a_vp->v_rdev));
b9a4d0ff
KM
541}
542
a4128336
KM
543/*
544 * Special device advisory byte-level locks.
545 */
68a834b0 546/* ARGSUSED */
e2afbd7b
KM
547spec_advlock(ap)
548 struct vop_advlock_args /* {
549 struct vnode *a_vp;
550 caddr_t a_id;
551 int a_op;
552 struct flock *a_fl;
553 int a_flags;
554 } */ *ap;
a4128336
KM
555{
556
557 return (EOPNOTSUPP);
558}
559
a1d35437 560/*
7bbe72a5
KM
561 * Special device failed operation
562 */
563spec_ebadf()
564{
565
566 return (EBADF);
567}
568
569/*
570 * Special device bad operation
a1d35437 571 */
ad27f720 572spec_badop()
a1d35437
KM
573{
574
ad27f720 575 panic("spec_badop called");
59b0713e 576 /* NOTREACHED */
a1d35437 577}