vnd.c revision 1.25 1 /* $NetBSD: vnd.c,v 1.25 1996/03/16 23:19:08 christos 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/conf.h>
77 #include <sys/mount.h>
78 #include <sys/vnode.h>
79 #include <sys/file.h>
80 #include <sys/uio.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 vndbuf {
99 struct buf vb_buf;
100 struct buf *vb_obp;
101 };
102
103 #define getvndbuf() \
104 ((struct vndbuf *)malloc(sizeof(struct vndbuf), M_DEVBUF, M_WAITOK))
105 #define putvndbuf(vbp) \
106 free((caddr_t)(vbp), M_DEVBUF)
107
108 struct vnd_softc {
109 int sc_flags; /* flags */
110 size_t sc_size; /* size of vnd */
111 struct vnode *sc_vp; /* vnode */
112 struct ucred *sc_cred; /* credentials */
113 int sc_maxactive; /* max # of active requests */
114 struct buf sc_tab; /* transfer queue */
115 char sc_xname[8]; /* XXX external name */
116 struct disk sc_dkdev; /* generic disk device info */
117 };
118
119 /* sc_flags */
120 #define VNF_ALIVE 0x01
121 #define VNF_INITED 0x02
122 #define VNF_WANTED 0x40
123 #define VNF_LOCKED 0x80
124
125 struct vnd_softc *vnd_softc;
126 int numvnd = 0;
127
128 /* {b,c}devsw[] function prototypes XXX: move them to dev_conf.h */
129 bdev_decl(vnd);
130 cdev_decl(vnd);
131
132 /* called by main() at boot time */
133 void vndattach __P((int));
134
135 void vndclear __P((struct vnd_softc *));
136 void vndstart __P((struct vnd_softc *));
137 int vndsetcred __P((struct vnd_softc *, struct ucred *));
138 void vndthrottle __P((struct vnd_softc *, struct vnode *));
139 void vndiodone __P((struct buf *));
140 void vndshutdown __P((void));
141
142 static int vndlock __P((struct vnd_softc *));
143 static void vndunlock __P((struct vnd_softc *));
144
145 void
146 vndattach(num)
147 int num;
148 {
149 char *mem;
150 register u_long size;
151
152 if (num <= 0)
153 return;
154 size = num * sizeof(struct vnd_softc);
155 mem = malloc(size, M_DEVBUF, M_NOWAIT);
156 if (mem == NULL) {
157 printf("WARNING: no memory for vnode disks\n");
158 return;
159 }
160 bzero(mem, size);
161 vnd_softc = (struct vnd_softc *)mem;
162 numvnd = num;
163 }
164
165 int
166 vndopen(dev, flags, mode, p)
167 dev_t dev;
168 int flags, mode;
169 struct proc *p;
170 {
171 int unit = vndunit(dev);
172 struct vnd_softc *sc;
173 int error = 0, part, pmask;
174
175 /*
176 * XXX Should support disklabels.
177 */
178
179 #ifdef DEBUG
180 if (vnddebug & VDB_FOLLOW)
181 printf("vndopen(%x, %x, %x, %p)\n", dev, flags, mode, p);
182 #endif
183 if (unit >= numvnd)
184 return (ENXIO);
185 sc = &vnd_softc[unit];
186
187 if ((error = vndlock(sc)) != 0)
188 return (error);
189
190 part = DISKPART(dev);
191 pmask = (1 << part);
192
193 /* Prevent our unit from being unconfigured while open. */
194 switch (mode) {
195 case S_IFCHR:
196 sc->sc_dkdev.dk_copenmask |= pmask;
197 break;
198
199 case S_IFBLK:
200 sc->sc_dkdev.dk_bopenmask |= pmask;
201 break;
202 }
203 sc->sc_dkdev.dk_openmask =
204 sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask;
205
206 vndunlock(sc);
207 return (0);
208 }
209
210 int
211 vndclose(dev, flags, mode, p)
212 dev_t dev;
213 int flags, mode;
214 struct proc *p;
215 {
216 int unit = vndunit(dev);
217 struct vnd_softc *sc;
218 int error = 0, part;
219
220 #ifdef DEBUG
221 if (vnddebug & VDB_FOLLOW)
222 printf("vndclose(%x, %x, %x, %p)\n", dev, flags, mode, p);
223 #endif
224
225 if (unit >= numvnd)
226 return (ENXIO);
227 sc = &vnd_softc[unit];
228
229 if ((error = vndlock(sc)) != 0)
230 return (error);
231
232 part = DISKPART(dev);
233
234 /* ...that much closer to allowing unconfiguration... */
235 switch (mode) {
236 case S_IFCHR:
237 sc->sc_dkdev.dk_copenmask &= ~(1 << part);
238 break;
239
240 case S_IFBLK:
241 sc->sc_dkdev.dk_bopenmask &= ~(1 << part);
242 break;
243 }
244 sc->sc_dkdev.dk_openmask =
245 sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask;
246
247 vndunlock(sc);
248 return (0);
249 }
250
251 /*
252 * Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY.
253 * Note that this driver can only be used for swapping over NFS on the hp
254 * since nfs_strategy on the vax cannot handle u-areas and page tables.
255 */
256 void
257 vndstrategy(bp)
258 register struct buf *bp;
259 {
260 int unit = vndunit(bp->b_dev);
261 register struct vnd_softc *vnd = &vnd_softc[unit];
262 register struct vndbuf *nbp;
263 register int bn, bsize, resid;
264 register caddr_t addr;
265 int sz, flags, error;
266
267 #ifdef DEBUG
268 if (vnddebug & VDB_FOLLOW)
269 printf("vndstrategy(%p): unit %d\n", bp, unit);
270 #endif
271 if ((vnd->sc_flags & VNF_INITED) == 0) {
272 bp->b_error = ENXIO;
273 bp->b_flags |= B_ERROR;
274 biodone(bp);
275 return;
276 }
277 bn = bp->b_blkno;
278 sz = howmany(bp->b_bcount, DEV_BSIZE);
279 bp->b_resid = bp->b_bcount;
280 if (bn < 0 || bn + sz > vnd->sc_size) {
281 if (bn != vnd->sc_size) {
282 bp->b_error = EINVAL;
283 bp->b_flags |= B_ERROR;
284 }
285 biodone(bp);
286 return;
287 }
288 bn = dbtob(bn);
289 bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize;
290 addr = bp->b_data;
291 flags = bp->b_flags | B_CALL;
292 for (resid = bp->b_resid; resid; resid -= sz) {
293 struct vnode *vp;
294 daddr_t nbn;
295 int off, s, nra;
296
297 nra = 0;
298 VOP_LOCK(vnd->sc_vp);
299 error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra);
300 VOP_UNLOCK(vnd->sc_vp);
301 if (error == 0 && (long)nbn == -1)
302 error = EIO;
303 #ifdef DEBUG
304 if (!dovndcluster)
305 nra = 0;
306 #endif
307
308 if ((off = bn % bsize) != 0)
309 sz = bsize - off;
310 else
311 sz = (1 + nra) * bsize;
312 if (resid < sz)
313 sz = resid;
314 #ifdef DEBUG
315 if (vnddebug & VDB_IO)
316 printf("vndstrategy: vp %p/%p bn %x/%x sz %x\n",
317 vnd->sc_vp, vp, bn, nbn, sz);
318 #endif
319
320 nbp = getvndbuf();
321 nbp->vb_buf.b_flags = flags;
322 nbp->vb_buf.b_bcount = sz;
323 nbp->vb_buf.b_bufsize = bp->b_bufsize;
324 nbp->vb_buf.b_error = 0;
325 if (vp->v_type == VBLK || vp->v_type == VCHR)
326 nbp->vb_buf.b_dev = vp->v_rdev;
327 else
328 nbp->vb_buf.b_dev = NODEV;
329 nbp->vb_buf.b_data = addr;
330 nbp->vb_buf.b_blkno = nbn + btodb(off);
331 nbp->vb_buf.b_proc = bp->b_proc;
332 nbp->vb_buf.b_iodone = vndiodone;
333 nbp->vb_buf.b_vp = vp;
334 nbp->vb_buf.b_rcred = vnd->sc_cred; /* XXX crdup? */
335 nbp->vb_buf.b_wcred = vnd->sc_cred; /* XXX crdup? */
336 nbp->vb_buf.b_dirtyoff = bp->b_dirtyoff;
337 nbp->vb_buf.b_dirtyend = bp->b_dirtyend;
338 nbp->vb_buf.b_validoff = bp->b_validoff;
339 nbp->vb_buf.b_validend = bp->b_validend;
340
341 /* save a reference to the old buffer */
342 nbp->vb_obp = bp;
343
344 /*
345 * If there was an error or a hole in the file...punt.
346 * Note that we deal with this after the nbp allocation.
347 * This ensures that we properly clean up any operations
348 * that we have already fired off.
349 *
350 * XXX we could deal with holes here but it would be
351 * a hassle (in the write case).
352 */
353 if (error) {
354 nbp->vb_buf.b_error = error;
355 nbp->vb_buf.b_flags |= B_ERROR;
356 bp->b_resid -= (resid - sz);
357 biodone(&nbp->vb_buf);
358 return;
359 }
360 /*
361 * Just sort by block number
362 */
363 nbp->vb_buf.b_cylin = nbp->vb_buf.b_blkno;
364 s = splbio();
365 disksort(&vnd->sc_tab, &nbp->vb_buf);
366 if (vnd->sc_tab.b_active < vnd->sc_maxactive) {
367 vnd->sc_tab.b_active++;
368 vndstart(vnd);
369 }
370 splx(s);
371 bn += sz;
372 addr += sz;
373 }
374 }
375
376 /*
377 * Feed requests sequentially.
378 * We do it this way to keep from flooding NFS servers if we are connected
379 * to an NFS file. This places the burden on the client rather than the
380 * server.
381 */
382 void
383 vndstart(vnd)
384 register struct vnd_softc *vnd;
385 {
386 register struct buf *bp;
387
388 /*
389 * Dequeue now since lower level strategy routine might
390 * queue using same links
391 */
392 bp = vnd->sc_tab.b_actf;
393 vnd->sc_tab.b_actf = bp->b_actf;
394 #ifdef DEBUG
395 if (vnddebug & VDB_IO)
396 printf("vndstart(%d): bp %p vp %p blkno %x addr %p cnt %lx\n",
397 vnd-vnd_softc, bp, bp->b_vp, bp->b_blkno, bp->b_data,
398 bp->b_bcount);
399 #endif
400
401 /* Instrumentation. */
402 disk_busy(&vnd->sc_dkdev);
403
404 if ((bp->b_flags & B_READ) == 0)
405 bp->b_vp->v_numoutput++;
406 VOP_STRATEGY(bp);
407 }
408
409 void
410 vndiodone(bp)
411 struct buf *bp;
412 {
413 register struct vndbuf *vbp = (struct vndbuf *) bp;
414 register struct buf *pbp = vbp->vb_obp;
415 register struct vnd_softc *vnd = &vnd_softc[vndunit(pbp->b_dev)];
416 int s;
417
418 s = splbio();
419 #ifdef DEBUG
420 if (vnddebug & VDB_IO)
421 printf("vndiodone(%d): vbp %p vp %p blkno %x addr %p cnt %lx\n",
422 vnd-vnd_softc, vbp, vbp->vb_buf.b_vp, vbp->vb_buf.b_blkno,
423 vbp->vb_buf.b_data, vbp->vb_buf.b_bcount);
424 #endif
425
426 if (vbp->vb_buf.b_error) {
427 #ifdef DEBUG
428 if (vnddebug & VDB_IO)
429 printf("vndiodone: vbp %p error %d\n", vbp,
430 vbp->vb_buf.b_error);
431 #endif
432 pbp->b_flags |= B_ERROR;
433 pbp->b_error = biowait(&vbp->vb_buf);
434 }
435 pbp->b_resid -= vbp->vb_buf.b_bcount;
436 putvndbuf(vbp);
437 disk_unbusy(&vnd->sc_dkdev, (pbp->b_bcount - pbp->b_resid));
438 if (pbp->b_resid == 0) {
439 #ifdef DEBUG
440 if (vnddebug & VDB_IO)
441 printf("vndiodone: pbp %p iodone\n", pbp);
442 #endif
443 biodone(pbp);
444 }
445 if (vnd->sc_tab.b_actf)
446 vndstart(vnd);
447 else
448 vnd->sc_tab.b_active--;
449 splx(s);
450 }
451
452 /* ARGSUSED */
453 int
454 vndread(dev, uio, flags)
455 dev_t dev;
456 struct uio *uio;
457 int flags;
458 {
459 int unit = vndunit(dev);
460 struct vnd_softc *sc;
461
462 #ifdef DEBUG
463 if (vnddebug & VDB_FOLLOW)
464 printf("vndread(%x, %p)\n", dev, uio);
465 #endif
466
467 if (unit >= numvnd)
468 return (ENXIO);
469 sc = &vnd_softc[unit];
470
471 if ((sc->sc_flags & VNF_INITED) == 0)
472 return (ENXIO);
473
474 return (physio(vndstrategy, NULL, dev, B_READ, minphys, uio));
475 }
476
477 /* ARGSUSED */
478 int
479 vndwrite(dev, uio, flags)
480 dev_t dev;
481 struct uio *uio;
482 int flags;
483 {
484 int unit = vndunit(dev);
485 struct vnd_softc *sc;
486
487 #ifdef DEBUG
488 if (vnddebug & VDB_FOLLOW)
489 printf("vndwrite(%x, %p)\n", dev, uio);
490 #endif
491
492 if (unit >= numvnd)
493 return (ENXIO);
494 sc = &vnd_softc[unit];
495
496 if ((sc->sc_flags & VNF_INITED) == 0)
497 return (ENXIO);
498
499 return (physio(vndstrategy, NULL, dev, B_WRITE, minphys, uio));
500 }
501
502 /* ARGSUSED */
503 int
504 vndioctl(dev, cmd, data, flag, p)
505 dev_t dev;
506 u_long cmd;
507 caddr_t data;
508 int flag;
509 struct proc *p;
510 {
511 int unit = vndunit(dev);
512 register struct vnd_softc *vnd;
513 struct vnd_ioctl *vio;
514 struct vattr vattr;
515 struct nameidata nd;
516 int error, part, pmask, s;
517
518 #ifdef DEBUG
519 if (vnddebug & VDB_FOLLOW)
520 printf("vndioctl(%x, %lx, %p, %x, %p): unit %d\n",
521 dev, cmd, data, flag, p, unit);
522 #endif
523 error = suser(p->p_ucred, &p->p_acflag);
524 if (error)
525 return (error);
526 if (unit >= numvnd)
527 return (ENXIO);
528
529 vnd = &vnd_softc[unit];
530 vio = (struct vnd_ioctl *)data;
531 switch (cmd) {
532
533 case VNDIOCSET:
534 if (vnd->sc_flags & VNF_INITED)
535 return (EBUSY);
536
537 if ((error = vndlock(vnd)) != 0)
538 return (error);
539
540 /*
541 * Always open for read and write.
542 * This is probably bogus, but it lets vn_open()
543 * weed out directories, sockets, etc. so we don't
544 * have to worry about them.
545 */
546 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p);
547 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
548 vndunlock(vnd);
549 return(error);
550 }
551 error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p);
552 if (error) {
553 VOP_UNLOCK(nd.ni_vp);
554 (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
555 vndunlock(vnd);
556 return(error);
557 }
558 VOP_UNLOCK(nd.ni_vp);
559 vnd->sc_vp = nd.ni_vp;
560 vnd->sc_size = btodb(vattr.va_size); /* note truncation */
561 if ((error = vndsetcred(vnd, p->p_ucred)) != 0) {
562 (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
563 vndunlock(vnd);
564 return(error);
565 }
566 vndthrottle(vnd, vnd->sc_vp);
567 vio->vnd_size = dbtob(vnd->sc_size);
568 vnd->sc_flags |= VNF_INITED;
569 #ifdef DEBUG
570 if (vnddebug & VDB_INIT)
571 printf("vndioctl: SET vp %p size %x\n",
572 vnd->sc_vp, vnd->sc_size);
573 #endif
574
575 /* Attach the disk. */
576 bzero(vnd->sc_xname, sizeof(vnd->sc_xname)); /* XXX */
577 sprintf(vnd->sc_xname, "vnd%d", unit); /* XXX */
578 vnd->sc_dkdev.dk_name = vnd->sc_xname;
579 disk_attach(&vnd->sc_dkdev);
580
581 vndunlock(vnd);
582
583 break;
584
585 case VNDIOCCLR:
586 if ((vnd->sc_flags & VNF_INITED) == 0)
587 return (ENXIO);
588
589 if ((error = vndlock(vnd)) != 0)
590 return (error);
591
592 /*
593 * Don't unconfigure if any other partitions are open
594 * or if both the character and block flavors of this
595 * partition are open.
596 */
597 part = DISKPART(dev);
598 pmask = (1 << part);
599 if ((vnd->sc_dkdev.dk_openmask & ~pmask) ||
600 ((vnd->sc_dkdev.dk_bopenmask & pmask) &&
601 (vnd->sc_dkdev.dk_copenmask & pmask))) {
602 vndunlock(vnd);
603 return (EBUSY);
604 }
605
606 vndclear(vnd);
607 #ifdef DEBUG
608 if (vnddebug & VDB_INIT)
609 printf("vndioctl: CLRed\n");
610 #endif
611
612 /* Detatch the disk. */
613 disk_detach(&vnd->sc_dkdev);
614
615 /* This must be atomic. */
616 s = splhigh();
617 vndunlock(vnd);
618 bzero(vnd, sizeof(struct vnd_softc));
619 splx(s);
620
621 break;
622
623 /*
624 * XXX Should support disklabels.
625 */
626
627 default:
628 return(ENOTTY);
629 }
630
631 return (0);
632 }
633
634 /*
635 * Duplicate the current processes' credentials. Since we are called only
636 * as the result of a SET ioctl and only root can do that, any future access
637 * to this "disk" is essentially as root. Note that credentials may change
638 * if some other uid can write directly to the mapped file (NFS).
639 */
640 int
641 vndsetcred(vnd, cred)
642 register struct vnd_softc *vnd;
643 struct ucred *cred;
644 {
645 struct uio auio;
646 struct iovec aiov;
647 char *tmpbuf;
648 int error;
649
650 vnd->sc_cred = crdup(cred);
651 tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK);
652
653 /* XXX: Horrible kludge to establish credentials for NFS */
654 aiov.iov_base = tmpbuf;
655 aiov.iov_len = min(DEV_BSIZE, dbtob(vnd->sc_size));
656 auio.uio_iov = &aiov;
657 auio.uio_iovcnt = 1;
658 auio.uio_offset = 0;
659 auio.uio_rw = UIO_READ;
660 auio.uio_segflg = UIO_SYSSPACE;
661 auio.uio_resid = aiov.iov_len;
662 VOP_LOCK(vnd->sc_vp);
663 error = VOP_READ(vnd->sc_vp, &auio, 0, vnd->sc_cred);
664 VOP_UNLOCK(vnd->sc_vp);
665
666 free(tmpbuf, M_TEMP);
667 return (error);
668 }
669
670 /*
671 * Set maxactive based on FS type
672 */
673 void
674 vndthrottle(vnd, vp)
675 register struct vnd_softc *vnd;
676 struct vnode *vp;
677 {
678 #ifdef NFSCLIENT
679 extern int (**nfsv2_vnodeop_p) __P((void *));
680
681 if (vp->v_op == nfsv2_vnodeop_p)
682 vnd->sc_maxactive = 2;
683 else
684 #endif
685 vnd->sc_maxactive = 8;
686
687 if (vnd->sc_maxactive < 1)
688 vnd->sc_maxactive = 1;
689 }
690
691 void
692 vndshutdown()
693 {
694 register struct vnd_softc *vnd;
695
696 for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++)
697 if (vnd->sc_flags & VNF_INITED)
698 vndclear(vnd);
699 }
700
701 void
702 vndclear(vnd)
703 register struct vnd_softc *vnd;
704 {
705 register struct vnode *vp = vnd->sc_vp;
706 struct proc *p = curproc; /* XXX */
707
708 #ifdef DEBUG
709 if (vnddebug & VDB_FOLLOW)
710 printf("vndclear(%p): vp %p\n", vnd, vp);
711 #endif
712 vnd->sc_flags &= ~VNF_INITED;
713 if (vp == (struct vnode *)0)
714 panic("vndioctl: null vp");
715 (void) vn_close(vp, FREAD|FWRITE, vnd->sc_cred, p);
716 crfree(vnd->sc_cred);
717 vnd->sc_vp = (struct vnode *)0;
718 vnd->sc_cred = (struct ucred *)0;
719 vnd->sc_size = 0;
720 }
721
722 int
723 vndsize(dev)
724 dev_t dev;
725 {
726 int unit = vndunit(dev);
727 register struct vnd_softc *vnd = &vnd_softc[unit];
728
729 if (unit >= numvnd || (vnd->sc_flags & VNF_INITED) == 0)
730 return(-1);
731 return(vnd->sc_size);
732 }
733
734 int
735 vnddump(dev, blkno, va, size)
736 dev_t dev;
737 daddr_t blkno;
738 caddr_t va;
739 size_t size;
740 {
741
742 /* Not implemented. */
743 return ENXIO;
744 }
745
746 /*
747 * Wait interruptibly for an exclusive lock.
748 *
749 * XXX
750 * Several drivers do this; it should be abstracted and made MP-safe.
751 */
752 static int
753 vndlock(sc)
754 struct vnd_softc *sc;
755 {
756 int error;
757
758 while ((sc->sc_flags & VNF_LOCKED) != 0) {
759 sc->sc_flags |= VNF_WANTED;
760 if ((error = tsleep(sc, PRIBIO | PCATCH, "vndlck", 0)) != 0)
761 return (error);
762 }
763 sc->sc_flags |= VNF_LOCKED;
764 return (0);
765 }
766
767 /*
768 * Unlock and wake up any waiters.
769 */
770 static void
771 vndunlock(sc)
772 struct vnd_softc *sc;
773 {
774
775 sc->sc_flags &= ~VNF_LOCKED;
776 if ((sc->sc_flags & VNF_WANTED) != 0) {
777 sc->sc_flags &= ~VNF_WANTED;
778 wakeup(sc);
779 }
780 }
781