vnd.c revision 1.36 1 /* $NetBSD: vnd.c,v 1.36 1997/05/25 19:37:36 pk Exp $ */
2
3 /*
4 * Copyright (c) 1988 University of Utah.
5 * Copyright (c) 1990, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * the Systems Programming Group of the University of Utah Computer
10 * Science Department.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * from: Utah $Hdr: vn.c 1.13 94/04/02$
41 *
42 * @(#)vn.c 8.6 (Berkeley) 4/1/94
43 */
44
45 /*
46 * Vnode disk driver.
47 *
48 * Block/character interface to a vnode. Allows one to treat a file
49 * as a disk (e.g. build a filesystem in it, mount it, etc.).
50 *
51 * NOTE 1: This uses the VOP_BMAP/VOP_STRATEGY interface to the vnode
52 * instead of a simple VOP_RDWR. We do this to avoid distorting the
53 * local buffer cache.
54 *
55 * NOTE 2: There is a security issue involved with this driver.
56 * Once mounted all access to the contents of the "mapped" file via
57 * the special file is controlled by the permissions on the special
58 * file, the protection of the mapped file is ignored (effectively,
59 * by using root credentials in all transactions).
60 *
61 * NOTE 3: Doesn't interact with leases, should it?
62 */
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/namei.h>
67 #include <sys/proc.h>
68 #include <sys/errno.h>
69 #include <sys/buf.h>
70 #include <sys/malloc.h>
71 #include <sys/ioctl.h>
72 #include <sys/disklabel.h>
73 #include <sys/device.h>
74 #include <sys/disk.h>
75 #include <sys/stat.h>
76 #include <sys/mount.h>
77 #include <sys/vnode.h>
78 #include <sys/file.h>
79 #include <sys/uio.h>
80 #include <sys/conf.h>
81
82 #include <miscfs/specfs/specdev.h>
83
84 #include <dev/vndioctl.h>
85
86 #ifdef DEBUG
87 int dovndcluster = 1;
88 int vnddebug = 0x00;
89 #define VDB_FOLLOW 0x01
90 #define VDB_INIT 0x02
91 #define VDB_IO 0x04
92 #endif
93
94 #define b_cylin b_resid
95
96 #define vndunit(x) DISKUNIT(x)
97
98 struct vndxfer {
99 struct buf *vx_bp; /* Pointer to parent buffer */
100 int vx_error;
101 int vx_pending; /* # of pending aux buffers */
102 };
103
104 struct vndbuf {
105 struct buf vb_buf;
106 struct vndxfer *vb_xfer;
107 };
108
109 #define getvndxfer() \
110 ((struct vndxfer *)malloc(sizeof(struct vndxfer), M_DEVBUF, M_WAITOK))
111 #define putvndxfer(vnx) \
112 free((caddr_t)(vnx), M_DEVBUF)
113 #define getvndbuf() \
114 ((struct vndbuf *)malloc(sizeof(struct vndbuf), M_DEVBUF, M_WAITOK))
115 #define putvndbuf(vbp) \
116 free((caddr_t)(vbp), M_DEVBUF)
117
118 struct vnd_softc {
119 int sc_flags; /* flags */
120 size_t sc_size; /* size of vnd */
121 struct vnode *sc_vp; /* vnode */
122 struct ucred *sc_cred; /* credentials */
123 int sc_maxactive; /* max # of active requests */
124 struct buf sc_tab; /* transfer queue */
125 char sc_xname[8]; /* XXX external name */
126 struct disk sc_dkdev; /* generic disk device info */
127 };
128
129 /* sc_flags */
130 #define VNF_ALIVE 0x01
131 #define VNF_INITED 0x02
132 #define VNF_WANTED 0x40
133 #define VNF_LOCKED 0x80
134
135 struct vnd_softc *vnd_softc;
136 int numvnd = 0;
137
138 /* called by main() at boot time */
139 void vndattach __P((int));
140
141 void vndclear __P((struct vnd_softc *));
142 void vndstart __P((struct vnd_softc *));
143 int vndsetcred __P((struct vnd_softc *, struct ucred *));
144 void vndthrottle __P((struct vnd_softc *, struct vnode *));
145 void vndiodone __P((struct buf *));
146 void vndshutdown __P((void));
147
148 static int vndlock __P((struct vnd_softc *));
149 static void vndunlock __P((struct vnd_softc *));
150
151 void
152 vndattach(num)
153 int num;
154 {
155 char *mem;
156 register u_long size;
157
158 if (num <= 0)
159 return;
160 size = num * sizeof(struct vnd_softc);
161 mem = malloc(size, M_DEVBUF, M_NOWAIT);
162 if (mem == NULL) {
163 printf("WARNING: no memory for vnode disks\n");
164 return;
165 }
166 bzero(mem, size);
167 vnd_softc = (struct vnd_softc *)mem;
168 numvnd = num;
169 }
170
171 int
172 vndopen(dev, flags, mode, p)
173 dev_t dev;
174 int flags, mode;
175 struct proc *p;
176 {
177 int unit = vndunit(dev);
178 struct vnd_softc *sc;
179 int error = 0, part, pmask;
180
181 /*
182 * XXX Should support disklabels.
183 */
184
185 #ifdef DEBUG
186 if (vnddebug & VDB_FOLLOW)
187 printf("vndopen(%x, %x, %x, %p)\n", dev, flags, mode, p);
188 #endif
189 if (unit >= numvnd)
190 return (ENXIO);
191 sc = &vnd_softc[unit];
192
193 if ((error = vndlock(sc)) != 0)
194 return (error);
195
196 part = DISKPART(dev);
197 pmask = (1 << part);
198
199 /* Prevent our unit from being unconfigured while open. */
200 switch (mode) {
201 case S_IFCHR:
202 sc->sc_dkdev.dk_copenmask |= pmask;
203 break;
204
205 case S_IFBLK:
206 sc->sc_dkdev.dk_bopenmask |= pmask;
207 break;
208 }
209 sc->sc_dkdev.dk_openmask =
210 sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask;
211
212 vndunlock(sc);
213 return (0);
214 }
215
216 int
217 vndclose(dev, flags, mode, p)
218 dev_t dev;
219 int flags, mode;
220 struct proc *p;
221 {
222 int unit = vndunit(dev);
223 struct vnd_softc *sc;
224 int error = 0, part;
225
226 #ifdef DEBUG
227 if (vnddebug & VDB_FOLLOW)
228 printf("vndclose(%x, %x, %x, %p)\n", dev, flags, mode, p);
229 #endif
230
231 if (unit >= numvnd)
232 return (ENXIO);
233 sc = &vnd_softc[unit];
234
235 if ((error = vndlock(sc)) != 0)
236 return (error);
237
238 part = DISKPART(dev);
239
240 /* ...that much closer to allowing unconfiguration... */
241 switch (mode) {
242 case S_IFCHR:
243 sc->sc_dkdev.dk_copenmask &= ~(1 << part);
244 break;
245
246 case S_IFBLK:
247 sc->sc_dkdev.dk_bopenmask &= ~(1 << part);
248 break;
249 }
250 sc->sc_dkdev.dk_openmask =
251 sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask;
252
253 vndunlock(sc);
254 return (0);
255 }
256
257 /*
258 * Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY.
259 * Note that this driver can only be used for swapping over NFS on the hp
260 * since nfs_strategy on the vax cannot handle u-areas and page tables.
261 */
262 void
263 vndstrategy(bp)
264 register struct buf *bp;
265 {
266 int unit = vndunit(bp->b_dev);
267 register struct vnd_softc *vnd = &vnd_softc[unit];
268 register struct vndbuf *nbp;
269 struct vndxfer *vnx;
270 register int bn, bsize, resid;
271 register caddr_t addr;
272 int sz, flags, error;
273
274 #ifdef DEBUG
275 if (vnddebug & VDB_FOLLOW)
276 printf("vndstrategy(%p): unit %d\n", bp, unit);
277 #endif
278 if ((vnd->sc_flags & VNF_INITED) == 0) {
279 bp->b_error = ENXIO;
280 bp->b_flags |= B_ERROR;
281 biodone(bp);
282 return;
283 }
284 bn = bp->b_blkno;
285 sz = howmany(bp->b_bcount, DEV_BSIZE);
286 bp->b_resid = bp->b_bcount;
287 if (bn < 0 || bn + sz > vnd->sc_size) {
288 if (bn != vnd->sc_size) {
289 bp->b_error = EINVAL;
290 bp->b_flags |= B_ERROR;
291 }
292 biodone(bp);
293 return;
294 }
295 bn = dbtob(bn);
296 bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize;
297 addr = bp->b_data;
298 flags = bp->b_flags | B_CALL;
299
300 /* Allocate a header for this transfer and link it to the buffer */
301 vnx = getvndxfer();
302 vnx->vx_error = 0;
303 vnx->vx_pending = 0;
304 vnx->vx_bp = bp;
305
306 for (resid = bp->b_resid; resid; resid -= sz) {
307 struct vnode *vp;
308 daddr_t nbn;
309 int off, s, nra;
310
311 nra = 0;
312 VOP_LOCK(vnd->sc_vp);
313 error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra);
314 VOP_UNLOCK(vnd->sc_vp);
315 if (error == 0 && (long)nbn == -1)
316 error = EIO;
317
318 /*
319 * If there was an error or a hole in the file...punt.
320 * Note that we may have to wait for any operations
321 * that we have already fired off before releasing
322 * the buffer.
323 *
324 * XXX we could deal with holes here but it would be
325 * a hassle (in the write case).
326 */
327 if (error) {
328 vnx->vx_error = error;
329 if (vnx->vx_pending == 0) {
330 bp->b_error = error;
331 bp->b_flags |= B_ERROR;
332 putvndxfer(vnx);
333 biodone(bp);
334 }
335 return;
336 }
337
338 #ifdef DEBUG
339 if (!dovndcluster)
340 nra = 0;
341 #endif
342
343 if ((off = bn % bsize) != 0)
344 sz = bsize - off;
345 else
346 sz = (1 + nra) * bsize;
347 if (resid < sz)
348 sz = resid;
349 #ifdef DEBUG
350 if (vnddebug & VDB_IO)
351 printf("vndstrategy: vp %p/%p bn %x/%x sz %x\n",
352 vnd->sc_vp, vp, bn, nbn, sz);
353 #endif
354
355 nbp = getvndbuf();
356 nbp->vb_buf.b_flags = flags;
357 nbp->vb_buf.b_bcount = sz;
358 nbp->vb_buf.b_bufsize = bp->b_bufsize;
359 nbp->vb_buf.b_error = 0;
360 if (vp->v_type == VBLK || vp->v_type == VCHR)
361 nbp->vb_buf.b_dev = vp->v_rdev;
362 else
363 nbp->vb_buf.b_dev = NODEV;
364 nbp->vb_buf.b_data = addr;
365 nbp->vb_buf.b_blkno = nbn + btodb(off);
366 nbp->vb_buf.b_proc = bp->b_proc;
367 nbp->vb_buf.b_iodone = vndiodone;
368 nbp->vb_buf.b_vp = vp;
369 nbp->vb_buf.b_rcred = vnd->sc_cred; /* XXX crdup? */
370 nbp->vb_buf.b_wcred = vnd->sc_cred; /* XXX crdup? */
371 if (bp->b_dirtyend == 0) {
372 nbp->vb_buf.b_dirtyoff = 0;
373 nbp->vb_buf.b_dirtyend = sz;
374 } else {
375 nbp->vb_buf.b_dirtyoff =
376 max(0, bp->b_dirtyoff - (bp->b_bcount - resid));
377 nbp->vb_buf.b_dirtyend =
378 min(sz,
379 max(0, bp->b_dirtyend - (bp->b_bcount-resid)));
380 }
381 if (bp->b_validend == 0) {
382 nbp->vb_buf.b_validoff = 0;
383 nbp->vb_buf.b_validend = sz;
384 } else {
385 nbp->vb_buf.b_validoff =
386 max(0, bp->b_validoff - (bp->b_bcount - resid));
387 nbp->vb_buf.b_validend =
388 min(sz,
389 max(0, bp->b_validend - (bp->b_bcount-resid)));
390 }
391
392 nbp->vb_xfer = vnx;
393 vnx->vx_pending++;
394
395 /*
396 * Just sort by block number
397 */
398 nbp->vb_buf.b_cylin = nbp->vb_buf.b_blkno;
399 s = splbio();
400 disksort(&vnd->sc_tab, &nbp->vb_buf);
401 if (vnd->sc_tab.b_active < vnd->sc_maxactive) {
402 vnd->sc_tab.b_active++;
403 vndstart(vnd);
404 }
405 splx(s);
406 bn += sz;
407 addr += sz;
408 }
409 }
410
411 /*
412 * Feed requests sequentially.
413 * We do it this way to keep from flooding NFS servers if we are connected
414 * to an NFS file. This places the burden on the client rather than the
415 * server.
416 */
417 void
418 vndstart(vnd)
419 register struct vnd_softc *vnd;
420 {
421 register struct buf *bp;
422
423 /*
424 * Dequeue now since lower level strategy routine might
425 * queue using same links
426 */
427 bp = vnd->sc_tab.b_actf;
428 vnd->sc_tab.b_actf = bp->b_actf;
429 #ifdef DEBUG
430 if (vnddebug & VDB_IO)
431 printf("vndstart(%ld): bp %p vp %p blkno %x addr %p cnt %lx\n",
432 (long) (vnd-vnd_softc), bp, bp->b_vp, bp->b_blkno,
433 bp->b_data, bp->b_bcount);
434 #endif
435
436 /* Instrumentation. */
437 disk_busy(&vnd->sc_dkdev);
438
439 if ((bp->b_flags & B_READ) == 0)
440 bp->b_vp->v_numoutput++;
441 VOP_STRATEGY(bp);
442 }
443
444 void
445 vndiodone(bp)
446 struct buf *bp;
447 {
448 register struct vndbuf *vbp = (struct vndbuf *) bp;
449 register struct vndxfer *vnx = (struct vndxfer *)vbp->vb_xfer;
450 register struct buf *pbp = vnx->vx_bp;
451 register struct vnd_softc *vnd = &vnd_softc[vndunit(pbp->b_dev)];
452 int s, resid;
453
454 s = splbio();
455 #ifdef DEBUG
456 if (vnddebug & VDB_IO)
457 printf("vndiodone(%ld): vbp %p vp %p blkno %x addr %p cnt %lx\n",
458 (long) (vnd-vnd_softc), vbp, vbp->vb_buf.b_vp,
459 vbp->vb_buf.b_blkno, vbp->vb_buf.b_data,
460 vbp->vb_buf.b_bcount);
461 #endif
462
463 resid = vbp->vb_buf.b_bcount - vbp->vb_buf.b_resid;
464 pbp->b_resid -= resid;
465 disk_unbusy(&vnd->sc_dkdev, resid);
466 vnx->vx_pending--;
467
468 if (vbp->vb_buf.b_error) {
469 #ifdef DEBUG
470 if (vnddebug & VDB_IO)
471 printf("vndiodone: vbp %p error %d\n", vbp,
472 vbp->vb_buf.b_error);
473 #endif
474 vnx->vx_error = vbp->vb_buf.b_error;
475 }
476 putvndbuf(vbp);
477
478 /*
479 * Wrap up this transaction if it has run to completion or, in
480 * case of an error, when all auxiliary buffers have returned.
481 */
482 if (pbp->b_resid == 0 || (vnx->vx_error && vnx->vx_pending == 0)) {
483
484 if (vnx->vx_error != 0) {
485 pbp->b_flags |= B_ERROR;
486 pbp->b_error = vnx->vx_error;
487 }
488 putvndxfer(vnx);
489 #ifdef DEBUG
490 if (vnddebug & VDB_IO)
491 printf("vndiodone: pbp %p iodone\n", pbp);
492 #endif
493 biodone(pbp);
494 }
495
496 if (vnd->sc_tab.b_actf)
497 vndstart(vnd);
498 else
499 vnd->sc_tab.b_active--;
500 splx(s);
501 }
502
503 /* ARGSUSED */
504 int
505 vndread(dev, uio, flags)
506 dev_t dev;
507 struct uio *uio;
508 int flags;
509 {
510 int unit = vndunit(dev);
511 struct vnd_softc *sc;
512
513 #ifdef DEBUG
514 if (vnddebug & VDB_FOLLOW)
515 printf("vndread(%x, %p)\n", dev, uio);
516 #endif
517
518 if (unit >= numvnd)
519 return (ENXIO);
520 sc = &vnd_softc[unit];
521
522 if ((sc->sc_flags & VNF_INITED) == 0)
523 return (ENXIO);
524
525 return (physio(vndstrategy, NULL, dev, B_READ, minphys, uio));
526 }
527
528 /* ARGSUSED */
529 int
530 vndwrite(dev, uio, flags)
531 dev_t dev;
532 struct uio *uio;
533 int flags;
534 {
535 int unit = vndunit(dev);
536 struct vnd_softc *sc;
537
538 #ifdef DEBUG
539 if (vnddebug & VDB_FOLLOW)
540 printf("vndwrite(%x, %p)\n", dev, uio);
541 #endif
542
543 if (unit >= numvnd)
544 return (ENXIO);
545 sc = &vnd_softc[unit];
546
547 if ((sc->sc_flags & VNF_INITED) == 0)
548 return (ENXIO);
549
550 return (physio(vndstrategy, NULL, dev, B_WRITE, minphys, uio));
551 }
552
553 /* ARGSUSED */
554 int
555 vndioctl(dev, cmd, data, flag, p)
556 dev_t dev;
557 u_long cmd;
558 caddr_t data;
559 int flag;
560 struct proc *p;
561 {
562 int unit = vndunit(dev);
563 register struct vnd_softc *vnd;
564 struct vnd_ioctl *vio;
565 struct vattr vattr;
566 struct nameidata nd;
567 int error, part, pmask;
568
569 #ifdef DEBUG
570 if (vnddebug & VDB_FOLLOW)
571 printf("vndioctl(%x, %lx, %p, %x, %p): unit %d\n",
572 dev, cmd, data, flag, p, unit);
573 #endif
574 error = suser(p->p_ucred, &p->p_acflag);
575 if (error)
576 return (error);
577 if (unit >= numvnd)
578 return (ENXIO);
579
580 vnd = &vnd_softc[unit];
581 vio = (struct vnd_ioctl *)data;
582 switch (cmd) {
583
584 case VNDIOCSET:
585 if (vnd->sc_flags & VNF_INITED)
586 return (EBUSY);
587
588 if ((error = vndlock(vnd)) != 0)
589 return (error);
590
591 /*
592 * Always open for read and write.
593 * This is probably bogus, but it lets vn_open()
594 * weed out directories, sockets, etc. so we don't
595 * have to worry about them.
596 */
597 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p);
598 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
599 vndunlock(vnd);
600 return(error);
601 }
602 error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p);
603 if (error) {
604 VOP_UNLOCK(nd.ni_vp);
605 (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
606 vndunlock(vnd);
607 return(error);
608 }
609 VOP_UNLOCK(nd.ni_vp);
610 vnd->sc_vp = nd.ni_vp;
611 vnd->sc_size = btodb(vattr.va_size); /* note truncation */
612 if ((error = vndsetcred(vnd, p->p_ucred)) != 0) {
613 (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
614 vndunlock(vnd);
615 return(error);
616 }
617 vndthrottle(vnd, vnd->sc_vp);
618 vio->vnd_size = dbtob(vnd->sc_size);
619 vnd->sc_flags |= VNF_INITED;
620 #ifdef DEBUG
621 if (vnddebug & VDB_INIT)
622 printf("vndioctl: SET vp %p size %lx\n",
623 vnd->sc_vp, (unsigned long) vnd->sc_size);
624 #endif
625
626 /* Attach the disk. */
627 bzero(vnd->sc_xname, sizeof(vnd->sc_xname)); /* XXX */
628 sprintf(vnd->sc_xname, "vnd%d", unit); /* XXX */
629 vnd->sc_dkdev.dk_name = vnd->sc_xname;
630 disk_attach(&vnd->sc_dkdev);
631
632 vndunlock(vnd);
633
634 break;
635
636 case VNDIOCCLR:
637 if ((vnd->sc_flags & VNF_INITED) == 0)
638 return (ENXIO);
639
640 if ((error = vndlock(vnd)) != 0)
641 return (error);
642
643 /*
644 * Don't unconfigure if any other partitions are open
645 * or if both the character and block flavors of this
646 * partition are open.
647 */
648 part = DISKPART(dev);
649 pmask = (1 << part);
650 if ((vnd->sc_dkdev.dk_openmask & ~pmask) ||
651 ((vnd->sc_dkdev.dk_bopenmask & pmask) &&
652 (vnd->sc_dkdev.dk_copenmask & pmask))) {
653 vndunlock(vnd);
654 return (EBUSY);
655 }
656
657 vndclear(vnd);
658 #ifdef DEBUG
659 if (vnddebug & VDB_INIT)
660 printf("vndioctl: CLRed\n");
661 #endif
662
663 /* Detatch the disk. */
664 disk_detach(&vnd->sc_dkdev);
665
666 vndunlock(vnd);
667
668 break;
669
670 /*
671 * XXX Should support disklabels.
672 */
673
674 default:
675 return(ENOTTY);
676 }
677
678 return (0);
679 }
680
681 /*
682 * Duplicate the current processes' credentials. Since we are called only
683 * as the result of a SET ioctl and only root can do that, any future access
684 * to this "disk" is essentially as root. Note that credentials may change
685 * if some other uid can write directly to the mapped file (NFS).
686 */
687 int
688 vndsetcred(vnd, cred)
689 register struct vnd_softc *vnd;
690 struct ucred *cred;
691 {
692 struct uio auio;
693 struct iovec aiov;
694 char *tmpbuf;
695 int error;
696
697 vnd->sc_cred = crdup(cred);
698 tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK);
699
700 /* XXX: Horrible kludge to establish credentials for NFS */
701 aiov.iov_base = tmpbuf;
702 aiov.iov_len = min(DEV_BSIZE, dbtob(vnd->sc_size));
703 auio.uio_iov = &aiov;
704 auio.uio_iovcnt = 1;
705 auio.uio_offset = 0;
706 auio.uio_rw = UIO_READ;
707 auio.uio_segflg = UIO_SYSSPACE;
708 auio.uio_resid = aiov.iov_len;
709 VOP_LOCK(vnd->sc_vp);
710 error = VOP_READ(vnd->sc_vp, &auio, 0, vnd->sc_cred);
711 VOP_UNLOCK(vnd->sc_vp);
712
713 free(tmpbuf, M_TEMP);
714 return (error);
715 }
716
717 /*
718 * Set maxactive based on FS type
719 */
720 void
721 vndthrottle(vnd, vp)
722 register struct vnd_softc *vnd;
723 struct vnode *vp;
724 {
725 #ifdef NFS
726 extern int (**nfsv2_vnodeop_p) __P((void *));
727
728 if (vp->v_op == nfsv2_vnodeop_p)
729 vnd->sc_maxactive = 2;
730 else
731 #endif
732 vnd->sc_maxactive = 8;
733
734 if (vnd->sc_maxactive < 1)
735 vnd->sc_maxactive = 1;
736 }
737
738 void
739 vndshutdown()
740 {
741 register struct vnd_softc *vnd;
742
743 for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++)
744 if (vnd->sc_flags & VNF_INITED)
745 vndclear(vnd);
746 }
747
748 void
749 vndclear(vnd)
750 register struct vnd_softc *vnd;
751 {
752 register struct vnode *vp = vnd->sc_vp;
753 struct proc *p = curproc; /* XXX */
754
755 #ifdef DEBUG
756 if (vnddebug & VDB_FOLLOW)
757 printf("vndclear(%p): vp %p\n", vnd, vp);
758 #endif
759 vnd->sc_flags &= ~VNF_INITED;
760 if (vp == (struct vnode *)0)
761 panic("vndioctl: null vp");
762 (void) vn_close(vp, FREAD|FWRITE, vnd->sc_cred, p);
763 crfree(vnd->sc_cred);
764 vnd->sc_vp = (struct vnode *)0;
765 vnd->sc_cred = (struct ucred *)0;
766 vnd->sc_size = 0;
767 }
768
769 int
770 vndsize(dev)
771 dev_t dev;
772 {
773 int unit = vndunit(dev);
774 register struct vnd_softc *vnd = &vnd_softc[unit];
775
776 if (unit >= numvnd || (vnd->sc_flags & VNF_INITED) == 0)
777 return(-1);
778 return(vnd->sc_size);
779 }
780
781 int
782 vnddump(dev, blkno, va, size)
783 dev_t dev;
784 daddr_t blkno;
785 caddr_t va;
786 size_t size;
787 {
788
789 /* Not implemented. */
790 return ENXIO;
791 }
792
793 /*
794 * Wait interruptibly for an exclusive lock.
795 *
796 * XXX
797 * Several drivers do this; it should be abstracted and made MP-safe.
798 */
799 static int
800 vndlock(sc)
801 struct vnd_softc *sc;
802 {
803 int error;
804
805 while ((sc->sc_flags & VNF_LOCKED) != 0) {
806 sc->sc_flags |= VNF_WANTED;
807 if ((error = tsleep(sc, PRIBIO | PCATCH, "vndlck", 0)) != 0)
808 return (error);
809 }
810 sc->sc_flags |= VNF_LOCKED;
811 return (0);
812 }
813
814 /*
815 * Unlock and wake up any waiters.
816 */
817 static void
818 vndunlock(sc)
819 struct vnd_softc *sc;
820 {
821
822 sc->sc_flags &= ~VNF_LOCKED;
823 if ((sc->sc_flags & VNF_WANTED) != 0) {
824 sc->sc_flags &= ~VNF_WANTED;
825 wakeup(sc);
826 }
827 }
828