vnd.c revision 1.40 1 /* $NetBSD: vnd.c,v 1.40 1997/06/08 15:59:41 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 struct vnd_softc *vnd = &vnd_softc[unit];
268 struct vndbuf *nbp;
269 struct vndxfer *vnx;
270 int bn, bsize, resid;
271 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
316 if (error == 0 && (long)nbn == -1)
317 error = EIO;
318
319 /*
320 * If there was an error or a hole in the file...punt.
321 * Note that we may have to wait for any operations
322 * that we have already fired off before releasing
323 * the buffer.
324 *
325 * XXX we could deal with holes here but it would be
326 * a hassle (in the write case).
327 */
328 if (error) {
329 vnx->vx_error = error;
330 s = splbio();
331 if (vnx->vx_pending == 0) {
332 bp->b_error = error;
333 bp->b_flags |= B_ERROR;
334 putvndxfer(vnx);
335 biodone(bp);
336 }
337 splx(s);
338 return;
339 }
340
341 #ifdef DEBUG
342 if (!dovndcluster)
343 nra = 0;
344 #endif
345
346 if ((off = bn % bsize) != 0)
347 sz = bsize - off;
348 else
349 sz = (1 + nra) * bsize;
350 if (resid < sz)
351 sz = resid;
352 #ifdef DEBUG
353 if (vnddebug & VDB_IO)
354 printf("vndstrategy: vp %p/%p bn %x/%x sz %x\n",
355 vnd->sc_vp, vp, bn, nbn, sz);
356 #endif
357
358 nbp = getvndbuf();
359 nbp->vb_buf.b_flags = flags;
360 nbp->vb_buf.b_bcount = sz;
361 nbp->vb_buf.b_bufsize = bp->b_bufsize;
362 nbp->vb_buf.b_error = 0;
363 if (vp->v_type == VBLK || vp->v_type == VCHR)
364 nbp->vb_buf.b_dev = vp->v_rdev;
365 else
366 nbp->vb_buf.b_dev = NODEV;
367 nbp->vb_buf.b_data = addr;
368 nbp->vb_buf.b_blkno = nbn + btodb(off);
369 nbp->vb_buf.b_proc = bp->b_proc;
370 nbp->vb_buf.b_iodone = vndiodone;
371 nbp->vb_buf.b_vp = vp;
372 nbp->vb_buf.b_rcred = vnd->sc_cred; /* XXX crdup? */
373 nbp->vb_buf.b_wcred = vnd->sc_cred; /* XXX crdup? */
374 if (bp->b_dirtyend == 0) {
375 nbp->vb_buf.b_dirtyoff = 0;
376 nbp->vb_buf.b_dirtyend = sz;
377 } else {
378 nbp->vb_buf.b_dirtyoff =
379 max(0, bp->b_dirtyoff - (bp->b_bcount - resid));
380 nbp->vb_buf.b_dirtyend =
381 min(sz,
382 max(0, bp->b_dirtyend - (bp->b_bcount-resid)));
383 }
384 if (bp->b_validend == 0) {
385 nbp->vb_buf.b_validoff = 0;
386 nbp->vb_buf.b_validend = sz;
387 } else {
388 nbp->vb_buf.b_validoff =
389 max(0, bp->b_validoff - (bp->b_bcount - resid));
390 nbp->vb_buf.b_validend =
391 min(sz,
392 max(0, bp->b_validend - (bp->b_bcount-resid)));
393 }
394
395 nbp->vb_xfer = vnx;
396
397 /*
398 * Just sort by block number
399 */
400 nbp->vb_buf.b_cylin = nbp->vb_buf.b_blkno;
401 s = splbio();
402 vnx->vx_pending++;
403 disksort(&vnd->sc_tab, &nbp->vb_buf);
404 if (vnd->sc_tab.b_active < vnd->sc_maxactive) {
405 vnd->sc_tab.b_active++;
406 vndstart(vnd);
407 }
408 splx(s);
409 bn += sz;
410 addr += sz;
411 }
412 }
413
414 /*
415 * Feed requests sequentially.
416 * We do it this way to keep from flooding NFS servers if we are connected
417 * to an NFS file. This places the burden on the client rather than the
418 * server.
419 */
420 void
421 vndstart(vnd)
422 register struct vnd_softc *vnd;
423 {
424 register struct buf *bp;
425
426 /*
427 * Dequeue now since lower level strategy routine might
428 * queue using same links
429 */
430 bp = vnd->sc_tab.b_actf;
431 vnd->sc_tab.b_actf = bp->b_actf;
432 #ifdef DEBUG
433 if (vnddebug & VDB_IO)
434 printf("vndstart(%ld): bp %p vp %p blkno %x addr %p cnt %lx\n",
435 (long) (vnd-vnd_softc), bp, bp->b_vp, bp->b_blkno,
436 bp->b_data, bp->b_bcount);
437 #endif
438
439 /* Instrumentation. */
440 disk_busy(&vnd->sc_dkdev);
441
442 if ((bp->b_flags & B_READ) == 0)
443 bp->b_vp->v_numoutput++;
444 VOP_STRATEGY(bp);
445 }
446
447 void
448 vndiodone(bp)
449 struct buf *bp;
450 {
451 register struct vndbuf *vbp = (struct vndbuf *) bp;
452 register struct vndxfer *vnx = (struct vndxfer *)vbp->vb_xfer;
453 register struct buf *pbp = vnx->vx_bp;
454 register struct vnd_softc *vnd = &vnd_softc[vndunit(pbp->b_dev)];
455 int s, resid;
456
457 s = splbio();
458 #ifdef DEBUG
459 if (vnddebug & VDB_IO)
460 printf("vndiodone(%ld): vbp %p vp %p blkno %x addr %p cnt %lx\n",
461 (long) (vnd-vnd_softc), vbp, vbp->vb_buf.b_vp,
462 vbp->vb_buf.b_blkno, vbp->vb_buf.b_data,
463 vbp->vb_buf.b_bcount);
464 #endif
465
466 resid = vbp->vb_buf.b_bcount - vbp->vb_buf.b_resid;
467 pbp->b_resid -= resid;
468 disk_unbusy(&vnd->sc_dkdev, resid);
469 vnx->vx_pending--;
470
471 if (vbp->vb_buf.b_error) {
472 #ifdef DEBUG
473 if (vnddebug & VDB_IO)
474 printf("vndiodone: vbp %p error %d\n", vbp,
475 vbp->vb_buf.b_error);
476 #endif
477 vnx->vx_error = vbp->vb_buf.b_error;
478 }
479 putvndbuf(vbp);
480
481 /*
482 * Wrap up this transaction if it has run to completion or, in
483 * case of an error, when all auxiliary buffers have returned.
484 */
485 if (pbp->b_resid == 0 || (vnx->vx_error && vnx->vx_pending == 0)) {
486
487 if (vnx->vx_error != 0) {
488 pbp->b_flags |= B_ERROR;
489 pbp->b_error = vnx->vx_error;
490 }
491 putvndxfer(vnx);
492 #ifdef DEBUG
493 if (vnddebug & VDB_IO)
494 printf("vndiodone: pbp %p iodone\n", pbp);
495 #endif
496 biodone(pbp);
497 }
498
499 if (vnd->sc_tab.b_actf)
500 vndstart(vnd);
501 else
502 vnd->sc_tab.b_active--;
503 splx(s);
504 }
505
506 /* ARGSUSED */
507 int
508 vndread(dev, uio, flags)
509 dev_t dev;
510 struct uio *uio;
511 int flags;
512 {
513 int unit = vndunit(dev);
514 struct vnd_softc *sc;
515
516 #ifdef DEBUG
517 if (vnddebug & VDB_FOLLOW)
518 printf("vndread(%x, %p)\n", dev, uio);
519 #endif
520
521 if (unit >= numvnd)
522 return (ENXIO);
523 sc = &vnd_softc[unit];
524
525 if ((sc->sc_flags & VNF_INITED) == 0)
526 return (ENXIO);
527
528 return (physio(vndstrategy, NULL, dev, B_READ, minphys, uio));
529 }
530
531 /* ARGSUSED */
532 int
533 vndwrite(dev, uio, flags)
534 dev_t dev;
535 struct uio *uio;
536 int flags;
537 {
538 int unit = vndunit(dev);
539 struct vnd_softc *sc;
540
541 #ifdef DEBUG
542 if (vnddebug & VDB_FOLLOW)
543 printf("vndwrite(%x, %p)\n", dev, uio);
544 #endif
545
546 if (unit >= numvnd)
547 return (ENXIO);
548 sc = &vnd_softc[unit];
549
550 if ((sc->sc_flags & VNF_INITED) == 0)
551 return (ENXIO);
552
553 return (physio(vndstrategy, NULL, dev, B_WRITE, minphys, uio));
554 }
555
556 /* ARGSUSED */
557 int
558 vndioctl(dev, cmd, data, flag, p)
559 dev_t dev;
560 u_long cmd;
561 caddr_t data;
562 int flag;
563 struct proc *p;
564 {
565 int unit = vndunit(dev);
566 register struct vnd_softc *vnd;
567 struct vnd_ioctl *vio;
568 struct vattr vattr;
569 struct nameidata nd;
570 int error, part, pmask;
571
572 #ifdef DEBUG
573 if (vnddebug & VDB_FOLLOW)
574 printf("vndioctl(%x, %lx, %p, %x, %p): unit %d\n",
575 dev, cmd, data, flag, p, unit);
576 #endif
577 error = suser(p->p_ucred, &p->p_acflag);
578 if (error)
579 return (error);
580 if (unit >= numvnd)
581 return (ENXIO);
582
583 vnd = &vnd_softc[unit];
584 vio = (struct vnd_ioctl *)data;
585 switch (cmd) {
586
587 case VNDIOCSET:
588 if (vnd->sc_flags & VNF_INITED)
589 return (EBUSY);
590
591 if ((error = vndlock(vnd)) != 0)
592 return (error);
593
594 /*
595 * Always open for read and write.
596 * This is probably bogus, but it lets vn_open()
597 * weed out directories, sockets, etc. so we don't
598 * have to worry about them.
599 */
600 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p);
601 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
602 vndunlock(vnd);
603 return(error);
604 }
605 error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p);
606 if (error) {
607 VOP_UNLOCK(nd.ni_vp);
608 (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
609 vndunlock(vnd);
610 return(error);
611 }
612 VOP_UNLOCK(nd.ni_vp);
613 vnd->sc_vp = nd.ni_vp;
614 vnd->sc_size = btodb(vattr.va_size); /* note truncation */
615 if ((error = vndsetcred(vnd, p->p_ucred)) != 0) {
616 (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
617 vndunlock(vnd);
618 return(error);
619 }
620 vndthrottle(vnd, vnd->sc_vp);
621 vio->vnd_size = dbtob(vnd->sc_size);
622 vnd->sc_flags |= VNF_INITED;
623 #ifdef DEBUG
624 if (vnddebug & VDB_INIT)
625 printf("vndioctl: SET vp %p size %lx\n",
626 vnd->sc_vp, (unsigned long) vnd->sc_size);
627 #endif
628
629 /* Attach the disk. */
630 bzero(vnd->sc_xname, sizeof(vnd->sc_xname)); /* XXX */
631 sprintf(vnd->sc_xname, "vnd%d", unit); /* XXX */
632 vnd->sc_dkdev.dk_name = vnd->sc_xname;
633 disk_attach(&vnd->sc_dkdev);
634
635 vndunlock(vnd);
636
637 break;
638
639 case VNDIOCCLR:
640 if ((vnd->sc_flags & VNF_INITED) == 0)
641 return (ENXIO);
642
643 if ((error = vndlock(vnd)) != 0)
644 return (error);
645
646 /*
647 * Don't unconfigure if any other partitions are open
648 * or if both the character and block flavors of this
649 * partition are open.
650 */
651 part = DISKPART(dev);
652 pmask = (1 << part);
653 if ((vnd->sc_dkdev.dk_openmask & ~pmask) ||
654 ((vnd->sc_dkdev.dk_bopenmask & pmask) &&
655 (vnd->sc_dkdev.dk_copenmask & pmask))) {
656 vndunlock(vnd);
657 return (EBUSY);
658 }
659
660 vndclear(vnd);
661 #ifdef DEBUG
662 if (vnddebug & VDB_INIT)
663 printf("vndioctl: CLRed\n");
664 #endif
665
666 /* Detatch the disk. */
667 disk_detach(&vnd->sc_dkdev);
668
669 vndunlock(vnd);
670
671 break;
672
673 /*
674 * XXX Should support disklabels.
675 */
676
677 default:
678 return(ENOTTY);
679 }
680
681 return (0);
682 }
683
684 /*
685 * Duplicate the current processes' credentials. Since we are called only
686 * as the result of a SET ioctl and only root can do that, any future access
687 * to this "disk" is essentially as root. Note that credentials may change
688 * if some other uid can write directly to the mapped file (NFS).
689 */
690 int
691 vndsetcred(vnd, cred)
692 register struct vnd_softc *vnd;
693 struct ucred *cred;
694 {
695 struct uio auio;
696 struct iovec aiov;
697 char *tmpbuf;
698 int error;
699
700 vnd->sc_cred = crdup(cred);
701 tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK);
702
703 /* XXX: Horrible kludge to establish credentials for NFS */
704 aiov.iov_base = tmpbuf;
705 aiov.iov_len = min(DEV_BSIZE, dbtob(vnd->sc_size));
706 auio.uio_iov = &aiov;
707 auio.uio_iovcnt = 1;
708 auio.uio_offset = 0;
709 auio.uio_rw = UIO_READ;
710 auio.uio_segflg = UIO_SYSSPACE;
711 auio.uio_resid = aiov.iov_len;
712 VOP_LOCK(vnd->sc_vp);
713 error = VOP_READ(vnd->sc_vp, &auio, 0, vnd->sc_cred);
714 VOP_UNLOCK(vnd->sc_vp);
715
716 free(tmpbuf, M_TEMP);
717 return (error);
718 }
719
720 /*
721 * Set maxactive based on FS type
722 */
723 void
724 vndthrottle(vnd, vp)
725 register struct vnd_softc *vnd;
726 struct vnode *vp;
727 {
728 #ifdef NFS
729 extern int (**nfsv2_vnodeop_p) __P((void *));
730
731 if (vp->v_op == nfsv2_vnodeop_p)
732 vnd->sc_maxactive = 2;
733 else
734 #endif
735 vnd->sc_maxactive = 8;
736
737 if (vnd->sc_maxactive < 1)
738 vnd->sc_maxactive = 1;
739 }
740
741 void
742 vndshutdown()
743 {
744 register struct vnd_softc *vnd;
745
746 for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++)
747 if (vnd->sc_flags & VNF_INITED)
748 vndclear(vnd);
749 }
750
751 void
752 vndclear(vnd)
753 register struct vnd_softc *vnd;
754 {
755 register struct vnode *vp = vnd->sc_vp;
756 struct proc *p = curproc; /* XXX */
757
758 #ifdef DEBUG
759 if (vnddebug & VDB_FOLLOW)
760 printf("vndclear(%p): vp %p\n", vnd, vp);
761 #endif
762 vnd->sc_flags &= ~VNF_INITED;
763 if (vp == (struct vnode *)0)
764 panic("vndioctl: null vp");
765 (void) vn_close(vp, FREAD|FWRITE, vnd->sc_cred, p);
766 crfree(vnd->sc_cred);
767 vnd->sc_vp = (struct vnode *)0;
768 vnd->sc_cred = (struct ucred *)0;
769 vnd->sc_size = 0;
770 }
771
772 int
773 vndsize(dev)
774 dev_t dev;
775 {
776 int unit = vndunit(dev);
777 register struct vnd_softc *vnd = &vnd_softc[unit];
778
779 if (unit >= numvnd || (vnd->sc_flags & VNF_INITED) == 0)
780 return(-1);
781 return(vnd->sc_size);
782 }
783
784 int
785 vnddump(dev, blkno, va, size)
786 dev_t dev;
787 daddr_t blkno;
788 caddr_t va;
789 size_t size;
790 {
791
792 /* Not implemented. */
793 return ENXIO;
794 }
795
796 /*
797 * Wait interruptibly for an exclusive lock.
798 *
799 * XXX
800 * Several drivers do this; it should be abstracted and made MP-safe.
801 */
802 static int
803 vndlock(sc)
804 struct vnd_softc *sc;
805 {
806 int error;
807
808 while ((sc->sc_flags & VNF_LOCKED) != 0) {
809 sc->sc_flags |= VNF_WANTED;
810 if ((error = tsleep(sc, PRIBIO | PCATCH, "vndlck", 0)) != 0)
811 return (error);
812 }
813 sc->sc_flags |= VNF_LOCKED;
814 return (0);
815 }
816
817 /*
818 * Unlock and wake up any waiters.
819 */
820 static void
821 vndunlock(sc)
822 struct vnd_softc *sc;
823 {
824
825 sc->sc_flags &= ~VNF_LOCKED;
826 if ((sc->sc_flags & VNF_WANTED) != 0) {
827 sc->sc_flags &= ~VNF_WANTED;
828 wakeup(sc);
829 }
830 }
831