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