|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1988 University of Utah.
28: * Copyright (c) 1990, 1993
29: * The Regents of the University of California. All rights reserved.
30: *
31: * This code is derived from software contributed to Berkeley by
32: * the Systems Programming Group of the University of Utah Computer
33: * Science Department.
34: *
35: * Redistribution and use in source and binary forms, with or without
36: * modification, are permitted provided that the following conditions
37: * are met:
38: * 1. Redistributions of source code must retain the above copyright
39: * notice, this list of conditions and the following disclaimer.
40: * 2. Redistributions in binary form must reproduce the above copyright
41: * notice, this list of conditions and the following disclaimer in the
42: * documentation and/or other materials provided with the distribution.
43: * 3. All advertising materials mentioning features or use of this software
44: * must display the following acknowledgement:
45: * This product includes software developed by the University of
46: * California, Berkeley and its contributors.
47: * 4. Neither the name of the University nor the names of its contributors
48: * may be used to endorse or promote products derived from this software
49: * without specific prior written permission.
50: *
51: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61: * SUCH DAMAGE.
62: *
63: * from: Utah $Hdr: vn.c 1.13 94/04/02$
64: *
65: * @(#)vn.c 8.9 (Berkeley) 5/14/95
66: */
67:
68: /*
69: * Vnode disk driver.
70: *
71: * Block/character interface to a vnode. Allows one to treat a file
72: * as a disk (e.g. build a filesystem in it, mount it, etc.).
73: *
74: * NOTE 1: This uses the VOP_BMAP/VOP_STRATEGY interface to the vnode
75: * instead of a simple VOP_RDWR. We do this to avoid distorting the
76: * local buffer cache.
77: *
78: * NOTE 2: There is a security issue involved with this driver.
79: * Once mounted all access to the contents of the "mapped" file via
80: * the special file is controlled by the permissions on the special
81: * file, the protection of the mapped file is ignored (effectively,
82: * by using root credentials in all transactions).
83: *
84: * NOTE 3: Doesn't interact with leases, should it?
85: */
86: #include "vnd.h"
87: #if NVND > 0
88:
89: #include <sys/param.h>
90: #include <sys/systm.h>
91: #include <sys/namei.h>
92: #include <sys/proc.h>
93: #include <sys/errno.h>
94: #include <sys/dkstat.h>
95: #include <sys/buf.h>
96: #include <sys/malloc.h>
97: #include <sys/ioctl.h>
98: #include <sys/disklabel.h>
99: #include <sys/mount.h>
100: #include <sys/vnode.h>
101: #include <sys/file.h>
102: #include <sys/uio.h>
103:
104: #include <miscfs/specfs/specdev.h>
105:
106: #include <dev/vndioctl.h>
107:
108: #ifdef DEBUG
109: int dovndcluster = 1;
110: int vnddebug = 0x00;
111: #define VDB_FOLLOW 0x01
112: #define VDB_INIT 0x02
113: #define VDB_IO 0x04
114: #endif
115:
116: #define b_cylin b_resid
117:
118: #define vndunit(x) DISKUNIT(x)
119:
120: struct vndbuf {
121: struct buf vb_buf;
122: struct buf *vb_obp;
123: };
124:
125: //#define getvndbuf() \
126: // ((struct vndbuf *)malloc(sizeof(struct vndbuf), M_DEVBUF, M_WAITOK))
127: #define putvndbuf(vbp) \
128: free((caddr_t)(vbp), M_DEVBUF)
129:
130: struct vnd_softc {
131: int sc_flags; /* flags */
132: size_t sc_size; /* size of vnd */
133: struct vnode *sc_vp; /* vnode */
134: struct ucred *sc_cred; /* credentials */
135: int sc_maxactive; /* max # of active requests */
136: struct buf sc_tab; /* transfer queue */
137: };
138:
139: /* sc_flags */
140: #define VNF_ALIVE 0x01
141: #define VNF_INITED 0x02
142:
143: #if 0 /* if you need static allocation */
144: struct vnd_softc vn_softc[NVND];
145: int numvnd = NVND;
146: #else
147: struct vnd_softc *vnd_softc;
148: int numvnd;
149: #endif
150:
151: void vndclear __P((struct vnd_softc *));
152: void vndstart __P((struct vnd_softc *));
153: int vndsetcred __P((struct vnd_softc *, struct ucred *));
154: void vndthrottle __P((struct vnd_softc *, struct vnode *));
155:
156: void
157: vndattach(num)
158: int num;
159: {
160: char *mem;
161: register u_long size;
162:
163: if (num <= 0)
164: return;
165: size = num * sizeof(struct vnd_softc);
166: // mem = malloc(size, M_DEVBUF, M_NOWAIT);
167: MALLOC(mem, char *, size, M_DEVBUF, M_NOWAIT);
168: if (mem == NULL) {
169: printf("WARNING: no memory for vnode disks\n");
170: return;
171: }
172: bzero(mem, size);
173: vnd_softc = (struct vnd_softc *)mem;
174: numvnd = num;
175: }
176:
177: int
178: vndopen(dev, flags, mode, p)
179: dev_t dev;
180: int flags, mode;
181: struct proc *p;
182: {
183: int unit = vndunit(dev);
184:
185: #ifdef DEBUG
186: if (vnddebug & VDB_FOLLOW)
187: printf("vndopen(%x, %x, %x, %x)\n", dev, flags, mode, p);
188: #endif
189: if (unit >= numvnd)
190: return(ENXIO);
191: return(0);
192: }
193:
194: int
195: vndclose(dev, flags, mode, p)
196: dev_t dev;
197: int flags, mode;
198: struct proc *p;
199: {
200: #ifdef DEBUG
201: if (vnddebug & VDB_FOLLOW)
202: printf("vndclose(%x, %x, %x, %x)\n", dev, flags, mode, p);
203: #endif
204: return 0;
205: }
206:
207: /*
208: * Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY.
209: * Note that this driver can only be used for swapping over NFS on the hp
210: * since nfs_strategy on the vax cannot handle u-areas and page tables.
211: */
212: void
213: vndstrategy(bp)
214: register struct buf *bp;
215: {
216: int unit = vndunit(bp->b_dev);
217: register struct vnd_softc *vnd = &vnd_softc[unit];
218: register struct vndbuf *nbp;
219: register int bn, bsize, resid;
220: register caddr_t addr;
221: int sz, flags, error;
222: extern void vndiodone();
223:
224: #ifdef DEBUG
225: if (vnddebug & VDB_FOLLOW)
226: printf("vndstrategy(%x): unit %d\n", bp, unit);
227: #endif
228: if ((vnd->sc_flags & VNF_INITED) == 0) {
229: bp->b_error = ENXIO;
230: bp->b_flags |= B_ERROR;
231: biodone(bp);
232: return;
233: }
234: bn = bp->b_blkno;
235: sz = howmany(bp->b_bcount, DEV_BSIZE);
236: bp->b_resid = bp->b_bcount;
237: if (bn < 0 || bn + sz > vnd->sc_size) {
238: if (bn != vnd->sc_size) {
239: bp->b_error = EINVAL;
240: bp->b_flags |= B_ERROR;
241: }
242: biodone(bp);
243: return;
244: }
245: bn = dbtob(bn);
246: bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize;
247: addr = bp->b_data;
248: flags = bp->b_flags | B_CALL;
249: for (resid = bp->b_resid; resid; resid -= sz) {
250: struct vnode *vp;
251: daddr_t nbn;
252: int off, s, nra;
253:
254: nra = 0;
255: error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra);
256: if (error == 0 && (long)nbn == -1)
257: error = EIO;
258: #ifdef DEBUG
259: if (!dovndcluster)
260: nra = 0;
261: #endif
262:
263: if (off = bn % bsize)
264: sz = bsize - off;
265: else
266: sz = (1 + nra) * bsize;
267: if (resid < sz)
268: sz = resid;
269: #ifdef DEBUG
270: if (vnddebug & VDB_IO)
271: printf("vndstrategy: vp %x/%x bn %x/%x sz %x\n",
272: vnd->sc_vp, vp, bn, nbn, sz);
273: #endif
274:
275: // nbp = getvndbuf();
276: MALLOC(nbp, struct vndbuf *, sizeof(struct vndbuf),M_DEVBUF, M_WAITOK);
277: nbp->vb_buf.b_flags = flags;
278: nbp->vb_buf.b_bcount = sz;
279: nbp->vb_buf.b_bufsize = bp->b_bufsize;
280: nbp->vb_buf.b_error = 0;
281: if (vp->v_type == VBLK || vp->v_type == VCHR)
282: nbp->vb_buf.b_dev = vp->v_rdev;
283: else
284: nbp->vb_buf.b_dev = NODEV;
285: nbp->vb_buf.b_data = addr;
286: nbp->vb_buf.b_blkno = nbn + btodb(off);
287: nbp->vb_buf.b_proc = bp->b_proc;
288: nbp->vb_buf.b_iodone = vndiodone;
289: nbp->vb_buf.b_vp = vp;
290: nbp->vb_buf.b_rcred = vnd->sc_cred; /* XXX crdup? */
291: nbp->vb_buf.b_wcred = vnd->sc_cred; /* XXX crdup? */
292: nbp->vb_buf.b_dirtyoff = bp->b_dirtyoff;
293: nbp->vb_buf.b_dirtyend = bp->b_dirtyend;
294: nbp->vb_buf.b_validoff = bp->b_validoff;
295: nbp->vb_buf.b_validend = bp->b_validend;
296:
297: /* save a reference to the old buffer */
298: nbp->vb_obp = bp;
299:
300: /*
301: * If there was an error or a hole in the file...punt.
302: * Note that we deal with this after the nbp allocation.
303: * This ensures that we properly clean up any operations
304: * that we have already fired off.
305: *
306: * XXX we could deal with holes here but it would be
307: * a hassle (in the write case).
308: */
309: if (error) {
310: nbp->vb_buf.b_error = error;
311: nbp->vb_buf.b_flags |= B_ERROR;
312: bp->b_resid -= (resid - sz);
313: biodone(&nbp->vb_buf);
314: return;
315: }
316: /*
317: * Just sort by block number
318: */
319: nbp->vb_buf.b_cylin = nbp->vb_buf.b_blkno;
320: s = splbio();
321: disksort(&vnd->sc_tab, &nbp->vb_buf);
322: if (vnd->sc_tab.b_active < vnd->sc_maxactive) {
323: vnd->sc_tab.b_active++;
324: vndstart(vnd);
325: }
326: splx(s);
327: bn += sz;
328: addr += sz;
329: }
330: }
331:
332: /*
333: * Feed requests sequentially.
334: * We do it this way to keep from flooding NFS servers if we are connected
335: * to an NFS file. This places the burden on the client rather than the
336: * server.
337: */
338: void
339: vndstart(vnd)
340: register struct vnd_softc *vnd;
341: {
342: register struct buf *bp;
343:
344: /*
345: * Dequeue now since lower level strategy routine might
346: * queue using same links
347: */
348: bp = vnd->sc_tab.b_actf;
349: vnd->sc_tab.b_actf = bp->b_actf;
350: #ifdef DEBUG
351: if (vnddebug & VDB_IO)
352: printf("vndstart(%d): bp %x vp %x blkno %x addr %x cnt %x\n",
353: vnd-vnd_softc, bp, bp->b_vp, bp->b_blkno, bp->b_data,
354: bp->b_bcount);
355: #endif
356: if ((bp->b_flags & B_READ) == 0)
357: bp->b_vp->v_numoutput++;
358: VOP_STRATEGY(bp);
359: }
360:
361: void
362: vndiodone(vbp)
363: register struct vndbuf *vbp;
364: {
365: register struct buf *pbp = vbp->vb_obp;
366: register struct vnd_softc *vnd = &vnd_softc[vndunit(pbp->b_dev)];
367: int s;
368:
369: s = splbio();
370: #ifdef DEBUG
371: if (vnddebug & VDB_IO)
372: printf("vndiodone(%d): vbp %x vp %x blkno %x addr %x cnt %x\n",
373: vnd-vnd_softc, vbp, vbp->vb_buf.b_vp, vbp->vb_buf.b_blkno,
374: vbp->vb_buf.b_data, vbp->vb_buf.b_bcount);
375: #endif
376: if (vbp->vb_buf.b_error) {
377: #ifdef DEBUG
378: if (vnddebug & VDB_IO)
379: printf("vndiodone: vbp %x error %d\n", vbp,
380: vbp->vb_buf.b_error);
381: #endif
382: pbp->b_flags |= B_ERROR;
383: pbp->b_error = biowait(&vbp->vb_buf);
384: }
385: pbp->b_resid -= vbp->vb_buf.b_bcount;
386: putvndbuf(vbp);
387: if (pbp->b_resid == 0) {
388: #ifdef DEBUG
389: if (vnddebug & VDB_IO)
390: printf("vndiodone: pbp %x iodone\n", pbp);
391: #endif
392: biodone(pbp);
393: }
394: if (vnd->sc_tab.b_actf)
395: vndstart(vnd);
396: else
397: vnd->sc_tab.b_active--;
398: splx(s);
399: }
400:
401: /* ARGSUSED */
402: int
403: vndioctl(dev, cmd, data, flag, p)
404: dev_t dev;
405: u_long cmd;
406: caddr_t data;
407: int flag;
408: struct proc *p;
409: {
410: int unit = vndunit(dev);
411: register struct vnd_softc *vnd;
412: struct vnd_ioctl *vio;
413: struct vattr vattr;
414: struct nameidata nd;
415: int error;
416:
417: #ifdef DEBUG
418: if (vnddebug & VDB_FOLLOW)
419: printf("vndioctl(%x, %lx, %x, %x, %x): unit %d\n",
420: dev, cmd, data, flag, p, unit);
421: #endif
422: error = suser(p->p_ucred, &p->p_acflag);
423: if (error)
424: return (error);
425: if (unit >= numvnd)
426: return (ENXIO);
427:
428: vnd = &vnd_softc[unit];
429: vio = (struct vnd_ioctl *)data;
430: switch (cmd) {
431:
432: case VNDIOCSET:
433: if (vnd->sc_flags & VNF_INITED)
434: return(EBUSY);
435: /*
436: * Always open for read and write.
437: * This is probably bogus, but it lets vn_open()
438: * weed out directories, sockets, etc. so we don't
439: * have to worry about them.
440: */
441: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p);
442: if (error = vn_open(&nd, FREAD|FWRITE, 0))
443: return(error);
444: if (error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p)) {
445: VOP_UNLOCK(nd.ni_vp);
446: (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
447: return(error);
448: }
449: VOP_UNLOCK(nd.ni_vp);
450: vnd->sc_vp = nd.ni_vp;
451: vnd->sc_size = btodb(vattr.va_size); /* note truncation */
452: if (error = vndsetcred(vnd, p->p_ucred)) {
453: (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
454: return(error);
455: }
456: vndthrottle(vnd, vnd->sc_vp);
457: vio->vnd_size = dbtob(vnd->sc_size);
458: vnd->sc_flags |= VNF_INITED;
459: #ifdef DEBUG
460: if (vnddebug & VDB_INIT)
461: printf("vndioctl: SET vp %x size %x\n",
462: vnd->sc_vp, vnd->sc_size);
463: #endif
464: break;
465:
466: case VNDIOCCLR:
467: if ((vnd->sc_flags & VNF_INITED) == 0)
468: return(ENXIO);
469: vndclear(vnd);
470: #ifdef DEBUG
471: if (vnddebug & VDB_INIT)
472: printf("vndioctl: CLRed\n");
473: #endif
474: break;
475:
476: default:
477: return(ENOTTY);
478: }
479: return(0);
480: }
481:
482: /*
483: * Duplicate the current processes' credentials. Since we are called only
484: * as the result of a SET ioctl and only root can do that, any future access
485: * to this "disk" is essentially as root. Note that credentials may change
486: * if some other uid can write directly to the mapped file (NFS).
487: */
488: int
489: vndsetcred(vnd, cred)
490: register struct vnd_softc *vnd;
491: struct ucred *cred;
492: {
493: struct uio auio;
494: struct iovec aiov;
495: char *tmpbuf;
496: int error;
497:
498: vnd->sc_cred = crdup(cred);
499: // tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK);
500: MALLOC(tmpbuf, char *, DEV_BSIZE, M_TEMP, M_WAITOK);
501:
502: /* XXX: Horrible kludge to establish credentials for NFS */
503: aiov.iov_base = tmpbuf;
504: aiov.iov_len = min(DEV_BSIZE, dbtob(vnd->sc_size));
505: auio.uio_iov = &aiov;
506: auio.uio_iovcnt = 1;
507: auio.uio_offset = 0;
508: auio.uio_rw = UIO_READ;
509: auio.uio_segflg = UIO_SYSSPACE;
510: auio.uio_resid = aiov.iov_len;
511: error = VOP_READ(vnd->sc_vp, &auio, 0, vnd->sc_cred);
512:
513: free(tmpbuf, M_TEMP);
514: return (error);
515: }
516:
517: /*
518: * Set maxactive based on FS type
519: */
520: void
521: vndthrottle(vnd, vp)
522: register struct vnd_softc *vnd;
523: struct vnode *vp;
524: {
525: #ifdef NFSCLIENT
526: extern int (**nfsv2_vnodeop_p)();
527:
528: if (vp->v_op == nfsv2_vnodeop_p)
529: vnd->sc_maxactive = 2;
530: else
531: #endif
532: vnd->sc_maxactive = 8;
533:
534: if (vnd->sc_maxactive < 1)
535: vnd->sc_maxactive = 1;
536: }
537:
538: void
539: vndshutdown()
540: {
541: register struct vnd_softc *vnd;
542:
543: for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++)
544: if (vnd->sc_flags & VNF_INITED)
545: vndclear(vnd);
546: }
547:
548: void
549: vndclear(vnd)
550: register struct vnd_softc *vnd;
551: {
552: register struct vnode *vp = vnd->sc_vp;
553: struct proc *p = curproc; /* XXX */
554: struct ucred *cred;
555:
556: #ifdef DEBUG
557: if (vnddebug & VDB_FOLLOW)
558: printf("vndclear(%x): vp %x\n", vp);
559: #endif
560: vnd->sc_flags &= ~VNF_INITED;
561: if (vp == (struct vnode *)0)
562: panic("vndioctl: null vp");
563: (void) vn_close(vp, FREAD|FWRITE, vnd->sc_cred, p);
564: cred = vnd->sc_cred;
565: if (cred != NOCRED) {
566: vnd->sc_cred = NOCRED;
567: crfree(cred);
568: }
569: vnd->sc_vp = (struct vnode *)0;
570: vnd->sc_size = 0;
571: }
572:
573: int
574: vndsize(dev)
575: dev_t dev;
576: {
577: int unit = vndunit(dev);
578: register struct vnd_softc *vnd = &vnd_softc[unit];
579:
580: if (unit >= numvnd || (vnd->sc_flags & VNF_INITED) == 0)
581: return(-1);
582: return(vnd->sc_size);
583: }
584:
585: int
586: vnddump(dev)
587: dev_t dev;
588: {
589:
590: return(ENXIO);
591: }
592: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.