don't mark as a local filesystem
[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 *
196b7053 7 * @(#)spec_vnops.c 7.53 (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>
17c64659
KB
19#include <sys/stat.h>
20#include <sys/errno.h>
21#include <sys/ioctl.h>
22#include <sys/file.h>
23#include <sys/disklabel.h>
a798c07b 24#include <miscfs/specfs/specdev.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/*
196b7053 99 * Open a special file.
a1d35437 100 */
3d5d83ff 101/* ARGSUSED */
e2afbd7b
KM
102spec_open(ap)
103 struct vop_open_args /* {
104 struct vnode *a_vp;
105 int a_mode;
106 struct ucred *a_cred;
107 struct proc *a_p;
108 } */ *ap;
a1d35437 109{
196b7053
KM
110 struct vnode *bvp, *vp = ap->a_vp;
111 dev_t bdev, dev = (dev_t)vp->v_rdev;
a1d35437 112 register int maj = major(dev);
5b2e9327 113 int error;
a1d35437 114
196b7053
KM
115 /*
116 * Don't allow open if fs is mounted -nodev.
117 */
406c9a0d 118 if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
786053cd
KM
119 return (ENXIO);
120
406c9a0d 121 switch (vp->v_type) {
a1d35437
KM
122
123 case VCHR:
124 if ((u_int)maj >= nchrdev)
125 return (ENXIO);
196b7053
KM
126 if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) {
127 /*
128 * When running in very secure mode, do not allow
129 * opens for writing of any disk character devices.
130 */
131 if (securelevel >= 2 && isdisk(dev, VCHR))
132 return (EPERM);
133 /*
134 * When running in secure mode, do not allow opens
135 * for writing of /dev/mem, /dev/kmem, or character
136 * devices whose corresponding block devices are
137 * currently mounted.
138 */
139 if (securelevel >= 1) {
140 if ((bdev = chrtoblk(dev)) != NODEV &&
141 vfinddev(bdev, VBLK, &bvp) &&
142 bvp->v_usecount > 0 &&
143 (error = ufs_mountedon(bvp)))
144 return (error);
145 if (iskmemdev(dev))
146 return (EPERM);
147 }
148 }
406c9a0d 149 VOP_UNLOCK(vp);
e1b76915 150 error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p);
406c9a0d 151 VOP_LOCK(vp);
b3bf09c7 152 return (error);
a1d35437
KM
153
154 case VBLK:
155 if ((u_int)maj >= nblkdev)
156 return (ENXIO);
196b7053
KM
157 /*
158 * When running in very secure mode, do not allow
159 * opens for writing of any disk block devices.
160 */
161 if (securelevel >= 2 && ap->a_cred != FSCRED &&
162 (ap->a_mode & FWRITE) && isdisk(dev, VBLK))
163 return (EPERM);
164 /*
165 * Do not allow opens of block devices that are
166 * currently mounted.
167 */
406c9a0d 168 if (error = ufs_mountedon(vp))
5b2e9327 169 return (error);
e1b76915 170 return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p));
a1d35437
KM
171 }
172 return (0);
173}
174
a1d35437
KM
175/*
176 * Vnode op for read
177 */
fe6cdffe 178/* ARGSUSED */
e2afbd7b
KM
179spec_read(ap)
180 struct vop_read_args /* {
181 struct vnode *a_vp;
182 struct uio *a_uio;
183 int a_ioflag;
184 struct ucred *a_cred;
185 } */ *ap;
a1d35437 186{
406c9a0d
JH
187 register struct vnode *vp = ap->a_vp;
188 register struct uio *uio = ap->a_uio;
189 struct proc *p = uio->uio_procp;
7d4e5ac1 190 struct buf *bp;
2e4bbf7a 191 daddr_t bn, nextbn;
7d4e5ac1
KM
192 long bsize, bscale;
193 struct partinfo dpart;
194 register int n, on;
195 int error = 0;
a1d35437 196
68a834b0 197#ifdef DIAGNOSTIC
406c9a0d 198 if (uio->uio_rw != UIO_READ)
43444338 199 panic("spec_read mode");
406c9a0d 200 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
68a834b0
KM
201 panic("spec_read proc");
202#endif
406c9a0d 203 if (uio->uio_resid == 0)
43444338 204 return (0);
43444338 205
406c9a0d 206 switch (vp->v_type) {
43444338
KM
207
208 case VCHR:
406c9a0d
JH
209 VOP_UNLOCK(vp);
210 error = (*cdevsw[major(vp->v_rdev)].d_read)
211 (vp->v_rdev, uio, ap->a_ioflag);
212 VOP_LOCK(vp);
43444338
KM
213 return (error);
214
215 case VBLK:
406c9a0d 216 if (uio->uio_offset < 0)
43444338 217 return (EINVAL);
7d4e5ac1 218 bsize = BLKDEV_IOSIZE;
406c9a0d 219 if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
8429d022 220 (caddr_t)&dpart, FREAD, p) == 0) {
7d4e5ac1
KM
221 if (dpart.part->p_fstype == FS_BSDFFS &&
222 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
223 bsize = dpart.part->p_frag *
224 dpart.part->p_fsize;
225 }
226 bscale = bsize / DEV_BSIZE;
227 do {
406c9a0d
JH
228 bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
229 on = uio->uio_offset % bsize;
48c77711 230 n = min((unsigned)(bsize - on), uio->uio_resid);
406c9a0d 231 if (vp->v_lastr + bscale == bn) {
2e4bbf7a 232 nextbn = bn + bscale;
406c9a0d 233 error = breadn(vp, bn, (int)bsize, &nextbn,
2e4bbf7a
KM
234 (int *)&bsize, 1, NOCRED, &bp);
235 } else
406c9a0d
JH
236 error = bread(vp, bn, (int)bsize, NOCRED, &bp);
237 vp->v_lastr = bn;
48c77711 238 n = min(n, bsize - bp->b_resid);
7d4e5ac1
KM
239 if (error) {
240 brelse(bp);
241 return (error);
242 }
406c9a0d 243 error = uiomove(bp->b_un.b_addr + on, n, uio);
7d4e5ac1
KM
244 if (n + on == bsize)
245 bp->b_flags |= B_AGE;
246 brelse(bp);
406c9a0d 247 } while (error == 0 && uio->uio_resid > 0 && n != 0);
7d4e5ac1 248 return (error);
43444338
KM
249
250 default:
251 panic("spec_read type");
252 }
253 /* NOTREACHED */
a1d35437
KM
254}
255
256/*
257 * Vnode op for write
258 */
fe6cdffe 259/* ARGSUSED */
e2afbd7b
KM
260spec_write(ap)
261 struct vop_write_args /* {
262 struct vnode *a_vp;
263 struct uio *a_uio;
264 int a_ioflag;
265 struct ucred *a_cred;
266 } */ *ap;
a1d35437 267{
406c9a0d
JH
268 register struct vnode *vp = ap->a_vp;
269 register struct uio *uio = ap->a_uio;
270 struct proc *p = uio->uio_procp;
7d4e5ac1
KM
271 struct buf *bp;
272 daddr_t bn;
273 int bsize, blkmask;
274 struct partinfo dpart;
9db58063
KM
275 register int n, on;
276 int error = 0;
a1d35437 277
68a834b0 278#ifdef DIAGNOSTIC
406c9a0d 279 if (uio->uio_rw != UIO_WRITE)
43444338 280 panic("spec_write mode");
406c9a0d 281 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
68a834b0
KM
282 panic("spec_write proc");
283#endif
43444338 284
406c9a0d 285 switch (vp->v_type) {
43444338
KM
286
287 case VCHR:
406c9a0d
JH
288 VOP_UNLOCK(vp);
289 error = (*cdevsw[major(vp->v_rdev)].d_write)
290 (vp->v_rdev, uio, ap->a_ioflag);
291 VOP_LOCK(vp);
43444338
KM
292 return (error);
293
294 case VBLK:
406c9a0d 295 if (uio->uio_resid == 0)
43444338 296 return (0);
406c9a0d 297 if (uio->uio_offset < 0)
43444338 298 return (EINVAL);
7d4e5ac1 299 bsize = BLKDEV_IOSIZE;
406c9a0d 300 if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
8429d022 301 (caddr_t)&dpart, FREAD, p) == 0) {
7d4e5ac1
KM
302 if (dpart.part->p_fstype == FS_BSDFFS &&
303 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
304 bsize = dpart.part->p_frag *
305 dpart.part->p_fsize;
306 }
307 blkmask = (bsize / DEV_BSIZE) - 1;
308 do {
406c9a0d
JH
309 bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
310 on = uio->uio_offset % bsize;
48c77711 311 n = min((unsigned)(bsize - on), uio->uio_resid);
7d4e5ac1 312 if (n == bsize)
c74a8e8b 313 bp = getblk(vp, bn, bsize, 0, 0);
7d4e5ac1 314 else
406c9a0d 315 error = bread(vp, bn, bsize, NOCRED, &bp);
48c77711 316 n = min(n, bsize - bp->b_resid);
7d4e5ac1
KM
317 if (error) {
318 brelse(bp);
319 return (error);
320 }
406c9a0d 321 error = uiomove(bp->b_un.b_addr + on, n, uio);
7d4e5ac1
KM
322 if (n + on == bsize) {
323 bp->b_flags |= B_AGE;
324 bawrite(bp);
325 } else
326 bdwrite(bp);
406c9a0d 327 } while (error == 0 && uio->uio_resid > 0 && n != 0);
7d4e5ac1 328 return (error);
43444338
KM
329
330 default:
331 panic("spec_write type");
332 }
333 /* NOTREACHED */
a1d35437
KM
334}
335
336/*
337 * Device ioctl operation.
338 */
3d5d83ff 339/* ARGSUSED */
e2afbd7b
KM
340spec_ioctl(ap)
341 struct vop_ioctl_args /* {
342 struct vnode *a_vp;
343 int a_command;
344 caddr_t a_data;
345 int a_fflag;
346 struct ucred *a_cred;
347 struct proc *a_p;
348 } */ *ap;
a1d35437 349{
e1b76915 350 dev_t dev = ap->a_vp->v_rdev;
a1d35437 351
e1b76915 352 switch (ap->a_vp->v_type) {
a1d35437
KM
353
354 case VCHR:
e1b76915
JH
355 return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
356 ap->a_fflag, ap->a_p));
a1d35437
KM
357
358 case VBLK:
e1b76915 359 if (ap->a_command == 0 && (int)ap->a_data == B_TAPE)
b9a4d0ff
KM
360 if (bdevsw[major(dev)].d_flags & B_TAPE)
361 return (0);
362 else
363 return (1);
e1b76915
JH
364 return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
365 ap->a_fflag, ap->a_p));
a1d35437
KM
366
367 default:
ad27f720 368 panic("spec_ioctl");
a1d35437
KM
369 /* NOTREACHED */
370 }
371}
372
3d5d83ff 373/* ARGSUSED */
e2afbd7b
KM
374spec_select(ap)
375 struct vop_select_args /* {
376 struct vnode *a_vp;
377 int a_which;
378 int a_fflags;
379 struct ucred *a_cred;
380 struct proc *a_p;
381 } */ *ap;
a1d35437 382{
a1d35437
KM
383 register dev_t dev;
384
e1b76915 385 switch (ap->a_vp->v_type) {
a1d35437
KM
386
387 default:
388 return (1); /* XXX */
389
390 case VCHR:
e1b76915
JH
391 dev = ap->a_vp->v_rdev;
392 return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p);
a1d35437
KM
393 }
394}
e2afbd7b
KM
395/*
396 * Synch buffers associated with a block device
397 */
398/* ARGSUSED */
399int
400spec_fsync(ap)
401 struct vop_fsync_args /* {
402 struct vnode *a_vp;
403 struct ucred *a_cred;
404 int a_waitfor;
405 struct proc *a_p;
406 } */ *ap;
407{
408 register struct vnode *vp = ap->a_vp;
409 register struct buf *bp;
410 struct buf *nbp;
a376c42f 411 int s;
e2afbd7b
KM
412
413 if (vp->v_type == VCHR)
414 return (0);
415 /*
416 * Flush all dirty buffers associated with a block device.
417 */
418loop:
419 s = splbio();
243083d2
KM
420 for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) {
421 nbp = bp->b_vnbufs.qe_next;
e2afbd7b
KM
422 if ((bp->b_flags & B_BUSY))
423 continue;
424 if ((bp->b_flags & B_DELWRI) == 0)
425 panic("spec_fsync: not dirty");
426 bremfree(bp);
427 bp->b_flags |= B_BUSY;
428 splx(s);
a376c42f 429 bawrite(bp);
e2afbd7b
KM
430 goto loop;
431 }
432 if (ap->a_waitfor == MNT_WAIT) {
433 while (vp->v_numoutput) {
434 vp->v_flag |= VBWAIT;
435 sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
436 }
437#ifdef DIAGNOSTIC
243083d2 438 if (vp->v_dirtyblkhd.le_next) {
e2afbd7b
KM
439 vprint("spec_fsync: dirty", vp);
440 goto loop;
441 }
442#endif
443 }
444 splx(s);
a376c42f 445 return (0);
e2afbd7b 446}
a1d35437
KM
447
448/*
449 * Just call the device strategy routine
450 */
e2afbd7b
KM
451spec_strategy(ap)
452 struct vop_strategy_args /* {
453 struct buf *a_bp;
454 } */ *ap;
a1d35437 455{
b9a4d0ff 456
e1b76915 457 (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp);
a1d35437
KM
458 return (0);
459}
460
b9a4d0ff
KM
461/*
462 * This is a noop, simply returning what one has been given.
463 */
e2afbd7b
KM
464spec_bmap(ap)
465 struct vop_bmap_args /* {
466 struct vnode *a_vp;
467 daddr_t a_bn;
468 struct vnode **a_vpp;
469 daddr_t *a_bnp;
470 } */ *ap;
b9a4d0ff
KM
471{
472
e1b76915
JH
473 if (ap->a_vpp != NULL)
474 *ap->a_vpp = ap->a_vp;
475 if (ap->a_bnp != NULL)
476 *ap->a_bnp = ap->a_bn;
b9a4d0ff
KM
477 return (0);
478}
479
1c00bf64
KM
480/*
481 * At the moment we do not do any locking.
482 */
ff4fb102 483/* ARGSUSED */
e2afbd7b
KM
484spec_lock(ap)
485 struct vop_lock_args /* {
486 struct vnode *a_vp;
487 } */ *ap;
a1d35437 488{
a1d35437 489
a1d35437
KM
490 return (0);
491}
492
ff4fb102 493/* ARGSUSED */
e2afbd7b
KM
494spec_unlock(ap)
495 struct vop_unlock_args /* {
496 struct vnode *a_vp;
497 } */ *ap;
a1d35437 498{
a1d35437 499
a1d35437
KM
500 return (0);
501}
502
a1d35437
KM
503/*
504 * Device close routine
505 */
3d5d83ff 506/* ARGSUSED */
e2afbd7b
KM
507spec_close(ap)
508 struct vop_close_args /* {
509 struct vnode *a_vp;
510 int a_fflag;
511 struct ucred *a_cred;
512 struct proc *a_p;
513 } */ *ap;
a1d35437 514{
406c9a0d
JH
515 register struct vnode *vp = ap->a_vp;
516 dev_t dev = vp->v_rdev;
e15ce6a3 517 int (*devclose) __P((dev_t, int, int, struct proc *));
e2afbd7b 518 int mode, error;
a1d35437 519
406c9a0d 520 switch (vp->v_type) {
3d5d83ff
KM
521
522 case VCHR:
f4b3ea62
KM
523 /*
524 * If the vnode is locked, then we are in the midst
525 * of forcably closing the device, otherwise we only
526 * close on last reference.
527 */
406c9a0d 528 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
3d5d83ff 529 return (0);
e15ce6a3 530 devclose = cdevsw[major(dev)].d_close;
1c00bf64 531 mode = S_IFCHR;
3d5d83ff
KM
532 break;
533
534 case VBLK:
535 /*
536 * On last close of a block device (that isn't mounted)
537 * we must invalidate any in core blocks, so that
538 * we can, for instance, change floppy disks.
539 */
c74a8e8b 540 if (error = vinvalbuf(vp, 1, ap->a_cred, ap->a_p, 0, 0))
e2afbd7b 541 return (error);
3d5d83ff 542 /*
f4b3ea62
KM
543 * We do not want to really close the device if it
544 * is still in use unless we are trying to close it
545 * forcibly. Since every use (buffer, vnode, swap, cmap)
3ab57521
KM
546 * holds a reference to the vnode, and because we mark
547 * any other vnodes that alias this device, when the
548 * sum of the reference counts on all the aliased
549 * vnodes descends to one, we are on last close.
3d5d83ff 550 */
406c9a0d 551 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
3d5d83ff 552 return (0);
e15ce6a3 553 devclose = bdevsw[major(dev)].d_close;
1c00bf64 554 mode = S_IFBLK;
3d5d83ff
KM
555 break;
556
557 default:
ad27f720 558 panic("spec_close: not special");
3d5d83ff
KM
559 }
560
e1b76915 561 return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p));
a1d35437
KM
562}
563
b9a4d0ff
KM
564/*
565 * Print out the contents of a special device vnode.
566 */
e2afbd7b
KM
567spec_print(ap)
568 struct vop_print_args /* {
569 struct vnode *a_vp;
570 } */ *ap;
b9a4d0ff
KM
571{
572
e1b76915
JH
573 printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev),
574 minor(ap->a_vp->v_rdev));
b9a4d0ff
KM
575}
576
a4128336
KM
577/*
578 * Special device advisory byte-level locks.
579 */
68a834b0 580/* ARGSUSED */
e2afbd7b
KM
581spec_advlock(ap)
582 struct vop_advlock_args /* {
583 struct vnode *a_vp;
584 caddr_t a_id;
585 int a_op;
586 struct flock *a_fl;
587 int a_flags;
588 } */ *ap;
a4128336
KM
589{
590
591 return (EOPNOTSUPP);
592}
593
a1d35437 594/*
7bbe72a5
KM
595 * Special device failed operation
596 */
597spec_ebadf()
598{
599
600 return (EBADF);
601}
602
603/*
604 * Special device bad operation
a1d35437 605 */
ad27f720 606spec_badop()
a1d35437
KM
607{
608
ad27f720 609 panic("spec_badop called");
59b0713e 610 /* NOTREACHED */
a1d35437 611}