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