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