registerized vnodeop ops after vnode interface conversion
[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 *
406c9a0d 7 * @(#)spec_vnops.c 7.45 (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 */
72 { &vop_vget_desc, spec_vget }, /* vget */
73 { &vop_valloc_desc, spec_valloc }, /* valloc */
74 { &vop_vfree_desc, spec_vfree }, /* vfree */
75 { &vop_truncate_desc, spec_truncate }, /* truncate */
76 { &vop_update_desc, spec_update }, /* update */
77 { &vop_bwrite_desc, spec_bwrite }, /* bwrite */
78 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
a1d35437 79};
9342689a
JH
80struct vnodeopv_desc spec_vnodeop_opv_desc =
81 { &spec_vnodeop_p, spec_vnodeop_entries };
a1d35437 82
59b0713e
KM
83/*
84 * Trivial lookup routine that always fails.
85 */
6ee99c46 86int
9342689a
JH
87spec_lookup (ap)
88 struct vop_lookup_args *ap;
59b0713e
KM
89{
90
e1b76915 91 *ap->a_vpp = NULL;
59b0713e
KM
92 return (ENOTDIR);
93}
94
a1d35437 95/*
e15ce6a3
MK
96 * Open a special file: Don't allow open if fs is mounted -nodev,
97 * and don't allow opens of block devices that are currently mounted.
98 * Otherwise, call device driver open function.
a1d35437 99 */
3d5d83ff 100/* ARGSUSED */
9342689a
JH
101spec_open (ap)
102 struct vop_open_args *ap;
a1d35437 103{
9342689a
JH
104 USES_VOP_LOCK;
105 USES_VOP_UNLOCK;
406c9a0d
JH
106 register struct vnode *vp = ap->a_vp;
107 dev_t dev = (dev_t)vp->v_rdev;
a1d35437 108 register int maj = major(dev);
5b2e9327 109 int error;
a1d35437 110
406c9a0d 111 if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
786053cd
KM
112 return (ENXIO);
113
406c9a0d 114 switch (vp->v_type) {
a1d35437
KM
115
116 case VCHR:
117 if ((u_int)maj >= nchrdev)
118 return (ENXIO);
406c9a0d 119 VOP_UNLOCK(vp);
e1b76915 120 error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p);
406c9a0d 121 VOP_LOCK(vp);
b3bf09c7 122 return (error);
a1d35437
KM
123
124 case VBLK:
125 if ((u_int)maj >= nblkdev)
126 return (ENXIO);
406c9a0d 127 if (error = ufs_mountedon(vp))
5b2e9327 128 return (error);
e1b76915 129 return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p));
a1d35437
KM
130 }
131 return (0);
132}
133
a1d35437
KM
134/*
135 * Vnode op for read
136 */
fe6cdffe 137/* ARGSUSED */
9342689a
JH
138spec_read (ap)
139 struct vop_read_args *ap;
a1d35437 140{
9342689a
JH
141 USES_VOP_LOCK;
142 USES_VOP_UNLOCK;
406c9a0d
JH
143 register struct vnode *vp = ap->a_vp;
144 register struct uio *uio = ap->a_uio;
145 struct proc *p = uio->uio_procp;
7d4e5ac1 146 struct buf *bp;
2e4bbf7a 147 daddr_t bn, nextbn;
7d4e5ac1
KM
148 long bsize, bscale;
149 struct partinfo dpart;
150 register int n, on;
151 int error = 0;
a1d35437 152
68a834b0 153#ifdef DIAGNOSTIC
406c9a0d 154 if (uio->uio_rw != UIO_READ)
43444338 155 panic("spec_read mode");
406c9a0d 156 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
68a834b0
KM
157 panic("spec_read proc");
158#endif
406c9a0d 159 if (uio->uio_resid == 0)
43444338 160 return (0);
43444338 161
406c9a0d 162 switch (vp->v_type) {
43444338
KM
163
164 case VCHR:
406c9a0d
JH
165 VOP_UNLOCK(vp);
166 error = (*cdevsw[major(vp->v_rdev)].d_read)
167 (vp->v_rdev, uio, ap->a_ioflag);
168 VOP_LOCK(vp);
43444338
KM
169 return (error);
170
171 case VBLK:
406c9a0d 172 if (uio->uio_offset < 0)
43444338 173 return (EINVAL);
7d4e5ac1 174 bsize = BLKDEV_IOSIZE;
406c9a0d 175 if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
8429d022 176 (caddr_t)&dpart, FREAD, p) == 0) {
7d4e5ac1
KM
177 if (dpart.part->p_fstype == FS_BSDFFS &&
178 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
179 bsize = dpart.part->p_frag *
180 dpart.part->p_fsize;
181 }
182 bscale = bsize / DEV_BSIZE;
183 do {
406c9a0d
JH
184 bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
185 on = uio->uio_offset % bsize;
186 n = MIN((unsigned)(bsize - on), uio->uio_resid);
187 if (vp->v_lastr + bscale == bn) {
2e4bbf7a 188 nextbn = bn + bscale;
406c9a0d 189 error = breadn(vp, bn, (int)bsize, &nextbn,
2e4bbf7a
KM
190 (int *)&bsize, 1, NOCRED, &bp);
191 } else
406c9a0d
JH
192 error = bread(vp, bn, (int)bsize, NOCRED, &bp);
193 vp->v_lastr = bn;
7d4e5ac1
KM
194 n = MIN(n, bsize - bp->b_resid);
195 if (error) {
196 brelse(bp);
197 return (error);
198 }
406c9a0d 199 error = uiomove(bp->b_un.b_addr + on, n, uio);
7d4e5ac1
KM
200 if (n + on == bsize)
201 bp->b_flags |= B_AGE;
202 brelse(bp);
406c9a0d 203 } while (error == 0 && uio->uio_resid > 0 && n != 0);
7d4e5ac1 204 return (error);
43444338
KM
205
206 default:
207 panic("spec_read type");
208 }
209 /* NOTREACHED */
a1d35437
KM
210}
211
212/*
213 * Vnode op for write
214 */
fe6cdffe 215/* ARGSUSED */
9342689a
JH
216spec_write (ap)
217 struct vop_write_args *ap;
a1d35437 218{
9342689a
JH
219 USES_VOP_LOCK;
220 USES_VOP_UNLOCK;
406c9a0d
JH
221 register struct vnode *vp = ap->a_vp;
222 register struct uio *uio = ap->a_uio;
223 struct proc *p = uio->uio_procp;
7d4e5ac1
KM
224 struct buf *bp;
225 daddr_t bn;
226 int bsize, blkmask;
227 struct partinfo dpart;
9db58063
KM
228 register int n, on;
229 int error = 0;
a1d35437 230
68a834b0 231#ifdef DIAGNOSTIC
406c9a0d 232 if (uio->uio_rw != UIO_WRITE)
43444338 233 panic("spec_write mode");
406c9a0d 234 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
68a834b0
KM
235 panic("spec_write proc");
236#endif
43444338 237
406c9a0d 238 switch (vp->v_type) {
43444338
KM
239
240 case VCHR:
406c9a0d
JH
241 VOP_UNLOCK(vp);
242 error = (*cdevsw[major(vp->v_rdev)].d_write)
243 (vp->v_rdev, uio, ap->a_ioflag);
244 VOP_LOCK(vp);
43444338
KM
245 return (error);
246
247 case VBLK:
406c9a0d 248 if (uio->uio_resid == 0)
43444338 249 return (0);
406c9a0d 250 if (uio->uio_offset < 0)
43444338 251 return (EINVAL);
7d4e5ac1 252 bsize = BLKDEV_IOSIZE;
406c9a0d 253 if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
8429d022 254 (caddr_t)&dpart, FREAD, p) == 0) {
7d4e5ac1
KM
255 if (dpart.part->p_fstype == FS_BSDFFS &&
256 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
257 bsize = dpart.part->p_frag *
258 dpart.part->p_fsize;
259 }
260 blkmask = (bsize / DEV_BSIZE) - 1;
261 do {
406c9a0d
JH
262 bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
263 on = uio->uio_offset % bsize;
264 n = MIN((unsigned)(bsize - on), uio->uio_resid);
7d4e5ac1 265 if (n == bsize)
406c9a0d 266 bp = getblk(vp, bn, bsize);
7d4e5ac1 267 else
406c9a0d 268 error = bread(vp, bn, bsize, NOCRED, &bp);
7d4e5ac1
KM
269 n = MIN(n, bsize - bp->b_resid);
270 if (error) {
271 brelse(bp);
272 return (error);
273 }
406c9a0d 274 error = uiomove(bp->b_un.b_addr + on, n, uio);
7d4e5ac1
KM
275 if (n + on == bsize) {
276 bp->b_flags |= B_AGE;
277 bawrite(bp);
278 } else
279 bdwrite(bp);
406c9a0d 280 } while (error == 0 && uio->uio_resid > 0 && n != 0);
7d4e5ac1 281 return (error);
43444338
KM
282
283 default:
284 panic("spec_write type");
285 }
286 /* NOTREACHED */
a1d35437
KM
287}
288
289/*
290 * Device ioctl operation.
291 */
3d5d83ff 292/* ARGSUSED */
9342689a
JH
293spec_ioctl (ap)
294 struct vop_ioctl_args *ap;
a1d35437 295{
e1b76915 296 dev_t dev = ap->a_vp->v_rdev;
a1d35437 297
e1b76915 298 switch (ap->a_vp->v_type) {
a1d35437
KM
299
300 case VCHR:
e1b76915
JH
301 return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
302 ap->a_fflag, ap->a_p));
a1d35437
KM
303
304 case VBLK:
e1b76915 305 if (ap->a_command == 0 && (int)ap->a_data == B_TAPE)
b9a4d0ff
KM
306 if (bdevsw[major(dev)].d_flags & B_TAPE)
307 return (0);
308 else
309 return (1);
e1b76915
JH
310 return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
311 ap->a_fflag, ap->a_p));
a1d35437
KM
312
313 default:
ad27f720 314 panic("spec_ioctl");
a1d35437
KM
315 /* NOTREACHED */
316 }
317}
318
3d5d83ff 319/* ARGSUSED */
9342689a
JH
320spec_select (ap)
321 struct vop_select_args *ap;
a1d35437 322{
a1d35437
KM
323 register dev_t dev;
324
e1b76915 325 switch (ap->a_vp->v_type) {
a1d35437
KM
326
327 default:
328 return (1); /* XXX */
329
330 case VCHR:
e1b76915
JH
331 dev = ap->a_vp->v_rdev;
332 return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p);
a1d35437
KM
333 }
334}
335
336/*
337 * Just call the device strategy routine
338 */
9342689a
JH
339spec_strategy (ap)
340 struct vop_strategy_args *ap;
a1d35437 341{
b9a4d0ff 342
e1b76915 343 (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp);
a1d35437
KM
344 return (0);
345}
346
b9a4d0ff
KM
347/*
348 * This is a noop, simply returning what one has been given.
349 */
9342689a
JH
350spec_bmap (ap)
351 struct vop_bmap_args *ap;
b9a4d0ff
KM
352{
353
e1b76915
JH
354 if (ap->a_vpp != NULL)
355 *ap->a_vpp = ap->a_vp;
356 if (ap->a_bnp != NULL)
357 *ap->a_bnp = ap->a_bn;
b9a4d0ff
KM
358 return (0);
359}
360
1c00bf64
KM
361/*
362 * At the moment we do not do any locking.
363 */
ff4fb102 364/* ARGSUSED */
9342689a
JH
365spec_lock (ap)
366 struct vop_lock_args *ap;
a1d35437 367{
a1d35437 368
a1d35437
KM
369 return (0);
370}
371
ff4fb102 372/* ARGSUSED */
9342689a
JH
373spec_unlock (ap)
374 struct vop_unlock_args *ap;
a1d35437 375{
a1d35437 376
a1d35437
KM
377 return (0);
378}
379
a1d35437
KM
380/*
381 * Device close routine
382 */
3d5d83ff 383/* ARGSUSED */
9342689a
JH
384spec_close (ap)
385 struct vop_close_args *ap;
a1d35437 386{
406c9a0d
JH
387 register struct vnode *vp = ap->a_vp;
388 dev_t dev = vp->v_rdev;
e15ce6a3 389 int (*devclose) __P((dev_t, int, int, struct proc *));
ccee3c59 390 int mode;
a1d35437 391
406c9a0d 392 switch (vp->v_type) {
3d5d83ff
KM
393
394 case VCHR:
f4b3ea62
KM
395 /*
396 * If the vnode is locked, then we are in the midst
397 * of forcably closing the device, otherwise we only
398 * close on last reference.
399 */
406c9a0d 400 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
3d5d83ff 401 return (0);
e15ce6a3 402 devclose = cdevsw[major(dev)].d_close;
1c00bf64 403 mode = S_IFCHR;
3d5d83ff
KM
404 break;
405
406 case VBLK:
407 /*
408 * On last close of a block device (that isn't mounted)
409 * we must invalidate any in core blocks, so that
410 * we can, for instance, change floppy disks.
411 */
406c9a0d
JH
412 vflushbuf(vp, 0);
413 if (vinvalbuf(vp, 1))
4a29fa35 414 return (0);
3d5d83ff 415 /*
f4b3ea62
KM
416 * We do not want to really close the device if it
417 * is still in use unless we are trying to close it
418 * forcibly. Since every use (buffer, vnode, swap, cmap)
3ab57521
KM
419 * holds a reference to the vnode, and because we mark
420 * any other vnodes that alias this device, when the
421 * sum of the reference counts on all the aliased
422 * vnodes descends to one, we are on last close.
3d5d83ff 423 */
406c9a0d 424 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
3d5d83ff 425 return (0);
e15ce6a3 426 devclose = bdevsw[major(dev)].d_close;
1c00bf64 427 mode = S_IFBLK;
3d5d83ff
KM
428 break;
429
430 default:
ad27f720 431 panic("spec_close: not special");
3d5d83ff
KM
432 }
433
e1b76915 434 return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p));
a1d35437
KM
435}
436
b9a4d0ff
KM
437/*
438 * Print out the contents of a special device vnode.
439 */
9342689a
JH
440spec_print (ap)
441 struct vop_print_args *ap;
b9a4d0ff
KM
442{
443
e1b76915
JH
444 printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev),
445 minor(ap->a_vp->v_rdev));
b9a4d0ff
KM
446}
447
a4128336
KM
448/*
449 * Special device advisory byte-level locks.
450 */
68a834b0 451/* ARGSUSED */
9342689a
JH
452spec_advlock (ap)
453 struct vop_advlock_args *ap;
a4128336
KM
454{
455
456 return (EOPNOTSUPP);
457}
458
a1d35437 459/*
7bbe72a5
KM
460 * Special device failed operation
461 */
462spec_ebadf()
463{
464
465 return (EBADF);
466}
467
468/*
469 * Special device bad operation
a1d35437 470 */
ad27f720 471spec_badop()
a1d35437
KM
472{
473
ad27f720 474 panic("spec_badop called");
59b0713e 475 /* NOTREACHED */
a1d35437 476}