137486Smckusick /*
268234Spendry * Copyright (c) 1989, 1993, 1995
363247Sbostic * The Regents of the University of California. All rights reserved.
437486Smckusick *
544443Sbostic * %sccs.include.redist.c%
637486Smckusick *
7*69597Smckusick * @(#)spec_vnops.c 8.14 (Berkeley) 05/21/95
837486Smckusick */
937486Smckusick
1051457Sbostic #include <sys/param.h>
1151457Sbostic #include <sys/proc.h>
1251457Sbostic #include <sys/systm.h>
1351457Sbostic #include <sys/kernel.h>
1451457Sbostic #include <sys/conf.h>
1551457Sbostic #include <sys/buf.h>
1651457Sbostic #include <sys/mount.h>
1751457Sbostic #include <sys/namei.h>
1851457Sbostic #include <sys/vnode.h>
1951457Sbostic #include <sys/stat.h>
2051457Sbostic #include <sys/errno.h>
2151457Sbostic #include <sys/ioctl.h>
2251457Sbostic #include <sys/file.h>
2351457Sbostic #include <sys/disklabel.h>
2455028Smckusick #include <miscfs/specfs/specdev.h>
2537486Smckusick
2640707Skarels /* symbolic sleep message strings for devices */
2740707Skarels char devopn[] = "devopn";
2840707Skarels char devio[] = "devio";
2940707Skarels char devwait[] = "devwait";
3040707Skarels char devin[] = "devin";
3140707Skarels char devout[] = "devout";
3240707Skarels char devioc[] = "devioc";
3340707Skarels char devcls[] = "devcls";
3440707Skarels
3553542Sheideman int (**spec_vnodeop_p)();
3653542Sheideman struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
3753542Sheideman { &vop_default_desc, vn_default_error },
3853542Sheideman { &vop_lookup_desc, spec_lookup }, /* lookup */
3953542Sheideman { &vop_create_desc, spec_create }, /* create */
4053542Sheideman { &vop_mknod_desc, spec_mknod }, /* mknod */
4160391Smckusick { &vop_open_desc, spec_open }, /* open */
4253542Sheideman { &vop_close_desc, spec_close }, /* close */
4353542Sheideman { &vop_access_desc, spec_access }, /* access */
4453542Sheideman { &vop_getattr_desc, spec_getattr }, /* getattr */
4553542Sheideman { &vop_setattr_desc, spec_setattr }, /* setattr */
4660391Smckusick { &vop_read_desc, spec_read }, /* read */
4753542Sheideman { &vop_write_desc, spec_write }, /* write */
4867650Smckusick { &vop_lease_desc, spec_lease_check }, /* lease */
4953542Sheideman { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
5053542Sheideman { &vop_select_desc, spec_select }, /* select */
5168411Smckusick { &vop_revoke_desc, spec_revoke }, /* revoke */
5260391Smckusick { &vop_mmap_desc, spec_mmap }, /* mmap */
5353542Sheideman { &vop_fsync_desc, spec_fsync }, /* fsync */
5460391Smckusick { &vop_seek_desc, spec_seek }, /* seek */
5553542Sheideman { &vop_remove_desc, spec_remove }, /* remove */
5660391Smckusick { &vop_link_desc, spec_link }, /* link */
5753542Sheideman { &vop_rename_desc, spec_rename }, /* rename */
5853542Sheideman { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
5953542Sheideman { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
6053542Sheideman { &vop_symlink_desc, spec_symlink }, /* symlink */
6153542Sheideman { &vop_readdir_desc, spec_readdir }, /* readdir */
6253542Sheideman { &vop_readlink_desc, spec_readlink }, /* readlink */
6353542Sheideman { &vop_abortop_desc, spec_abortop }, /* abortop */
6453542Sheideman { &vop_inactive_desc, spec_inactive }, /* inactive */
6553542Sheideman { &vop_reclaim_desc, spec_reclaim }, /* reclaim */
6660391Smckusick { &vop_lock_desc, spec_lock }, /* lock */
6753542Sheideman { &vop_unlock_desc, spec_unlock }, /* unlock */
6860391Smckusick { &vop_bmap_desc, spec_bmap }, /* bmap */
6953542Sheideman { &vop_strategy_desc, spec_strategy }, /* strategy */
7053542Sheideman { &vop_print_desc, spec_print }, /* print */
7153542Sheideman { &vop_islocked_desc, spec_islocked }, /* islocked */
7260391Smckusick { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
7353542Sheideman { &vop_advlock_desc, spec_advlock }, /* advlock */
7453542Sheideman { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */
7553542Sheideman { &vop_valloc_desc, spec_valloc }, /* valloc */
7653542Sheideman { &vop_vfree_desc, spec_vfree }, /* vfree */
7753542Sheideman { &vop_truncate_desc, spec_truncate }, /* truncate */
7853542Sheideman { &vop_update_desc, spec_update }, /* update */
7953542Sheideman { &vop_bwrite_desc, spec_bwrite }, /* bwrite */
8053542Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL }
8137486Smckusick };
8253542Sheideman struct vnodeopv_desc spec_vnodeop_opv_desc =
8353542Sheideman { &spec_vnodeop_p, spec_vnodeop_entries };
8437486Smckusick
8537486Smckusick /*
8639292Smckusick * Trivial lookup routine that always fails.
8739292Smckusick */
8852320Sheideman int
spec_lookup(ap)8954439Smckusick spec_lookup(ap)
9054439Smckusick struct vop_lookup_args /* {
9154439Smckusick struct vnode *a_dvp;
9254439Smckusick struct vnode **a_vpp;
9354439Smckusick struct componentname *a_cnp;
9454439Smckusick } */ *ap;
9539292Smckusick {
9639292Smckusick
9753597Sheideman *ap->a_vpp = NULL;
9839292Smckusick return (ENOTDIR);
9939292Smckusick }
10039292Smckusick
10139292Smckusick /*
10259486Smckusick * Open a special file.
10337486Smckusick */
10437725Smckusick /* ARGSUSED */
10554439Smckusick spec_open(ap)
10654439Smckusick struct vop_open_args /* {
10754439Smckusick struct vnode *a_vp;
10854439Smckusick int a_mode;
10954439Smckusick struct ucred *a_cred;
11054439Smckusick struct proc *a_p;
11154439Smckusick } */ *ap;
11237486Smckusick {
11369444Smckusick struct proc *p = ap->a_p;
11459486Smckusick struct vnode *bvp, *vp = ap->a_vp;
11559486Smckusick dev_t bdev, dev = (dev_t)vp->v_rdev;
11669444Smckusick int maj = major(dev);
11740375Smckusick int error;
11837486Smckusick
11959486Smckusick /*
12059486Smckusick * Don't allow open if fs is mounted -nodev.
12159486Smckusick */
12253863Sheideman if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
12339365Smckusick return (ENXIO);
12439365Smckusick
12553863Sheideman switch (vp->v_type) {
12637486Smckusick
12737486Smckusick case VCHR:
12837486Smckusick if ((u_int)maj >= nchrdev)
12937486Smckusick return (ENXIO);
13059486Smckusick if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) {
13159486Smckusick /*
13259486Smckusick * When running in very secure mode, do not allow
13359486Smckusick * opens for writing of any disk character devices.
13459486Smckusick */
13568129Smckusick if (securelevel >= 2 && cdevsw[maj].d_type == D_DISK)
13659486Smckusick return (EPERM);
13759486Smckusick /*
13859486Smckusick * When running in secure mode, do not allow opens
13959486Smckusick * for writing of /dev/mem, /dev/kmem, or character
14059486Smckusick * devices whose corresponding block devices are
14159486Smckusick * currently mounted.
14259486Smckusick */
14359486Smckusick if (securelevel >= 1) {
14459486Smckusick if ((bdev = chrtoblk(dev)) != NODEV &&
14559486Smckusick vfinddev(bdev, VBLK, &bvp) &&
14659486Smckusick bvp->v_usecount > 0 &&
14765671Shibler (error = vfs_mountedon(bvp)))
14859486Smckusick return (error);
14959486Smckusick if (iskmemdev(dev))
15059486Smckusick return (EPERM);
15159486Smckusick }
15259486Smckusick }
15368129Smckusick if (cdevsw[maj].d_type == D_TTY)
15467951Smckusick vp->v_flag |= VISTTY;
15569444Smckusick VOP_UNLOCK(vp, 0, p);
15669444Smckusick error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, p);
15769444Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
15849944Smckusick return (error);
15937486Smckusick
16037486Smckusick case VBLK:
16137486Smckusick if ((u_int)maj >= nblkdev)
16237486Smckusick return (ENXIO);
16359486Smckusick /*
16459486Smckusick * When running in very secure mode, do not allow
16559486Smckusick * opens for writing of any disk block devices.
16659486Smckusick */
16759486Smckusick if (securelevel >= 2 && ap->a_cred != FSCRED &&
16868129Smckusick (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK)
16959486Smckusick return (EPERM);
17059486Smckusick /*
17159486Smckusick * Do not allow opens of block devices that are
17259486Smckusick * currently mounted.
17359486Smckusick */
17465671Shibler if (error = vfs_mountedon(vp))
17540375Smckusick return (error);
17669444Smckusick return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, p));
17737486Smckusick }
17837486Smckusick return (0);
17937486Smckusick }
18037486Smckusick
18137486Smckusick /*
18237486Smckusick * Vnode op for read
18337486Smckusick */
18441961Smckusick /* ARGSUSED */
18554439Smckusick spec_read(ap)
18654439Smckusick struct vop_read_args /* {
18754439Smckusick struct vnode *a_vp;
18854439Smckusick struct uio *a_uio;
18954439Smckusick int a_ioflag;
19054439Smckusick struct ucred *a_cred;
19154439Smckusick } */ *ap;
19237486Smckusick {
19353863Sheideman register struct vnode *vp = ap->a_vp;
19453863Sheideman register struct uio *uio = ap->a_uio;
19553863Sheideman struct proc *p = uio->uio_procp;
19639614Smckusick struct buf *bp;
19752321Smckusick daddr_t bn, nextbn;
19839614Smckusick long bsize, bscale;
19939614Smckusick struct partinfo dpart;
20065532Smckusick int n, on, majordev, (*ioctl)();
20139614Smckusick int error = 0;
20265532Smckusick dev_t dev;
20337486Smckusick
20448015Smckusick #ifdef DIAGNOSTIC
20553863Sheideman if (uio->uio_rw != UIO_READ)
20639588Smckusick panic("spec_read mode");
20753863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
20848015Smckusick panic("spec_read proc");
20948015Smckusick #endif
21053863Sheideman if (uio->uio_resid == 0)
21139588Smckusick return (0);
21239588Smckusick
21353863Sheideman switch (vp->v_type) {
21439588Smckusick
21539588Smckusick case VCHR:
21669444Smckusick VOP_UNLOCK(vp, 0, p);
21753863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_read)
21853863Sheideman (vp->v_rdev, uio, ap->a_ioflag);
21969444Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
22039588Smckusick return (error);
22139588Smckusick
22239588Smckusick case VBLK:
22353863Sheideman if (uio->uio_offset < 0)
22439588Smckusick return (EINVAL);
22539614Smckusick bsize = BLKDEV_IOSIZE;
22665532Smckusick dev = vp->v_rdev;
22765532Smckusick if ((majordev = major(dev)) < nblkdev &&
22865532Smckusick (ioctl = bdevsw[majordev].d_ioctl) != NULL &&
22965532Smckusick (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0 &&
23065532Smckusick dpart.part->p_fstype == FS_BSDFFS &&
23165532Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
23265532Smckusick bsize = dpart.part->p_frag * dpart.part->p_fsize;
23339614Smckusick bscale = bsize / DEV_BSIZE;
23439614Smckusick do {
23553863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
23653863Sheideman on = uio->uio_offset % bsize;
23755059Spendry n = min((unsigned)(bsize - on), uio->uio_resid);
23853863Sheideman if (vp->v_lastr + bscale == bn) {
23952321Smckusick nextbn = bn + bscale;
24053863Sheideman error = breadn(vp, bn, (int)bsize, &nextbn,
24152321Smckusick (int *)&bsize, 1, NOCRED, &bp);
24252321Smckusick } else
24353863Sheideman error = bread(vp, bn, (int)bsize, NOCRED, &bp);
24453863Sheideman vp->v_lastr = bn;
24555059Spendry n = min(n, bsize - bp->b_resid);
24639614Smckusick if (error) {
24739614Smckusick brelse(bp);
24839614Smckusick return (error);
24939614Smckusick }
25064551Sbostic error = uiomove((char *)bp->b_data + on, n, uio);
25139614Smckusick if (n + on == bsize)
25239614Smckusick bp->b_flags |= B_AGE;
25339614Smckusick brelse(bp);
25453863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0);
25539614Smckusick return (error);
25639588Smckusick
25739588Smckusick default:
25839588Smckusick panic("spec_read type");
25939588Smckusick }
26039588Smckusick /* NOTREACHED */
26137486Smckusick }
26237486Smckusick
26337486Smckusick /*
26437486Smckusick * Vnode op for write
26537486Smckusick */
26641961Smckusick /* ARGSUSED */
26754439Smckusick spec_write(ap)
26854439Smckusick struct vop_write_args /* {
26954439Smckusick struct vnode *a_vp;
27054439Smckusick struct uio *a_uio;
27154439Smckusick int a_ioflag;
27254439Smckusick struct ucred *a_cred;
27354439Smckusick } */ *ap;
27437486Smckusick {
27553863Sheideman register struct vnode *vp = ap->a_vp;
27653863Sheideman register struct uio *uio = ap->a_uio;
27753863Sheideman struct proc *p = uio->uio_procp;
27839614Smckusick struct buf *bp;
27939614Smckusick daddr_t bn;
28039614Smckusick int bsize, blkmask;
28139614Smckusick struct partinfo dpart;
28245731Smckusick register int n, on;
28345731Smckusick int error = 0;
28437486Smckusick
28548015Smckusick #ifdef DIAGNOSTIC
28653863Sheideman if (uio->uio_rw != UIO_WRITE)
28739588Smckusick panic("spec_write mode");
28853863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
28948015Smckusick panic("spec_write proc");
29048015Smckusick #endif
29139588Smckusick
29253863Sheideman switch (vp->v_type) {
29339588Smckusick
29439588Smckusick case VCHR:
29569444Smckusick VOP_UNLOCK(vp, 0, p);
29653863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_write)
29753863Sheideman (vp->v_rdev, uio, ap->a_ioflag);
29869444Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
29939588Smckusick return (error);
30039588Smckusick
30139588Smckusick case VBLK:
30253863Sheideman if (uio->uio_resid == 0)
30339588Smckusick return (0);
30453863Sheideman if (uio->uio_offset < 0)
30539588Smckusick return (EINVAL);
30639614Smckusick bsize = BLKDEV_IOSIZE;
30753863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
30847540Skarels (caddr_t)&dpart, FREAD, p) == 0) {
30939614Smckusick if (dpart.part->p_fstype == FS_BSDFFS &&
31039614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
31139614Smckusick bsize = dpart.part->p_frag *
31239614Smckusick dpart.part->p_fsize;
31339614Smckusick }
31439614Smckusick blkmask = (bsize / DEV_BSIZE) - 1;
31539614Smckusick do {
31653863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
31753863Sheideman on = uio->uio_offset % bsize;
31855059Spendry n = min((unsigned)(bsize - on), uio->uio_resid);
31939614Smckusick if (n == bsize)
32057798Smckusick bp = getblk(vp, bn, bsize, 0, 0);
32139614Smckusick else
32253863Sheideman error = bread(vp, bn, bsize, NOCRED, &bp);
32355059Spendry n = min(n, bsize - bp->b_resid);
32439614Smckusick if (error) {
32539614Smckusick brelse(bp);
32639614Smckusick return (error);
32739614Smckusick }
32864551Sbostic error = uiomove((char *)bp->b_data + on, n, uio);
32939614Smckusick if (n + on == bsize) {
33039614Smckusick bp->b_flags |= B_AGE;
33139614Smckusick bawrite(bp);
33239614Smckusick } else
33339614Smckusick bdwrite(bp);
33453863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0);
33539614Smckusick return (error);
33639588Smckusick
33739588Smckusick default:
33839588Smckusick panic("spec_write type");
33939588Smckusick }
34039588Smckusick /* NOTREACHED */
34137486Smckusick }
34237486Smckusick
34337486Smckusick /*
34437486Smckusick * Device ioctl operation.
34537486Smckusick */
34637725Smckusick /* ARGSUSED */
34754439Smckusick spec_ioctl(ap)
34854439Smckusick struct vop_ioctl_args /* {
34954439Smckusick struct vnode *a_vp;
35054439Smckusick int a_command;
35154439Smckusick caddr_t a_data;
35254439Smckusick int a_fflag;
35354439Smckusick struct ucred *a_cred;
35454439Smckusick struct proc *a_p;
35554439Smckusick } */ *ap;
35637486Smckusick {
35753597Sheideman dev_t dev = ap->a_vp->v_rdev;
35837486Smckusick
35953597Sheideman switch (ap->a_vp->v_type) {
36037486Smckusick
36137486Smckusick case VCHR:
36253597Sheideman return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
36353597Sheideman ap->a_fflag, ap->a_p));
36437486Smckusick
36537486Smckusick case VBLK:
36653597Sheideman if (ap->a_command == 0 && (int)ap->a_data == B_TAPE)
36768129Smckusick if (bdevsw[major(dev)].d_type == D_TAPE)
36839666Smckusick return (0);
36939666Smckusick else
37039666Smckusick return (1);
37153597Sheideman return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
37253597Sheideman ap->a_fflag, ap->a_p));
37337486Smckusick
37437486Smckusick default:
37539446Smckusick panic("spec_ioctl");
37637486Smckusick /* NOTREACHED */
37737486Smckusick }
37837486Smckusick }
37937486Smckusick
38037725Smckusick /* ARGSUSED */
38154439Smckusick spec_select(ap)
38254439Smckusick struct vop_select_args /* {
38354439Smckusick struct vnode *a_vp;
38454439Smckusick int a_which;
38554439Smckusick int a_fflags;
38654439Smckusick struct ucred *a_cred;
38754439Smckusick struct proc *a_p;
38854439Smckusick } */ *ap;
38937486Smckusick {
39037486Smckusick register dev_t dev;
39137486Smckusick
39253597Sheideman switch (ap->a_vp->v_type) {
39337486Smckusick
39437486Smckusick default:
39537486Smckusick return (1); /* XXX */
39637486Smckusick
39737486Smckusick case VCHR:
39853597Sheideman dev = ap->a_vp->v_rdev;
39953597Sheideman return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p);
40037486Smckusick }
40137486Smckusick }
40254439Smckusick /*
40354439Smckusick * Synch buffers associated with a block device
40454439Smckusick */
40554439Smckusick /* ARGSUSED */
40654439Smckusick int
spec_fsync(ap)40754439Smckusick spec_fsync(ap)
40854439Smckusick struct vop_fsync_args /* {
40954439Smckusick struct vnode *a_vp;
41054439Smckusick struct ucred *a_cred;
41154439Smckusick int a_waitfor;
41254439Smckusick struct proc *a_p;
41354439Smckusick } */ *ap;
41454439Smckusick {
41554439Smckusick register struct vnode *vp = ap->a_vp;
41654439Smckusick register struct buf *bp;
41754439Smckusick struct buf *nbp;
41856548Smckusick int s;
41937486Smckusick
42054439Smckusick if (vp->v_type == VCHR)
42154439Smckusick return (0);
42254439Smckusick /*
42354439Smckusick * Flush all dirty buffers associated with a block device.
42454439Smckusick */
42554439Smckusick loop:
42654439Smckusick s = splbio();
42765246Smckusick for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
42865246Smckusick nbp = bp->b_vnbufs.le_next;
42954439Smckusick if ((bp->b_flags & B_BUSY))
43054439Smckusick continue;
43154439Smckusick if ((bp->b_flags & B_DELWRI) == 0)
43254439Smckusick panic("spec_fsync: not dirty");
43354439Smckusick bremfree(bp);
43454439Smckusick bp->b_flags |= B_BUSY;
43554439Smckusick splx(s);
43656548Smckusick bawrite(bp);
43754439Smckusick goto loop;
43854439Smckusick }
43954439Smckusick if (ap->a_waitfor == MNT_WAIT) {
44054439Smckusick while (vp->v_numoutput) {
44154439Smckusick vp->v_flag |= VBWAIT;
44254439Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
44354439Smckusick }
44454439Smckusick #ifdef DIAGNOSTIC
44565246Smckusick if (vp->v_dirtyblkhd.lh_first) {
44654439Smckusick vprint("spec_fsync: dirty", vp);
44754439Smckusick goto loop;
44854439Smckusick }
44954439Smckusick #endif
45054439Smckusick }
45154439Smckusick splx(s);
45256548Smckusick return (0);
45354439Smckusick }
45454439Smckusick
455*69597Smckusick int
spec_inactive(ap)456*69597Smckusick spec_inactive(ap)
457*69597Smckusick struct vop_inactive_args /* {
458*69597Smckusick struct vnode *a_vp;
459*69597Smckusick struct proc *a_p;
460*69597Smckusick } */ *ap;
461*69597Smckusick {
462*69597Smckusick
463*69597Smckusick VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
464*69597Smckusick return (0);
465*69597Smckusick }
466*69597Smckusick
46737486Smckusick /*
46837486Smckusick * Just call the device strategy routine
46937486Smckusick */
47054439Smckusick spec_strategy(ap)
47154439Smckusick struct vop_strategy_args /* {
47254439Smckusick struct buf *a_bp;
47354439Smckusick } */ *ap;
47437486Smckusick {
47539666Smckusick
47653597Sheideman (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp);
47737486Smckusick return (0);
47837486Smckusick }
47937486Smckusick
48039432Smckusick /*
48139666Smckusick * This is a noop, simply returning what one has been given.
48239666Smckusick */
48354439Smckusick spec_bmap(ap)
48454439Smckusick struct vop_bmap_args /* {
48554439Smckusick struct vnode *a_vp;
48654439Smckusick daddr_t a_bn;
48754439Smckusick struct vnode **a_vpp;
48854439Smckusick daddr_t *a_bnp;
48968234Spendry int *a_runp;
49054439Smckusick } */ *ap;
49139666Smckusick {
49239666Smckusick
49353597Sheideman if (ap->a_vpp != NULL)
49453597Sheideman *ap->a_vpp = ap->a_vp;
49553597Sheideman if (ap->a_bnp != NULL)
49653597Sheideman *ap->a_bnp = ap->a_bn;
49768231Spendry if (ap->a_runp != NULL)
49868231Spendry *ap->a_runp = 0;
49939666Smckusick return (0);
50039666Smckusick }
50139666Smckusick
50239666Smckusick /*
50337486Smckusick * Device close routine
50437486Smckusick */
50537725Smckusick /* ARGSUSED */
50654439Smckusick spec_close(ap)
50754439Smckusick struct vop_close_args /* {
50854439Smckusick struct vnode *a_vp;
50954439Smckusick int a_fflag;
51054439Smckusick struct ucred *a_cred;
51154439Smckusick struct proc *a_p;
51254439Smckusick } */ *ap;
51337486Smckusick {
51453863Sheideman register struct vnode *vp = ap->a_vp;
51553863Sheideman dev_t dev = vp->v_rdev;
51649273Skarels int (*devclose) __P((dev_t, int, int, struct proc *));
51754439Smckusick int mode, error;
51837486Smckusick
51953863Sheideman switch (vp->v_type) {
52037725Smckusick
52137725Smckusick case VCHR:
52239485Smckusick /*
52360498Smckusick * Hack: a tty device that is a controlling terminal
52460498Smckusick * has a reference from the session structure.
52560498Smckusick * We cannot easily tell that a character device is
52660498Smckusick * a controlling terminal, unless it is the closing
52760498Smckusick * process' controlling terminal. In that case,
52860498Smckusick * if the reference count is 2 (this last descriptor
52960498Smckusick * plus the session), release the reference from the session.
53060498Smckusick */
53160527Smckusick if (vcount(vp) == 2 && ap->a_p &&
53260527Smckusick vp == ap->a_p->p_session->s_ttyvp) {
53360498Smckusick vrele(vp);
53460498Smckusick ap->a_p->p_session->s_ttyvp = NULL;
53560498Smckusick }
53660498Smckusick /*
53739485Smckusick * If the vnode is locked, then we are in the midst
53839485Smckusick * of forcably closing the device, otherwise we only
53939485Smckusick * close on last reference.
54039485Smckusick */
54153863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
54237725Smckusick return (0);
54349273Skarels devclose = cdevsw[major(dev)].d_close;
54439432Smckusick mode = S_IFCHR;
54537725Smckusick break;
54637725Smckusick
54737725Smckusick case VBLK:
54837725Smckusick /*
54937725Smckusick * On last close of a block device (that isn't mounted)
55037725Smckusick * we must invalidate any in core blocks, so that
55137725Smckusick * we can, for instance, change floppy disks.
55237725Smckusick */
55366739Spendry if (error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0))
55454439Smckusick return (error);
55537725Smckusick /*
55639485Smckusick * We do not want to really close the device if it
55739485Smckusick * is still in use unless we are trying to close it
55839485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap)
55939630Smckusick * holds a reference to the vnode, and because we mark
56039630Smckusick * any other vnodes that alias this device, when the
56139630Smckusick * sum of the reference counts on all the aliased
56239630Smckusick * vnodes descends to one, we are on last close.
56337725Smckusick */
56453863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
56537725Smckusick return (0);
56649273Skarels devclose = bdevsw[major(dev)].d_close;
56739432Smckusick mode = S_IFBLK;
56837725Smckusick break;
56937725Smckusick
57037725Smckusick default:
57139446Smckusick panic("spec_close: not special");
57237725Smckusick }
57337725Smckusick
57453597Sheideman return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p));
57537486Smckusick }
57637486Smckusick
57737486Smckusick /*
57839666Smckusick * Print out the contents of a special device vnode.
57939666Smckusick */
58054439Smckusick spec_print(ap)
58154439Smckusick struct vop_print_args /* {
58254439Smckusick struct vnode *a_vp;
58354439Smckusick } */ *ap;
58439666Smckusick {
58539666Smckusick
58653597Sheideman printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev),
58753597Sheideman minor(ap->a_vp->v_rdev));
58839666Smckusick }
58939666Smckusick
59039666Smckusick /*
59160391Smckusick * Return POSIX pathconf information applicable to special devices.
59260391Smckusick */
59360391Smckusick spec_pathconf(ap)
59460391Smckusick struct vop_pathconf_args /* {
59560391Smckusick struct vnode *a_vp;
59660391Smckusick int a_name;
59760391Smckusick int *a_retval;
59860391Smckusick } */ *ap;
59960391Smckusick {
60060391Smckusick
60160391Smckusick switch (ap->a_name) {
60260391Smckusick case _PC_LINK_MAX:
60360391Smckusick *ap->a_retval = LINK_MAX;
60460391Smckusick return (0);
60560391Smckusick case _PC_MAX_CANON:
60660391Smckusick *ap->a_retval = MAX_CANON;
60760391Smckusick return (0);
60860391Smckusick case _PC_MAX_INPUT:
60960391Smckusick *ap->a_retval = MAX_INPUT;
61060391Smckusick return (0);
61160391Smckusick case _PC_PIPE_BUF:
61260391Smckusick *ap->a_retval = PIPE_BUF;
61360391Smckusick return (0);
61460391Smckusick case _PC_CHOWN_RESTRICTED:
61560391Smckusick *ap->a_retval = 1;
61660391Smckusick return (0);
61760391Smckusick case _PC_VDISABLE:
61860391Smckusick *ap->a_retval = _POSIX_VDISABLE;
61960391Smckusick return (0);
62060391Smckusick default:
62160391Smckusick return (EINVAL);
62260391Smckusick }
62360391Smckusick /* NOTREACHED */
62460391Smckusick }
62560391Smckusick
62660391Smckusick /*
62746196Smckusick * Special device advisory byte-level locks.
62846196Smckusick */
62948015Smckusick /* ARGSUSED */
63054439Smckusick spec_advlock(ap)
63154439Smckusick struct vop_advlock_args /* {
63254439Smckusick struct vnode *a_vp;
63354439Smckusick caddr_t a_id;
63454439Smckusick int a_op;
63554439Smckusick struct flock *a_fl;
63654439Smckusick int a_flags;
63754439Smckusick } */ *ap;
63846196Smckusick {
63946196Smckusick
64046196Smckusick return (EOPNOTSUPP);
64146196Smckusick }
64246196Smckusick
64346196Smckusick /*
64439507Smckusick * Special device failed operation
64537486Smckusick */
spec_ebadf()64639507Smckusick spec_ebadf()
64739507Smckusick {
64839507Smckusick
64939507Smckusick return (EBADF);
65039507Smckusick }
65139507Smckusick
65239507Smckusick /*
65339507Smckusick * Special device bad operation
65439507Smckusick */
spec_badop()65539446Smckusick spec_badop()
65637486Smckusick {
65737486Smckusick
65839446Smckusick panic("spec_badop called");
65939292Smckusick /* NOTREACHED */
66037486Smckusick }
661