|
|
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: return(physio(vnstrategy, &vnbuf[unit], dev, B_READ, minphys, uio));
289: }
290:
291: vnwrite(dev, uio, flags, p)
292: dev_t dev;
293: struct uio *uio;
294: int flags;
295: struct proc *p;
296: {
297: register int unit = vnunit(dev);
298:
299: #ifdef DEBUG
300: if (vndebug & VDB_FOLLOW)
301: printf("vnwrite(%x, %x, %x, %x)\n", dev, uio, flags, p);
302: #endif
303: return(physio(vnstrategy, &vnbuf[unit], dev, B_WRITE, minphys, uio));
304: }
305:
306: /* ARGSUSED */
307: vnioctl(dev, cmd, data, flag, p)
308: dev_t dev;
309: u_long cmd;
310: caddr_t data;
311: int flag;
312: struct proc *p;
313: {
314: int unit = vnunit(dev);
315: register struct vn_softc *vn;
316: struct vn_ioctl *vio;
317: struct vattr vattr;
318: struct nameidata nd;
319: int error;
320:
321: #ifdef DEBUG
322: if (vndebug & VDB_FOLLOW)
323: printf("vnioctl(%x, %x, %x, %x, %x): unit %d\n",
324: dev, cmd, data, flag, p, unit);
325: #endif
326: error = suser(p->p_ucred, &p->p_acflag);
327: if (error)
328: return (error);
329: if (unit >= NVN)
330: return (ENXIO);
331:
332: vn = &vn_softc[unit];
333: vio = (struct vn_ioctl *)data;
334: switch (cmd) {
335:
336: case VNIOCSET:
337: if (vn->sc_flags & VNF_INITED)
338: return(EBUSY);
339: /*
340: * Always open for read and write.
341: * This is probably bogus, but it lets vn_open()
342: * weed out directories, sockets, etc. so we don't
343: * have to worry about them.
344: */
345: nd.ni_segflg = UIO_USERSPACE;
346: nd.ni_dirp = vio->vn_file;
347: if (error = vn_open(&nd, p, FREAD|FWRITE, 0))
348: return(error);
349: if (error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p)) {
350: VOP_UNLOCK(nd.ni_vp);
351: (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
352: return(error);
353: }
354: VOP_UNLOCK(nd.ni_vp);
355: vn->sc_vp = nd.ni_vp;
356: vn->sc_size = btodb(vattr.va_size); /* note truncation */
357: if (error = vnsetcred(vn, p->p_ucred)) {
358: (void) vn_close(vn->sc_vp, FREAD|FWRITE, p->p_ucred, p);
359: return(error);
360: }
361: vnthrottle(vn, vn->sc_vp);
362: vio->vn_size = dbtob(vn->sc_size);
363: vn->sc_flags |= VNF_INITED;
364: #ifdef DEBUG
365: if (vndebug & VDB_INIT)
366: printf("vnioctl: SET vp %x size %x\n",
367: vn->sc_vp, vn->sc_size);
368: #endif
369: break;
370:
371: case VNIOCCLR:
372: if ((vn->sc_flags & VNF_INITED) == 0)
373: return(ENXIO);
374: vnclear(vn);
375: #ifdef DEBUG
376: if (vndebug & VDB_INIT)
377: printf("vnioctl: CLRed\n");
378: #endif
379: break;
380:
381: default:
382: return(ENXIO);
383: }
384: return(0);
385: }
386:
387: /*
388: * Duplicate the current processes' credentials. Since we are called only
389: * as the result of a SET ioctl and only root can do that, any future access
390: * to this "disk" is essentially as root. Note that credentials may change
391: * if some other uid can write directly to the mapped file (NFS).
392: */
393: vnsetcred(vn, cred)
394: register struct vn_softc *vn;
395: struct ucred cred;
396: {
397: struct uio auio;
398: struct iovec aiov;
399: char tmpbuf[DEV_BSIZE];
400:
401: vn->sc_cred = crdup(cred);
402: /* XXX: Horrible kludge to establish credentials for NFS */
403: aiov.iov_base = tmpbuf;
404: aiov.iov_len = MIN(DEV_BSIZE, dbtob(vn->sc_size));
405: auio.uio_iov = &aiov;
406: auio.uio_iovcnt = 1;
407: auio.uio_offset = 0;
408: auio.uio_rw = UIO_READ;
409: auio.uio_segflg = UIO_SYSSPACE;
410: auio.uio_resid = aiov.iov_len;
411: return(VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred));
412: }
413:
414: /*
415: * Set maxactive based on FS type
416: */
417: vnthrottle(vn, vp)
418: register struct vn_softc *vn;
419: struct vnode *vp;
420: {
421: extern struct vnodeops ufs_vnodeops, nfsv2_vnodeops;
422:
423: if (vp->v_op == &nfsv2_vnodeops)
424: vn->sc_maxactive = 2;
425: else
426: vn->sc_maxactive = 8;
427:
428: if (vn->sc_maxactive < 1)
429: vn->sc_maxactive = 1;
430: }
431:
432: vnshutdown()
433: {
434: register struct vn_softc *vn;
435:
436: for (vn = &vn_softc[0]; vn < &vn_softc[NVN]; vn++)
437: if (vn->sc_flags & VNF_INITED)
438: vnclear(vn);
439: }
440:
441: vnclear(vn)
442: register struct vn_softc *vn;
443: {
444: register struct vnode *vp = vn->sc_vp;
445: struct proc *p = curproc; /* XXX */
446:
447: #ifdef DEBUG
448: if (vndebug & VDB_FOLLOW)
449: printf("vnclear(%x): vp %x\n", vp);
450: #endif
451: vn->sc_flags &= ~VNF_INITED;
452: if (vp == (struct vnode *)0)
453: panic("vnioctl: null vp");
454: #if 0
455: /* XXX - this doesn't work right now */
456: (void) VOP_FSYNC(vp, 0, vn->sc_cred, MNT_WAIT, p);
457: #endif
458: (void) vn_close(vp, FREAD|FWRITE, vn->sc_cred, p);
459: crfree(vn->sc_cred);
460: vn->sc_vp = (struct vnode *)0;
461: vn->sc_cred = (struct ucred *)0;
462: vn->sc_size = 0;
463: }
464:
465: vnsize(dev)
466: dev_t dev;
467: {
468: int unit = vnunit(dev);
469: register struct vn_softc *vn = &vn_softc[unit];
470:
471: if (unit >= NVN || (vn->sc_flags & VNF_INITED) == 0)
472: return(-1);
473: return(vn->sc_size);
474: }
475:
476: vndump(dev)
477: {
478: return(ENXIO);
479: }
480: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.