|
|
1.1 root 1: /*
2: * Copyright (c) 1988 University of Utah.
3: * Copyright (c) 1990 The Regents of the University of California.
4: * All rights reserved.
5: *
6: * This code is derived from software contributed to Berkeley by
7: * the Systems Programming Group of the University of Utah Computer
8: * Science Department.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the University of
21: * California, Berkeley and its contributors.
22: * 4. Neither the name of the University nor the names of its contributors
23: * may be used to endorse or promote products derived from this software
24: * without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36: * SUCH DAMAGE.
37: *
38: * from: Utah $Hdr: vn.c 1.1 91/04/30$
39: *
40: * @(#)vn.c 7.6 (Berkeley) 6/21/91
41: */
42:
43: /*
44: * Vnode disk driver.
45: *
46: * Block/character interface to a vnode. Allows one to treat a file
47: * as a disk (e.g. build a filesystem in it, mount it, etc.).
48: *
49: * NOTE 1: This uses the VOP_BMAP/VOP_STRATEGY interface to the vnode
50: * instead of a simple VOP_RDWR. We do this to avoid distorting the
51: * local buffer cache.
52: *
53: * NOTE 2: There is a security issue involved with this driver.
54: * Once mounted all access to the contents of the "mapped" file via
55: * the special file is controlled by the permissions on the special
56: * file, the protection of the mapped file is ignored (effectively,
57: * by using root credentials in all transactions).
58: */
59: #include "vn.h"
60: #if NVN > 0
61:
62: #include "sys/param.h"
63: #include "sys/systm.h"
64: #include "sys/namei.h"
65: #include "sys/proc.h"
66: #include "sys/errno.h"
67: #include "sys/dkstat.h"
68: #include "sys/buf.h"
69: #include "sys/malloc.h"
70: #include "sys/ioctl.h"
71: #include "sys/mount.h"
72: #include "sys/vnode.h"
73: #include "sys/specdev.h"
74: #include "sys/file.h"
75: #include "sys/uio.h"
76:
77: #include "vnioctl.h"
78:
79: #ifdef DEBUG
80: int vndebug = 0x00;
81: #define VDB_FOLLOW 0x01
82: #define VDB_INIT 0x02
83: #define VDB_IO 0x04
84: #endif
85:
86: struct buf vnbuf[NVN];
87: struct buf vntab[NVN];
88:
89: #define b_cylin b_resid
90:
91: #define vnunit(x) ((minor(x) >> 3) & 0x7) /* for consistency */
92:
93: #define getvnbuf() \
94: ((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK))
95: #define putvnbuf(bp) \
96: free((caddr_t)(bp), M_DEVBUF)
97:
98: struct vn_softc {
99: int sc_flags; /* flags */
100: size_t sc_size; /* size of vn */
101: struct vnode *sc_vp; /* vnode */
102: struct ucred *sc_cred; /* credentials */
103: int sc_maxactive; /* max # of active requests */
104: } vn_softc[NVN];
105:
106: /* sc_flags */
107: #define VNF_ALIVE 0x01
108: #define VNF_INITED 0x02
109:
110: int
111: vnopen(dev, flags, mode, p)
112: dev_t dev;
113: int flags, mode;
114: struct proc *p;
115: {
116: int unit = vnunit(dev);
117:
118: #ifdef DEBUG
119: if (vndebug & VDB_FOLLOW)
120: printf("vnopen(%x, %x, %x, %x)\n", dev, flags, mode, p);
121: #endif
122: if (unit >= NVN)
123: return(ENXIO);
124: return(0);
125: }
126:
127: /*
128: * Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY.
129: * Note that this driver can only be used for swapping over NFS on the hp
130: * since nfs_strategy on the vax cannot handle u-areas and page tables.
131: */
132: vnstrategy(bp)
133: register struct buf *bp;
134: {
135: int unit = vnunit(bp->b_dev);
136: register struct vn_softc *vn = &vn_softc[unit];
137: register struct buf *nbp;
138: register int bn, bsize, resid;
139: register caddr_t addr;
140: int sz, flags;
141: extern int vniodone();
142:
143: #ifdef DEBUG
144: if (vndebug & VDB_FOLLOW)
145: printf("vnstrategy(%x): unit %d\n", bp, unit);
146: #endif
147: if ((vn->sc_flags & VNF_INITED) == 0) {
148: bp->b_error = ENXIO;
149: bp->b_flags |= B_ERROR;
150: biodone(bp);
151: return;
152: }
153: bn = bp->b_blkno;
154: sz = howmany(bp->b_bcount, DEV_BSIZE);
155: bp->b_resid = bp->b_bcount;
156: if (bn < 0 || bn + sz > vn->sc_size) {
157: if (bn != vn->sc_size) {
158: bp->b_error = EINVAL;
159: bp->b_flags |= B_ERROR;
160: }
161: biodone(bp);
162: return;
163: }
164: bn = dbtob(bn);
165: bsize = vn->sc_vp->v_mount->mnt_stat.f_bsize;
166: addr = bp->b_un.b_addr;
167: flags = bp->b_flags | B_CALL;
168: for (resid = bp->b_resid; resid; resid -= sz) {
169: struct vnode *vp;
170: daddr_t nbn;
171: int off, s;
172:
173: nbp = getvnbuf();
174: off = bn % bsize;
175: sz = MIN(bsize - off, resid);
176: (void) VOP_BMAP(vn->sc_vp, bn / bsize, &vp, &nbn);
177: #ifdef DEBUG
178: if (vndebug & VDB_IO)
179: printf("vnstrategy: vp %x/%x bn %x/%x\n",
180: vn->sc_vp, vp, bn, nbn);
181: #endif
182: nbp->b_flags = flags;
183: nbp->b_bcount = sz;
184: nbp->b_bufsize = bp->b_bufsize;
185: nbp->b_error = 0;
186: if (vp->v_type == VBLK || vp->v_type == VCHR)
187: nbp->b_dev = vp->v_rdev;
188: else
189: nbp->b_dev = NODEV;
190: nbp->b_un.b_addr = addr;
191: nbp->b_blkno = nbn + btodb(off);
192: nbp->b_proc = bp->b_proc;
193: nbp->b_iodone = vniodone;
194: nbp->b_vp = vp;
195: nbp->b_pfcent = (int) bp; /* XXX */
196: /*
197: * Just sort by block number
198: */
199: nbp->b_cylin = nbp->b_blkno;
200: s = splbio();
201: disksort(&vntab[unit], nbp);
202: if (vntab[unit].b_active < vn->sc_maxactive) {
203: vntab[unit].b_active++;
204: vnstart(unit);
205: }
206: splx(s);
207: bn += sz;
208: addr += sz;
209: }
210: }
211:
212: /*
213: * Feed requests sequentially.
214: * We do it this way to keep from flooding NFS servers if we are connected
215: * to an NFS file. This places the burden on the client rather than the
216: * server.
217: */
218: vnstart(unit)
219: {
220: register struct vn_softc *vn = &vn_softc[unit];
221: register struct buf *bp;
222:
223: /*
224: * Dequeue now since lower level strategy routine might
225: * queue using same links
226: */
227: bp = vntab[unit].b_actf;
228: vntab[unit].b_actf = bp->b_actf;
229: #ifdef DEBUG
230: if (vndebug & VDB_IO)
231: printf("vnstart(%d): bp %x vp %x blkno %x addr %x cnt %x\n",
232: unit, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr,
233: bp->b_bcount);
234: #endif
235: VOP_STRATEGY(bp);
236: }
237:
238: vniodone(bp)
239: register struct buf *bp;
240: {
241: register struct buf *pbp = (struct buf *)bp->b_pfcent; /* XXX */
242: register int unit = vnunit(pbp->b_dev);
243: int s;
244:
245: s = splbio();
246: #ifdef DEBUG
247: if (vndebug & VDB_IO)
248: printf("vniodone(%d): bp %x vp %x blkno %x addr %x cnt %x\n",
249: unit, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr,
250: bp->b_bcount);
251: #endif
252: if (bp->b_error) {
253: #ifdef DEBUG
254: if (vndebug & VDB_IO)
255: printf("vniodone: bp %x error %d\n", bp, bp->b_error);
256: #endif
257: pbp->b_flags |= B_ERROR;
258: pbp->b_error = biowait(bp);
259: }
260: pbp->b_resid -= bp->b_bcount;
261: putvnbuf(bp);
262: if (pbp->b_resid == 0) {
263: #ifdef DEBUG
264: if (vndebug & VDB_IO)
265: printf("vniodone: pbp %x iodone\n", pbp);
266: #endif
267: biodone(pbp);
268: }
269: if (vntab[unit].b_actf)
270: vnstart(unit);
271: else
272: vntab[unit].b_active--;
273: splx(s);
274: }
275:
276: vnread(dev, uio, flags, p)
277: dev_t dev;
278: struct uio *uio;
279: int flags;
280: struct proc *p;
281: {
282: register int unit = vnunit(dev);
283:
284: #ifdef DEBUG
285: if (vndebug & VDB_FOLLOW)
286: printf("vnread(%x, %x, %x, %x)\n", dev, uio, flags, p);
287: #endif
288: #if 0
289: return(physio(vnstrategy, &vnbuf[unit], dev, B_READ, minphys, uio));
290: #else
291: return rawread (dev, uio);
292: #endif
293: }
294:
295: vnwrite(dev, uio, flags, p)
296: dev_t dev;
297: struct uio *uio;
298: int flags;
299: struct proc *p;
300: {
301: register int unit = vnunit(dev);
302:
303: #ifdef DEBUG
304: if (vndebug & VDB_FOLLOW)
305: printf("vnwrite(%x, %x, %x, %x)\n", dev, uio, flags, p);
306: #endif
307: #if 0
308: return(physio(vnstrategy, &vnbuf[unit], dev, B_WRITE, minphys, uio));
309: #else
310: return rawwrite (dev, uio);
311: #endif
312: }
313:
314: /* ARGSUSED */
315: vnioctl(dev, cmd, data, flag, p)
316: dev_t dev;
317: u_long cmd;
318: caddr_t data;
319: int flag;
320: struct proc *p;
321: {
322: int unit = vnunit(dev);
323: register struct vn_softc *vn;
324: struct vn_ioctl *vio;
325: struct vattr vattr;
326: struct nameidata nd;
327: int error;
328:
329: #ifdef DEBUG
330: if (vndebug & VDB_FOLLOW)
331: printf("vnioctl(%x, %x, %x, %x, %x): unit %d\n",
332: dev, cmd, data, flag, p, unit);
333: #endif
334: error = suser(p->p_ucred, &p->p_acflag);
335: if (error)
336: return (error);
337: if (unit >= NVN)
338: return (ENXIO);
339:
340: vn = &vn_softc[unit];
341: vio = (struct vn_ioctl *)data;
342: switch (cmd) {
343:
344: case VNIOCSET:
345: if (vn->sc_flags & VNF_INITED)
346: return(EBUSY);
347: /*
348: * Always open for read and write.
349: * This is probably bogus, but it lets vn_open()
350: * weed out directories, sockets, etc. so we don't
351: * have to worry about them.
352: */
353: nd.ni_segflg = UIO_USERSPACE;
354: nd.ni_dirp = vio->vn_file;
355: if (error = vn_open(&nd, p, FREAD|FWRITE, 0))
356: return(error);
357: if (error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p)) {
358: VOP_UNLOCK(nd.ni_vp);
359: (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
360: return(error);
361: }
362: VOP_UNLOCK(nd.ni_vp);
363: vn->sc_vp = nd.ni_vp;
364: vn->sc_size = btodb(vattr.va_size); /* note truncation */
365: if (error = vnsetcred(vn, p->p_ucred)) {
366: (void) vn_close(vn->sc_vp, FREAD|FWRITE, p->p_ucred, p);
367: return(error);
368: }
369: vnthrottle(vn, vn->sc_vp);
370: vio->vn_size = dbtob(vn->sc_size);
371: vn->sc_flags |= VNF_INITED;
372: #ifdef DEBUG
373: if (vndebug & VDB_INIT)
374: printf("vnioctl: SET vp %x size %x\n",
375: vn->sc_vp, vn->sc_size);
376: #endif
377: break;
378:
379: case VNIOCCLR:
380: if ((vn->sc_flags & VNF_INITED) == 0)
381: return(ENXIO);
382: vnclear(vn);
383: #ifdef DEBUG
384: if (vndebug & VDB_INIT)
385: printf("vnioctl: CLRed\n");
386: #endif
387: break;
388:
389: default:
390: return(ENXIO);
391: }
392: return(0);
393: }
394:
395: /*
396: * Duplicate the current processes' credentials. Since we are called only
397: * as the result of a SET ioctl and only root can do that, any future access
398: * to this "disk" is essentially as root. Note that credentials may change
399: * if some other uid can write directly to the mapped file (NFS).
400: */
401: vnsetcred(vn, cred)
402: register struct vn_softc *vn;
403: struct ucred *cred;
404: {
405: struct uio auio;
406: struct iovec aiov;
407: char tmpbuf[DEV_BSIZE];
408:
409: vn->sc_cred = crdup(cred);
410: /* XXX: Horrible kludge to establish credentials for NFS */
411: aiov.iov_base = tmpbuf;
412: aiov.iov_len = MIN(DEV_BSIZE, dbtob(vn->sc_size));
413: auio.uio_iov = &aiov;
414: auio.uio_iovcnt = 1;
415: auio.uio_offset = 0;
416: auio.uio_rw = UIO_READ;
417: auio.uio_segflg = UIO_SYSSPACE;
418: auio.uio_resid = aiov.iov_len;
419: return(VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred));
420: }
421:
422: /*
423: * Set maxactive based on FS type
424: */
425: vnthrottle(vn, vp)
426: register struct vn_softc *vn;
427: struct vnode *vp;
428: {
429: extern struct vnodeops ufs_vnodeops, nfsv2_vnodeops;
430:
431: if (vp->v_op == &nfsv2_vnodeops)
432: vn->sc_maxactive = 2;
433: else
434: vn->sc_maxactive = 8;
435:
436: if (vn->sc_maxactive < 1)
437: vn->sc_maxactive = 1;
438: }
439:
440: vnshutdown()
441: {
442: register struct vn_softc *vn;
443:
444: for (vn = &vn_softc[0]; vn < &vn_softc[NVN]; vn++)
445: if (vn->sc_flags & VNF_INITED)
446: vnclear(vn);
447: }
448:
449: vnclear(vn)
450: register struct vn_softc *vn;
451: {
452: register struct vnode *vp = vn->sc_vp;
453: struct proc *p = curproc; /* XXX */
454:
455: #ifdef DEBUG
456: if (vndebug & VDB_FOLLOW)
457: printf("vnclear(%x): vp %x\n", vp);
458: #endif
459: vn->sc_flags &= ~VNF_INITED;
460: if (vp == (struct vnode *)0)
461: panic("vnioctl: null vp");
462: #if 0
463: /* XXX - this doesn't work right now */
464: (void) VOP_FSYNC(vp, 0, vn->sc_cred, MNT_WAIT, p);
465: #endif
466: (void) vn_close(vp, FREAD|FWRITE, vn->sc_cred, p);
467: crfree(vn->sc_cred);
468: vn->sc_vp = (struct vnode *)0;
469: vn->sc_cred = (struct ucred *)0;
470: vn->sc_size = 0;
471: }
472:
473: vnsize(dev)
474: dev_t dev;
475: {
476: int unit = vnunit(dev);
477: register struct vn_softc *vn = &vn_softc[unit];
478:
479: if (unit >= NVN || (vn->sc_flags & VNF_INITED) == 0)
480: return(-1);
481: return(vn->sc_size);
482: }
483:
484: vndump(dev)
485: {
486: return(ENXIO);
487: }
488: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.