]> git.saurik.com Git - apple/xnu.git/blame - bsd/miscfs/specfs/spec_vnops.c
xnu-517.12.7.tar.gz
[apple/xnu.git] / bsd / miscfs / specfs / spec_vnops.c
CommitLineData
1c79356b 1/*
55e303ae 2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
1c79356b 11 *
e5568f75
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23/*
24 * Copyright (c) 1989, 1993, 1995
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 *
55 * @(#)spec_vnops.c 8.14 (Berkeley) 5/21/95
56 */
57
58#include <sys/param.h>
59#include <sys/proc.h>
60#include <sys/systm.h>
61#include <sys/kernel.h>
62#include <sys/conf.h>
63#include <sys/buf.h>
64#include <sys/mount.h>
65#include <sys/namei.h>
66#include <sys/vnode.h>
67#include <sys/stat.h>
68#include <sys/errno.h>
69#include <sys/ioctl.h>
70#include <sys/file.h>
71#include <sys/malloc.h>
55e303ae 72#include <sys/disk.h>
1c79356b 73#include <miscfs/specfs/specdev.h>
ccc36f2f 74#include <miscfs/specfs/lockf.h>
1c79356b
A
75#include <vfs/vfs_support.h>
76
9bccf70c 77#include <sys/kdebug.h>
1c79356b
A
78
79struct vnode *speclisth[SPECHSZ];
80
81/* symbolic sleep message strings for devices */
82char devopn[] = "devopn";
83char devio[] = "devio";
84char devwait[] = "devwait";
85char devin[] = "devin";
86char devout[] = "devout";
87char devioc[] = "devioc";
88char devcls[] = "devcls";
89
90#define VOPFUNC int (*)(void *)
91
92int (**spec_vnodeop_p)(void *);
93struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
94 { &vop_default_desc, (VOPFUNC)vn_default_error },
95 { &vop_lookup_desc, (VOPFUNC)spec_lookup }, /* lookup */
96 { &vop_create_desc, (VOPFUNC)err_create }, /* create */
97 { &vop_mknod_desc, (VOPFUNC)err_mknod }, /* mknod */
98 { &vop_open_desc, (VOPFUNC)spec_open }, /* open */
99 { &vop_close_desc, (VOPFUNC)spec_close }, /* close */
100 { &vop_access_desc, (VOPFUNC)spec_access }, /* access */
101 { &vop_getattr_desc, (VOPFUNC)spec_getattr }, /* getattr */
102 { &vop_setattr_desc, (VOPFUNC)spec_setattr }, /* setattr */
103 { &vop_read_desc, (VOPFUNC)spec_read }, /* read */
104 { &vop_write_desc, (VOPFUNC)spec_write }, /* write */
105 { &vop_lease_desc, (VOPFUNC)nop_lease }, /* lease */
106 { &vop_ioctl_desc, (VOPFUNC)spec_ioctl }, /* ioctl */
107 { &vop_select_desc, (VOPFUNC)spec_select }, /* select */
108 { &vop_revoke_desc, (VOPFUNC)nop_revoke }, /* revoke */
109 { &vop_mmap_desc, (VOPFUNC)err_mmap }, /* mmap */
110 { &vop_fsync_desc, (VOPFUNC)spec_fsync }, /* fsync */
111 { &vop_seek_desc, (VOPFUNC)err_seek }, /* seek */
112 { &vop_remove_desc, (VOPFUNC)err_remove }, /* remove */
113 { &vop_link_desc, (VOPFUNC)err_link }, /* link */
114 { &vop_rename_desc, (VOPFUNC)err_rename }, /* rename */
115 { &vop_mkdir_desc, (VOPFUNC)err_mkdir }, /* mkdir */
116 { &vop_rmdir_desc, (VOPFUNC)err_rmdir }, /* rmdir */
117 { &vop_symlink_desc, (VOPFUNC)err_symlink }, /* symlink */
118 { &vop_readdir_desc, (VOPFUNC)err_readdir }, /* readdir */
119 { &vop_readlink_desc, (VOPFUNC)err_readlink }, /* readlink */
120 { &vop_abortop_desc, (VOPFUNC)err_abortop }, /* abortop */
121 { &vop_inactive_desc, (VOPFUNC)nop_inactive }, /* inactive */
122 { &vop_reclaim_desc, (VOPFUNC)nop_reclaim }, /* reclaim */
123 { &vop_lock_desc, (VOPFUNC)nop_lock }, /* lock */
124 { &vop_unlock_desc, (VOPFUNC)nop_unlock }, /* unlock */
125 { &vop_bmap_desc, (VOPFUNC)spec_bmap }, /* bmap */
126 { &vop_strategy_desc, (VOPFUNC)spec_strategy }, /* strategy */
127 { &vop_print_desc, (VOPFUNC)spec_print }, /* print */
128 { &vop_islocked_desc, (VOPFUNC)nop_islocked }, /* islocked */
129 { &vop_pathconf_desc, (VOPFUNC)spec_pathconf }, /* pathconf */
ccc36f2f 130 { &vop_advlock_desc, (VOPFUNC)spec_advlock }, /* advlock */
1c79356b
A
131 { &vop_blkatoff_desc, (VOPFUNC)err_blkatoff }, /* blkatoff */
132 { &vop_valloc_desc, (VOPFUNC)err_valloc }, /* valloc */
133 { &vop_vfree_desc, (VOPFUNC)err_vfree }, /* vfree */
134 { &vop_truncate_desc, (VOPFUNC)nop_truncate }, /* truncate */
135 { &vop_update_desc, (VOPFUNC)nop_update }, /* update */
136 { &vop_bwrite_desc, (VOPFUNC)spec_bwrite }, /* bwrite */
137 { &vop_devblocksize_desc, (VOPFUNC)spec_devblocksize }, /* devblocksize */
138 { &vop_pagein_desc, (VOPFUNC)err_pagein }, /* Pagein */
139 { &vop_pageout_desc, (VOPFUNC)err_pageout }, /* Pageout */
140 { &vop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */
141 { &vop_blktooff_desc, (VOPFUNC)spec_blktooff }, /* blktooff */
142 { &vop_offtoblk_desc, (VOPFUNC)spec_offtoblk }, /* offtoblk */
143 { &vop_cmap_desc, (VOPFUNC)spec_cmap }, /* cmap */
144 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
145};
146struct vnodeopv_desc spec_vnodeop_opv_desc =
147 { &spec_vnodeop_p, spec_vnodeop_entries };
148
149/*
150 * Trivial lookup routine that always fails.
151 */
152int
153spec_lookup(ap)
154 struct vop_lookup_args /* {
155 struct vnode *a_dvp;
156 struct vnode **a_vpp;
157 struct componentname *a_cnp;
158 } */ *ap;
159{
160
161 *ap->a_vpp = NULL;
162 return (ENOTDIR);
163}
164
165void
166set_blocksize(struct vnode *vp, dev_t dev)
167{
168 int (*size)();
169 int rsize;
170
171 if ((major(dev) < nblkdev) && (size = bdevsw[major(dev)].d_psize)) {
172 rsize = (*size)(dev);
173 if (rsize <= 0) /* did size fail? */
174 vp->v_specsize = DEV_BSIZE;
175 else
176 vp->v_specsize = rsize;
177 }
178 else
179 vp->v_specsize = DEV_BSIZE;
180}
181
182void
183set_fsblocksize(struct vnode *vp)
184{
185
186 if (vp->v_type == VBLK) {
187 dev_t dev = (dev_t)vp->v_rdev;
188 int maj = major(dev);
189
190 if ((u_int)maj >= nblkdev)
191 return;
192
193 set_blocksize(vp, dev);
194 }
195
196}
197
198
199/*
200 * Open a special file.
201 */
202/* ARGSUSED */
203spec_open(ap)
204 struct vop_open_args /* {
205 struct vnode *a_vp;
206 int a_mode;
207 struct ucred *a_cred;
208 struct proc *a_p;
209 } */ *ap;
210{
211 struct proc *p = ap->a_p;
212 struct vnode *bvp, *vp = ap->a_vp;
213 dev_t bdev, dev = (dev_t)vp->v_rdev;
214 int maj = major(dev);
215 int error;
216
217 /*
218 * Don't allow open if fs is mounted -nodev.
219 */
220 if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
221 return (ENXIO);
222
223 switch (vp->v_type) {
224
225 case VCHR:
226 if ((u_int)maj >= nchrdev)
227 return (ENXIO);
228 if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) {
229 /*
230 * When running in very secure mode, do not allow
231 * opens for writing of any disk character devices.
232 */
233 if (securelevel >= 2 && isdisk(dev, VCHR))
234 return (EPERM);
235 /*
236 * When running in secure mode, do not allow opens
237 * for writing of /dev/mem, /dev/kmem, or character
238 * devices whose corresponding block devices are
239 * currently mounted.
240 */
241 if (securelevel >= 1) {
242 if ((bdev = chrtoblk(dev)) != NODEV &&
243 vfinddev(bdev, VBLK, &bvp) &&
244 bvp->v_usecount > 0 &&
245 (error = vfs_mountedon(bvp)))
246 return (error);
247 if (iskmemdev(dev))
248 return (EPERM);
249 }
250 }
251 if (cdevsw[maj].d_type == D_TTY)
252 vp->v_flag |= VISTTY;
253 VOP_UNLOCK(vp, 0, p);
254 error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, p);
255 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
256 return (error);
257
258 case VBLK:
259 if ((u_int)maj >= nblkdev)
260 return (ENXIO);
261 /*
262 * When running in very secure mode, do not allow
263 * opens for writing of any disk block devices.
264 */
265 if (securelevel >= 2 && ap->a_cred != FSCRED &&
266 (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK)
267 return (EPERM);
268 /*
269 * Do not allow opens of block devices that are
270 * currently mounted.
271 */
272 if (error = vfs_mountedon(vp))
273 return (error);
274 error = (*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, p);
275 if (!error) {
55e303ae
A
276 u_int64_t blkcnt;
277 u_int32_t blksize;
278
1c79356b 279 set_blocksize(vp, dev);
55e303ae
A
280
281 /*
282 * Cache the size in bytes of the block device for later
283 * use by spec_write().
284 */
285 vp->v_specdevsize = (u_int64_t)0; /* Default: Can't get */
286 if (!VOP_IOCTL(vp, DKIOCGETBLOCKSIZE, (caddr_t)&blksize, 0, NOCRED, p)) {
287 /* Switch to 512 byte sectors (temporarily) */
288 u_int32_t size512 = 512;
289
290 if (!VOP_IOCTL(vp, DKIOCSETBLOCKSIZE, (caddr_t)&size512, FWRITE, NOCRED, p)) {
291 /* Get the number of 512 byte physical blocks. */
292 if (!VOP_IOCTL(vp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, NOCRED, p)) {
293 vp->v_specdevsize = blkcnt * (u_int64_t)size512;
294 }
295 }
296 /* If it doesn't set back, we can't recover */
297 if (VOP_IOCTL(vp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, NOCRED, p))
298 error = ENXIO;
299 }
1c79356b
A
300 }
301 return(error);
302 }
303 return (0);
304}
305
306/*
307 * Vnode op for read
308 */
309/* ARGSUSED */
310spec_read(ap)
311 struct vop_read_args /* {
312 struct vnode *a_vp;
313 struct uio *a_uio;
314 int a_ioflag;
315 struct ucred *a_cred;
316 } */ *ap;
317{
318 register struct vnode *vp = ap->a_vp;
319 register struct uio *uio = ap->a_uio;
320 struct proc *p = uio->uio_procp;
321 struct buf *bp;
322 daddr_t bn, nextbn;
323 long bsize, bscale;
324 int devBlockSize=0;
325 int n, on, majordev, (*ioctl)();
326 int error = 0;
327 dev_t dev;
328
329#if DIAGNOSTIC
330 if (uio->uio_rw != UIO_READ)
331 panic("spec_read mode");
332 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != current_proc())
333 panic("spec_read proc");
334#endif
335 if (uio->uio_resid == 0)
336 return (0);
337
338 switch (vp->v_type) {
339
340 case VCHR:
341 VOP_UNLOCK(vp, 0, p);
342 error = (*cdevsw[major(vp->v_rdev)].d_read)
343 (vp->v_rdev, uio, ap->a_ioflag);
344 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
345 return (error);
346
347 case VBLK:
348 if (uio->uio_offset < 0)
349 return (EINVAL);
350
351 dev = vp->v_rdev;
352
353 devBlockSize = vp->v_specsize;
354
355 if (devBlockSize > PAGE_SIZE)
356 return (EINVAL);
357
358 bscale = PAGE_SIZE / devBlockSize;
359 bsize = bscale * devBlockSize;
360
361 do {
362 on = uio->uio_offset % bsize;
363
364 bn = (uio->uio_offset / devBlockSize) &~ (bscale - 1);
365
366 if (vp->v_lastr + bscale == bn) {
367 nextbn = bn + bscale;
368 error = breadn(vp, bn, (int)bsize, &nextbn,
369 (int *)&bsize, 1, NOCRED, &bp);
370 } else
371 error = bread(vp, bn, (int)bsize, NOCRED, &bp);
372
373 vp->v_lastr = bn;
374 n = bsize - bp->b_resid;
375 if ((on > n) || error) {
376 if (!error)
377 error = EINVAL;
378 brelse(bp);
379 return (error);
380 }
381 n = min((unsigned)(n - on), uio->uio_resid);
382
383 error = uiomove((char *)bp->b_data + on, n, uio);
384 if (n + on == bsize)
385 bp->b_flags |= B_AGE;
386 brelse(bp);
387 } while (error == 0 && uio->uio_resid > 0 && n != 0);
388 return (error);
389
390 default:
391 panic("spec_read type");
392 }
393 /* NOTREACHED */
394}
395
396/*
397 * Vnode op for write
398 */
399/* ARGSUSED */
400spec_write(ap)
401 struct vop_write_args /* {
402 struct vnode *a_vp;
403 struct uio *a_uio;
404 int a_ioflag;
405 struct ucred *a_cred;
406 } */ *ap;
407{
408 register struct vnode *vp = ap->a_vp;
409 register struct uio *uio = ap->a_uio;
410 struct proc *p = uio->uio_procp;
411 struct buf *bp;
412 daddr_t bn;
413 int bsize, blkmask, bscale;
414 register int io_sync;
415 register int io_size;
416 int devBlockSize=0;
417 register int n, on;
418 int error = 0;
419 dev_t dev;
420
421#if DIAGNOSTIC
422 if (uio->uio_rw != UIO_WRITE)
423 panic("spec_write mode");
424 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != current_proc())
425 panic("spec_write proc");
426#endif
427
428 switch (vp->v_type) {
429
430 case VCHR:
431 VOP_UNLOCK(vp, 0, p);
432 error = (*cdevsw[major(vp->v_rdev)].d_write)
433 (vp->v_rdev, uio, ap->a_ioflag);
434 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
435 return (error);
436
437 case VBLK:
438 if (uio->uio_resid == 0)
439 return (0);
440 if (uio->uio_offset < 0)
441 return (EINVAL);
442
443 io_sync = (ap->a_ioflag & IO_SYNC);
444 io_size = uio->uio_resid;
445
446 dev = (vp->v_rdev);
447
448 devBlockSize = vp->v_specsize;
449 if (devBlockSize > PAGE_SIZE)
450 return(EINVAL);
451
452 bscale = PAGE_SIZE / devBlockSize;
453 blkmask = bscale - 1;
454 bsize = bscale * devBlockSize;
455
456
457 do {
458 bn = (uio->uio_offset / devBlockSize) &~ blkmask;
459 on = uio->uio_offset % bsize;
460
461 n = min((unsigned)(bsize - on), uio->uio_resid);
462
55e303ae
A
463 /*
464 * Use getblk() as an optimization IFF:
465 *
466 * 1) We are reading exactly a block on a block
467 * aligned boundary
468 * 2) We know the size of the device from spec_open
469 * 3) The read doesn't span the end of the device
470 *
471 * Otherwise, we fall back on bread().
472 */
473 if (n == bsize &&
474 vp->v_specdevsize != (u_int64_t)0 &&
475 (uio->uio_offset + (u_int64_t)n) > vp->v_specdevsize) {
476 /* reduce the size of the read to what is there */
477 n = (uio->uio_offset + (u_int64_t)n) - vp->v_specdevsize;
478 }
479
1c79356b
A
480 if (n == bsize)
481 bp = getblk(vp, bn, bsize, 0, 0, BLK_WRITE);
482 else
483 error = bread(vp, bn, bsize, NOCRED, &bp);
484
55e303ae
A
485 /* Translate downstream error for upstream, if needed */
486 if (!error) {
487 error = bp->b_error;
488 if (!error && (bp->b_flags & B_ERROR) != 0) {
489 error = EIO;
490 }
491 }
1c79356b
A
492 if (error) {
493 brelse(bp);
494 return (error);
495 }
496 n = min(n, bsize - bp->b_resid);
497
498 error = uiomove((char *)bp->b_data + on, n, uio);
499
500 bp->b_flags |= B_AGE;
501
502 if (io_sync)
503 bwrite(bp);
504 else {
505 if ((n + on) == bsize)
506 bawrite(bp);
507 else
508 bdwrite(bp);
509 }
510 } while (error == 0 && uio->uio_resid > 0 && n != 0);
511 return (error);
512
513 default:
514 panic("spec_write type");
515 }
516 /* NOTREACHED */
517}
518
519/*
520 * Device ioctl operation.
521 */
522/* ARGSUSED */
523spec_ioctl(ap)
524 struct vop_ioctl_args /* {
525 struct vnode *a_vp;
526 int a_command;
527 caddr_t a_data;
528 int a_fflag;
529 struct ucred *a_cred;
530 struct proc *a_p;
531 } */ *ap;
532{
533 dev_t dev = ap->a_vp->v_rdev;
534
535 switch (ap->a_vp->v_type) {
536
537 case VCHR:
538 return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
539 ap->a_fflag, ap->a_p));
540
541 case VBLK:
542 if (ap->a_command == 0 && (int)ap->a_data == B_TAPE)
543 if (bdevsw[major(dev)].d_type == D_TAPE)
544 return (0);
545 else
546 return (1);
547 return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
548 ap->a_fflag, ap->a_p));
549
550 default:
551 panic("spec_ioctl");
552 /* NOTREACHED */
553 }
554}
555
556/* ARGSUSED */
557spec_select(ap)
558 struct vop_select_args /* {
559 struct vnode *a_vp;
560 int a_which;
561 int a_fflags;
562 struct ucred *a_cred;
0b4e3aa0 563 void * a_wql;
1c79356b
A
564 struct proc *a_p;
565 } */ *ap;
566{
567 register dev_t dev;
568
569 switch (ap->a_vp->v_type) {
570
571 default:
572 return (1); /* XXX */
573
574 case VCHR:
575 dev = ap->a_vp->v_rdev;
0b4e3aa0 576 return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_wql, ap->a_p);
1c79356b
A
577 }
578}
579/*
580 * Synch buffers associated with a block device
581 */
582/* ARGSUSED */
583int
584spec_fsync(ap)
585 struct vop_fsync_args /* {
586 struct vnode *a_vp;
587 struct ucred *a_cred;
588 int a_waitfor;
589 struct proc *a_p;
590 } */ *ap;
591{
592 register struct vnode *vp = ap->a_vp;
593 register struct buf *bp;
594 struct buf *nbp;
595 int s;
596
597 if (vp->v_type == VCHR)
598 return (0);
599 /*
600 * Flush all dirty buffers associated with a block device.
601 */
602loop:
603 s = splbio();
604 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
605 nbp = bp->b_vnbufs.le_next;
b4c24cb9
A
606 // XXXdbg - don't flush locked blocks. they may be journaled.
607 if ((bp->b_flags & B_BUSY) || (bp->b_flags & B_LOCKED))
1c79356b
A
608 continue;
609 if ((bp->b_flags & B_DELWRI) == 0)
610 panic("spec_fsync: not dirty");
611 bremfree(bp);
612 bp->b_flags |= B_BUSY;
613 splx(s);
614 bawrite(bp);
615 goto loop;
616 }
617 if (ap->a_waitfor == MNT_WAIT) {
618 while (vp->v_numoutput) {
619 vp->v_flag |= VBWAIT;
620 tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "spec_fsync", 0);
621 }
622#if DIAGNOSTIC
623 if (vp->v_dirtyblkhd.lh_first) {
624 vprint("spec_fsync: dirty", vp);
625 splx(s);
626 goto loop;
627 }
628#endif
629 }
630 splx(s);
631 return (0);
632}
633
634/*
635 * Just call the device strategy routine
636 */
637spec_strategy(ap)
638 struct vop_strategy_args /* {
639 struct buf *a_bp;
640 } */ *ap;
641{
9bccf70c 642 struct buf *bp;
55e303ae 643 extern int hard_throttle_on_root;
9bccf70c
A
644
645 bp = ap->a_bp;
646
647 if (kdebug_enable) {
648 int code = 0;
649
650 if (bp->b_flags & B_READ)
651 code |= DKIO_READ;
652 if (bp->b_flags & B_ASYNC)
653 code |= DKIO_ASYNC;
654
655 if (bp->b_flags & B_META)
656 code |= DKIO_META;
657 else if (bp->b_flags & (B_PGIN | B_PAGEOUT))
658 code |= DKIO_PAGING;
659
660 KERNEL_DEBUG_CONSTANT(FSDBG_CODE(DBG_DKRW, code) | DBG_FUNC_NONE,
55e303ae 661 (unsigned int)bp, bp->b_dev, bp->b_blkno, bp->b_bcount, 0);
9bccf70c 662 }
55e303ae
A
663 if ((bp->b_flags & B_PGIN) && (bp->b_vp->v_mount->mnt_kern_flag & MNTK_ROOTDEV))
664 hard_throttle_on_root = 1;
665
9bccf70c
A
666 (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
667 return (0);
1c79356b
A
668}
669
ccc36f2f
A
670/*
671 * Advisory record locking support
672 */
673int
674spec_advlock(ap)
675 struct vop_advlock_args /* {
676 struct vnode *a_vp;
677 caddr_t a_id;
678 int a_op;
679 struct flock *a_fl;
680 int a_flags;
681 } */ *ap;
682{
683 register struct flock *fl = ap->a_fl;
684 register struct lockf *lock;
685 off_t start, end;
686 int error;
687
688 /*
689 * Avoid the common case of unlocking when inode has no locks.
690 */
691 if (ap->a_vp->v_specinfo->si_lockf == (struct lockf *)0) {
692 if (ap->a_op != F_SETLK) {
693 fl->l_type = F_UNLCK;
694 return (0);
695 }
696 }
697 /*
698 * Convert the flock structure into a start and end.
699 */
700 switch (fl->l_whence) {
701
702 case SEEK_SET:
703 case SEEK_CUR:
704 /*
705 * Caller is responsible for adding any necessary offset
706 * when SEEK_CUR is used.
707 */
708 start = fl->l_start;
709 break;
710
711 case SEEK_END:
712 start = ap->a_vp->v_specinfo->si_devsize + fl->l_start;
713 break;
714
715 default:
716 return (EINVAL);
717 }
718 if (fl->l_len == 0)
719 end = -1;
720 else if (fl->l_len > 0)
721 end = start + fl->l_len - 1;
722 else { /* l_len is negative */
723 end = start - 1;
724 start += fl->l_len;
725 }
726 if (start < 0)
727 return (EINVAL);
728 /*
729 * Create the lockf structure
730 */
731 MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK);
732 lock->lf_start = start;
733 lock->lf_end = end;
734 lock->lf_id = ap->a_id;
735 lock->lf_specinfo = ap->a_vp->v_specinfo;
736 lock->lf_type = fl->l_type;
737 lock->lf_next = (struct lockf *)0;
738 TAILQ_INIT(&lock->lf_blkhd);
739 lock->lf_flags = ap->a_flags;
740 /*
741 * Do the requested operation.
742 */
743 switch(ap->a_op) {
744 case F_SETLK:
745 return (spec_lf_setlock(lock));
746
747 case F_UNLCK:
748 error = spec_lf_clearlock(lock);
749 FREE(lock, M_LOCKF);
750 return (error);
751
752 case F_GETLK:
753 error = spec_lf_getlock(lock, fl);
754 FREE(lock, M_LOCKF);
755 return (error);
756
757 default:
758 _FREE(lock, M_LOCKF);
759 return (EINVAL);
760 }
761 /* NOTREACHED */
762}
763
1c79356b
A
764/*
765 * This is a noop, simply returning what one has been given.
766 */
767spec_bmap(ap)
768 struct vop_bmap_args /* {
769 struct vnode *a_vp;
770 daddr_t a_bn;
771 struct vnode **a_vpp;
772 daddr_t *a_bnp;
773 int *a_runp;
774 } */ *ap;
775{
776
777 if (ap->a_vpp != NULL)
778 *ap->a_vpp = ap->a_vp;
779 if (ap->a_bnp != NULL)
780 *ap->a_bnp = ap->a_bn * (PAGE_SIZE / ap->a_vp->v_specsize);
781 if (ap->a_runp != NULL)
782 *ap->a_runp = (MAXPHYSIO / PAGE_SIZE) - 1;
783 return (0);
784}
785
786/*
787 * This is a noop, simply returning what one has been given.
788 */
789spec_cmap(ap)
790 struct vop_cmap_args /* {
791 struct vnode *a_vp;
792 off_t a_offset;
793 size_t a_size;
794 daddr_t *a_bpn;
795 size_t *a_run;
796 void *a_poff;
797 } */ *ap;
798{
799 return (EOPNOTSUPP);
800}
801
802
803/*
804 * Device close routine
805 */
806/* ARGSUSED */
807spec_close(ap)
808 struct vop_close_args /* {
809 struct vnode *a_vp;
810 int a_fflag;
811 struct ucred *a_cred;
812 struct proc *a_p;
813 } */ *ap;
814{
815 register struct vnode *vp = ap->a_vp;
816 dev_t dev = vp->v_rdev;
817 int (*devclose) __P((dev_t, int, int, struct proc *));
818 int mode, error;
819
820 switch (vp->v_type) {
821
822 case VCHR:
823 /*
824 * Hack: a tty device that is a controlling terminal
825 * has a reference from the session structure.
826 * We cannot easily tell that a character device is
827 * a controlling terminal, unless it is the closing
828 * process' controlling terminal. In that case,
829 * if the reference count is 2 (this last descriptor
830 * plus the session), release the reference from the session.
831 */
832 if (vcount(vp) == 2 && ap->a_p &&
833 vp == ap->a_p->p_session->s_ttyvp) {
1c79356b 834 ap->a_p->p_session->s_ttyvp = NULL;
fa4905b1 835 vrele(vp);
1c79356b
A
836 }
837 /*
838 * If the vnode is locked, then we are in the midst
839 * of forcably closing the device, otherwise we only
840 * close on last reference.
841 */
842 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
843 return (0);
844 devclose = cdevsw[major(dev)].d_close;
845 mode = S_IFCHR;
846 break;
847
848 case VBLK:
0b4e3aa0 849#ifdef DEVFS_IMPLEMENTS_LOCKING
1c79356b
A
850 /*
851 * On last close of a block device (that isn't mounted)
852 * we must invalidate any in core blocks, so that
853 * we can, for instance, change floppy disks.
854 */
0b4e3aa0
A
855 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
856 error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0);
857 VOP_UNLOCK(vp, 0, ap->a_p);
858 if (error)
1c79356b
A
859 return (error);
860 /*
861 * We do not want to really close the device if it
862 * is still in use unless we are trying to close it
863 * forcibly. Since every use (buffer, vnode, swap, cmap)
864 * holds a reference to the vnode, and because we mark
865 * any other vnodes that alias this device, when the
866 * sum of the reference counts on all the aliased
867 * vnodes descends to one, we are on last close.
868 */
869 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
870 return (0);
0b4e3aa0
A
871#else /* DEVFS_IMPLEMENTS_LOCKING */
872 /*
873 * We do not want to really close the device if it
874 * is still in use unless we are trying to close it
875 * forcibly. Since every use (buffer, vnode, swap, cmap)
876 * holds a reference to the vnode, and because we mark
877 * any other vnodes that alias this device, when the
878 * sum of the reference counts on all the aliased
879 * vnodes descends to one, we are on last close.
880 */
881 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
882 return (0);
883
884 /*
885 * On last close of a block device (that isn't mounted)
886 * we must invalidate any in core blocks, so that
887 * we can, for instance, change floppy disks.
888 */
889 error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0);
890 if (error)
891 return (error);
892#endif /* DEVFS_IMPLEMENTS_LOCKING */
1c79356b
A
893 devclose = bdevsw[major(dev)].d_close;
894 mode = S_IFBLK;
895 break;
896
897 default:
898 panic("spec_close: not special");
899 }
900
901 return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p));
902}
903
904/*
905 * Print out the contents of a special device vnode.
906 */
907spec_print(ap)
908 struct vop_print_args /* {
909 struct vnode *a_vp;
910 } */ *ap;
911{
912
913 printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev),
914 minor(ap->a_vp->v_rdev));
915}
916
917/*
918 * Return POSIX pathconf information applicable to special devices.
919 */
920spec_pathconf(ap)
921 struct vop_pathconf_args /* {
922 struct vnode *a_vp;
923 int a_name;
924 int *a_retval;
925 } */ *ap;
926{
927
928 switch (ap->a_name) {
929 case _PC_LINK_MAX:
930 *ap->a_retval = LINK_MAX;
931 return (0);
932 case _PC_MAX_CANON:
933 *ap->a_retval = MAX_CANON;
934 return (0);
935 case _PC_MAX_INPUT:
936 *ap->a_retval = MAX_INPUT;
937 return (0);
938 case _PC_PIPE_BUF:
939 *ap->a_retval = PIPE_BUF;
940 return (0);
941 case _PC_CHOWN_RESTRICTED:
942 *ap->a_retval = 1;
943 return (0);
944 case _PC_VDISABLE:
945 *ap->a_retval = _POSIX_VDISABLE;
946 return (0);
947 default:
948 return (EINVAL);
949 }
950 /* NOTREACHED */
951}
952
953int
954spec_devblocksize(ap)
955 struct vop_devblocksize_args /* {
956 struct vnode *a_vp;
957 int *a_retval;
958 } */ *ap;
959{
960 *ap->a_retval = (ap->a_vp->v_specsize);
961 return (0);
962}
963
964/*
965 * Special device failed operation
966 */
967spec_ebadf()
968{
969
970 return (EBADF);
971}
972
973/*
974 * Special device bad operation
975 */
976spec_badop()
977{
978
979 panic("spec_badop called");
980 /* NOTREACHED */
981}
982
983/* Blktooff derives file offset from logical block number */
984int
985spec_blktooff(ap)
986 struct vop_blktooff_args /* {
987 struct vnode *a_vp;
988 daddr_t a_lblkno;
989 off_t *a_offset;
990 } */ *ap;
991{
992 register struct vnode *vp = ap->a_vp;
993
994 switch (vp->v_type) {
995 case VCHR:
996 *ap->a_offset = (off_t)-1; /* failure */
997 return (EOPNOTSUPP);
998
999 case VBLK:
1000 printf("spec_blktooff: not implemented for VBLK\n");
1001 *ap->a_offset = (off_t)-1; /* failure */
1002 return (EOPNOTSUPP);
1003
1004 default:
1005 panic("spec_blktooff type");
1006 }
1007 /* NOTREACHED */
1008}
1009
1010/* Offtoblk derives logical block number from file offset */
1011int
1012spec_offtoblk(ap)
1013 struct vop_offtoblk_args /* {
1014 struct vnode *a_vp;
1015 off_t a_offset;
1016 daddr_t *a_lblkno;
1017 } */ *ap;
1018{
1019 register struct vnode *vp = ap->a_vp;
1020
1021 switch (vp->v_type) {
1022 case VCHR:
1023 *ap->a_lblkno = (daddr_t)-1; /* failure */
1024 return (EOPNOTSUPP);
1025
1026 case VBLK:
1027 printf("spec_offtoblk: not implemented for VBLK\n");
1028 *ap->a_lblkno = (daddr_t)-1; /* failure */
1029 return (EOPNOTSUPP);
1030
1031 default:
1032 panic("spec_offtoblk type");
1033 }
1034 /* NOTREACHED */
1035}