add flags field to specinfo to mark mounted block devices
[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 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
fbb80d56 17 * @(#)spec_vnops.c 7.22 (Berkeley) %G%
a1d35437
KM
18 */
19
20#include "param.h"
21#include "systm.h"
3d5d83ff
KM
22#include "user.h"
23#include "kernel.h"
a1d35437
KM
24#include "conf.h"
25#include "buf.h"
786053cd 26#include "mount.h"
a1d35437 27#include "vnode.h"
1c00bf64 28#include "stat.h"
a1d35437 29#include "errno.h"
7d4e5ac1
KM
30#include "ioctl.h"
31#include "file.h"
32#include "disklabel.h"
a1d35437 33
ad27f720
KM
34int spec_lookup(),
35 spec_open(),
36 spec_read(),
37 spec_write(),
38 spec_strategy(),
b9a4d0ff 39 spec_bmap(),
ad27f720
KM
40 spec_ioctl(),
41 spec_select(),
42 spec_lock(),
43 spec_unlock(),
44 spec_close(),
b9a4d0ff 45 spec_print(),
7bbe72a5 46 spec_ebadf(),
ad27f720
KM
47 spec_badop(),
48 spec_nullop();
49
50struct vnodeops spec_vnodeops = {
7bbe72a5
KM
51 spec_lookup, /* lookup */
52 spec_badop, /* create */
53 spec_badop, /* mknod */
54 spec_open, /* open */
55 spec_close, /* close */
56 spec_ebadf, /* access */
57 spec_ebadf, /* getattr */
58 spec_ebadf, /* setattr */
59 spec_read, /* read */
60 spec_write, /* write */
61 spec_ioctl, /* ioctl */
62 spec_select, /* select */
63 spec_badop, /* mmap */
64 spec_nullop, /* fsync */
65 spec_badop, /* seek */
66 spec_badop, /* remove */
67 spec_badop, /* link */
68 spec_badop, /* rename */
69 spec_badop, /* mkdir */
70 spec_badop, /* rmdir */
71 spec_badop, /* symlink */
72 spec_badop, /* readdir */
73 spec_badop, /* readlink */
74 spec_badop, /* abortop */
75 spec_nullop, /* inactive */
76 spec_nullop, /* reclaim */
77 spec_lock, /* lock */
78 spec_unlock, /* unlock */
b9a4d0ff 79 spec_bmap, /* bmap */
7bbe72a5 80 spec_strategy, /* strategy */
b9a4d0ff 81 spec_print, /* print */
d4383369 82 spec_nullop, /* islocked */
a1d35437
KM
83};
84
59b0713e
KM
85/*
86 * Trivial lookup routine that always fails.
87 */
ad27f720 88spec_lookup(vp, ndp)
59b0713e
KM
89 struct vnode *vp;
90 struct nameidata *ndp;
91{
92
93 ndp->ni_dvp = vp;
94 ndp->ni_vp = NULL;
95 return (ENOTDIR);
96}
97
a1d35437
KM
98/*
99 * Open called to allow handler
100 * of special files to initialize and
101 * validate before actual IO.
102 */
3d5d83ff 103/* ARGSUSED */
ad27f720 104spec_open(vp, mode, cred)
a1d35437
KM
105 register struct vnode *vp;
106 int mode;
107 struct ucred *cred;
108{
109 dev_t dev = (dev_t)vp->v_rdev;
110 register int maj = major(dev);
111
786053cd
KM
112 if (vp->v_mount && (vp->v_mount->m_flag & M_NODEV))
113 return (ENXIO);
114
a1d35437
KM
115 switch (vp->v_type) {
116
117 case VCHR:
118 if ((u_int)maj >= nchrdev)
119 return (ENXIO);
1c00bf64 120 return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR));
a1d35437
KM
121
122 case VBLK:
123 if ((u_int)maj >= nblkdev)
124 return (ENXIO);
1c00bf64 125 return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK));
a1d35437
KM
126 }
127 return (0);
128}
129
a1d35437
KM
130/*
131 * Vnode op for read
132 */
43444338 133spec_read(vp, uio, ioflag, cred)
a1d35437 134 register struct vnode *vp;
7d4e5ac1 135 register struct uio *uio;
a1d35437
KM
136 int ioflag;
137 struct ucred *cred;
138{
7d4e5ac1
KM
139 struct buf *bp;
140 daddr_t bn;
141 long bsize, bscale;
142 struct partinfo dpart;
143 register int n, on;
144 int error = 0;
43444338 145 extern int mem_no;
a1d35437 146
43444338
KM
147 if (uio->uio_rw != UIO_READ)
148 panic("spec_read mode");
149 if (uio->uio_resid == 0)
150 return (0);
43444338
KM
151
152 switch (vp->v_type) {
153
154 case VCHR:
155 /*
156 * Negative offsets allowed only for /dev/kmem
157 */
158 if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
159 return (EINVAL);
3d5d83ff 160 VOP_UNLOCK(vp);
43444338
KM
161 error = (*cdevsw[major(vp->v_rdev)].d_read)
162 (vp->v_rdev, uio, ioflag);
163 VOP_LOCK(vp);
164 return (error);
165
166 case VBLK:
167 if (uio->uio_offset < 0)
168 return (EINVAL);
7d4e5ac1
KM
169 bsize = BLKDEV_IOSIZE;
170 if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
171 (caddr_t)&dpart, FREAD) == 0) {
172 if (dpart.part->p_fstype == FS_BSDFFS &&
173 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
174 bsize = dpart.part->p_frag *
175 dpart.part->p_fsize;
176 }
177 bscale = bsize / DEV_BSIZE;
178 do {
179 bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
180 on = uio->uio_offset % bsize;
181 n = MIN((unsigned)(bsize - on), uio->uio_resid);
182 if (vp->v_lastr + bscale == bn)
183 error = breada(vp, bn, (int)bsize, bn + bscale,
184 (int)bsize, NOCRED, &bp);
185 else
186 error = bread(vp, bn, (int)bsize, NOCRED, &bp);
187 vp->v_lastr = bn;
188 n = MIN(n, bsize - bp->b_resid);
189 if (error) {
190 brelse(bp);
191 return (error);
192 }
193 error = uiomove(bp->b_un.b_addr + on, n, uio);
194 if (n + on == bsize)
195 bp->b_flags |= B_AGE;
196 brelse(bp);
197 } while (error == 0 && uio->uio_resid > 0 && n != 0);
198 return (error);
43444338
KM
199
200 default:
201 panic("spec_read type");
202 }
203 /* NOTREACHED */
a1d35437
KM
204}
205
206/*
207 * Vnode op for write
208 */
43444338 209spec_write(vp, uio, ioflag, cred)
a1d35437 210 register struct vnode *vp;
7d4e5ac1 211 register struct uio *uio;
a1d35437
KM
212 int ioflag;
213 struct ucred *cred;
214{
7d4e5ac1
KM
215 struct buf *bp;
216 daddr_t bn;
217 int bsize, blkmask;
218 struct partinfo dpart;
219 register int n, on, i;
220 int count, error = 0;
43444338 221 extern int mem_no;
a1d35437 222
43444338
KM
223 if (uio->uio_rw != UIO_WRITE)
224 panic("spec_write mode");
43444338
KM
225
226 switch (vp->v_type) {
227
228 case VCHR:
229 /*
230 * Negative offsets allowed only for /dev/kmem
231 */
232 if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
233 return (EINVAL);
3d5d83ff 234 VOP_UNLOCK(vp);
43444338
KM
235 error = (*cdevsw[major(vp->v_rdev)].d_write)
236 (vp->v_rdev, uio, ioflag);
237 VOP_LOCK(vp);
238 return (error);
239
240 case VBLK:
241 if (uio->uio_resid == 0)
242 return (0);
243 if (uio->uio_offset < 0)
244 return (EINVAL);
7d4e5ac1
KM
245 bsize = BLKDEV_IOSIZE;
246 if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
247 (caddr_t)&dpart, FREAD) == 0) {
248 if (dpart.part->p_fstype == FS_BSDFFS &&
249 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
250 bsize = dpart.part->p_frag *
251 dpart.part->p_fsize;
252 }
253 blkmask = (bsize / DEV_BSIZE) - 1;
254 do {
255 bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
256 on = uio->uio_offset % bsize;
257 n = MIN((unsigned)(bsize - on), uio->uio_resid);
258 count = howmany(bsize, CLBYTES);
259 for (i = 0; i < count; i++)
260 munhash(vp, bn + i * (CLBYTES / DEV_BSIZE));
261 if (n == bsize)
262 bp = getblk(vp, bn, bsize);
263 else
264 error = bread(vp, bn, bsize, NOCRED, &bp);
265 n = MIN(n, bsize - bp->b_resid);
266 if (error) {
267 brelse(bp);
268 return (error);
269 }
270 error = uiomove(bp->b_un.b_addr + on, n, uio);
271 if (n + on == bsize) {
272 bp->b_flags |= B_AGE;
273 bawrite(bp);
274 } else
275 bdwrite(bp);
276 } while (error == 0 && uio->uio_resid > 0 && n != 0);
277 return (error);
43444338
KM
278
279 default:
280 panic("spec_write type");
281 }
282 /* NOTREACHED */
a1d35437
KM
283}
284
285/*
286 * Device ioctl operation.
287 */
3d5d83ff 288/* ARGSUSED */
ad27f720 289spec_ioctl(vp, com, data, fflag, cred)
a1d35437 290 struct vnode *vp;
b9a4d0ff 291 int com;
a1d35437
KM
292 caddr_t data;
293 int fflag;
294 struct ucred *cred;
295{
3d5d83ff 296 dev_t dev = vp->v_rdev;
a1d35437
KM
297
298 switch (vp->v_type) {
299
300 case VCHR:
301 return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag));
302
303 case VBLK:
b9a4d0ff
KM
304 if (com == 0 && (int)data == B_TAPE)
305 if (bdevsw[major(dev)].d_flags & B_TAPE)
306 return (0);
307 else
308 return (1);
a1d35437
KM
309 return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag));
310
311 default:
ad27f720 312 panic("spec_ioctl");
a1d35437
KM
313 /* NOTREACHED */
314 }
315}
316
3d5d83ff 317/* ARGSUSED */
fbb80d56 318spec_select(vp, which, fflags, cred)
a1d35437 319 struct vnode *vp;
fbb80d56 320 int which, fflags;
a1d35437
KM
321 struct ucred *cred;
322{
a1d35437
KM
323 register dev_t dev;
324
325 switch (vp->v_type) {
326
327 default:
328 return (1); /* XXX */
329
330 case VCHR:
3d5d83ff 331 dev = vp->v_rdev;
a1d35437
KM
332 return (*cdevsw[major(dev)].d_select)(dev, which);
333 }
334}
335
336/*
337 * Just call the device strategy routine
338 */
ad27f720 339spec_strategy(bp)
a1d35437
KM
340 register struct buf *bp;
341{
b9a4d0ff 342
a1d35437
KM
343 (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
344 return (0);
345}
346
b9a4d0ff
KM
347/*
348 * This is a noop, simply returning what one has been given.
349 */
350spec_bmap(vp, bn, vpp, bnp)
351 struct vnode *vp;
352 daddr_t bn;
353 struct vnode **vpp;
354 daddr_t *bnp;
355{
356
357 if (vpp != NULL)
358 *vpp = vp;
359 if (bnp != NULL)
360 *bnp = bn;
361 return (0);
362}
363
1c00bf64
KM
364/*
365 * At the moment we do not do any locking.
366 */
ff4fb102 367/* ARGSUSED */
ad27f720 368spec_lock(vp)
a1d35437
KM
369 struct vnode *vp;
370{
a1d35437 371
a1d35437
KM
372 return (0);
373}
374
ff4fb102 375/* ARGSUSED */
ad27f720 376spec_unlock(vp)
a1d35437
KM
377 struct vnode *vp;
378{
a1d35437 379
a1d35437
KM
380 return (0);
381}
382
a1d35437
KM
383/*
384 * Device close routine
385 */
3d5d83ff 386/* ARGSUSED */
ad27f720 387spec_close(vp, flag, cred)
3d5d83ff 388 register struct vnode *vp;
a1d35437
KM
389 int flag;
390 struct ucred *cred;
391{
392 dev_t dev = vp->v_rdev;
3d5d83ff
KM
393 int (*cfunc)();
394 int error, mode;
a1d35437 395
3d5d83ff
KM
396 switch (vp->v_type) {
397
398 case VCHR:
f4b3ea62
KM
399 /*
400 * If the vnode is locked, then we are in the midst
401 * of forcably closing the device, otherwise we only
402 * close on last reference.
403 */
3ab57521 404 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
3d5d83ff
KM
405 return (0);
406 cfunc = cdevsw[major(dev)].d_close;
1c00bf64 407 mode = S_IFCHR;
3d5d83ff
KM
408 break;
409
410 case VBLK:
411 /*
412 * On last close of a block device (that isn't mounted)
413 * we must invalidate any in core blocks, so that
414 * we can, for instance, change floppy disks.
415 */
b9a4d0ff
KM
416 vflushbuf(vp, 0);
417 if (vinvalbuf(vp, 1))
4a29fa35 418 return (0);
3d5d83ff 419 /*
f4b3ea62
KM
420 * We do not want to really close the device if it
421 * is still in use unless we are trying to close it
422 * forcibly. Since every use (buffer, vnode, swap, cmap)
3ab57521
KM
423 * holds a reference to the vnode, and because we mark
424 * any other vnodes that alias this device, when the
425 * sum of the reference counts on all the aliased
426 * vnodes descends to one, we are on last close.
3d5d83ff 427 */
3ab57521 428 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
3d5d83ff
KM
429 return (0);
430 cfunc = bdevsw[major(dev)].d_close;
1c00bf64 431 mode = S_IFBLK;
3d5d83ff
KM
432 break;
433
434 default:
ad27f720 435 panic("spec_close: not special");
3d5d83ff
KM
436 }
437
3d5d83ff
KM
438 if (setjmp(&u.u_qsave)) {
439 /*
440 * If device close routine is interrupted,
441 * must return so closef can clean up.
442 */
443 error = EINTR;
444 } else
445 error = (*cfunc)(dev, flag, mode);
3d5d83ff 446 return (error);
a1d35437
KM
447}
448
b9a4d0ff
KM
449/*
450 * Print out the contents of a special device vnode.
451 */
452spec_print(vp)
453 struct vnode *vp;
454{
455
456 printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev),
457 minor(vp->v_rdev));
458}
459
a1d35437 460/*
7bbe72a5
KM
461 * Special device failed operation
462 */
463spec_ebadf()
464{
465
466 return (EBADF);
467}
468
469/*
470 * Special device bad operation
a1d35437 471 */
ad27f720 472spec_badop()
a1d35437
KM
473{
474
ad27f720 475 panic("spec_badop called");
59b0713e 476 /* NOTREACHED */
a1d35437
KM
477}
478
479/*
7bbe72a5 480 * Special device null operation
a1d35437 481 */
ad27f720 482spec_nullop()
a1d35437
KM
483{
484
485 return (0);
486}