|
|
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 is only permitted until one year after the first shipment
11: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
12: * binary forms are permitted provided that: (1) source distributions retain
13: * this entire copyright notice and comment, and (2) distributions including
14: * binaries display the following acknowledgement: This product includes
15: * software developed by the University of California, Berkeley and its
16: * contributors'' in the documentation or other materials provided with the
17: * distribution and in all advertising materials mentioning features or use
18: * of this software. Neither the name of the University nor the names of
19: * its contributors may be used to endorse or promote products derived from
20: * this software without specific prior written permission.
21: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
22: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
23: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24: *
25: * from: Utah $Hdr: fd.c 1.3 89/12/03$
26: *
27: * @(#)fd.c 7.1 (Berkeley) 5/8/90
28: */
29:
30: /*
31: * File (vnode) disk driver.
32: *
33: * Block/character interface to a vnode. Note that this uses the
34: * VOP_BMAP/VOP_STRATEGY interface to the vnode instead of a simple
35: * VOP_RDWR. We do this to avoid distorting the local buffer cache.
36: *
37: * NOTE: There is a security issue involved with this driver.
38: * Once mounted all access to the contents of the "mapped" file via
39: * the special file is controlled by the permissions on the special
40: * file, the protection of the mapped file is ignored (effectively,
41: * by using root credentials in all transactions).
42: */
43: #include "fd.h"
44: #if NFD > 0
45:
46: #include "param.h"
47: #include "systm.h"
48: #include "buf.h"
49: #include "errno.h"
50: #include "dkstat.h"
51: #include "ioctl.h"
52: #include "user.h"
53: #include "vfs.h"
54: #include "vnode.h"
55: #include "file.h"
56: #include "uio.h"
57: #include "malloc.h"
58:
59: #include "fdioctl.h"
60:
61: #ifdef DEBUG
62: int fddebug = 0x00;
63: #define FDB_FOLLOW 0x01
64: #define FDB_INIT 0x02
65: #define FDB_IO 0x04
66: #endif
67:
68: struct buf fdbuf[NFD];
69: struct buf fdtab[NFD];
70:
71: #define b_cylin b_resid
72:
73: #define fdunit(x) ((minor(x) >> 3) & 0x7) /* for consistency */
74:
75: #define getfdbuf() \
76: ((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK))
77: #define putfdbuf(bp) \
78: free((caddr_t)(bp), M_DEVBUF)
79:
80: struct fd_softc {
81: int sc_flags; /* flags */
82: size_t sc_size; /* size of fd */
83: struct vnode *sc_vp; /* vnode */
84: struct ucred *sc_cred; /* credentials */
85: int sc_maxactive; /* max # of active requests */
86: } fd_softc[NFD];
87:
88: /* sc_flags */
89: #define FDF_ALIVE 0x01
90: #define FDF_INITED 0x02
91:
92: fdopen(dev, flags)
93: dev_t dev;
94: {
95: int unit = fdunit(dev);
96:
97: #ifdef DEBUG
98: if (fddebug & FDB_FOLLOW)
99: printf("fdopen(%x, %x)\n", dev, flags);
100: #endif
101: if (unit >= NFD)
102: return(ENXIO);
103: return(0);
104: }
105:
106: /*
107: * Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY.
108: * Note that this driver can only be used for swapping over NFS on the hp
109: * since nfs_strategy on the vax cannot handle u-areas and page tables.
110: */
111: fdstrategy(bp)
112: register struct buf *bp;
113: {
114: int unit = fdunit(bp->b_dev);
115: register struct fd_softc *fs = &fd_softc[unit];
116: register struct buf *nbp;
117: register int bn, bsize, resid;
118: register caddr_t addr;
119: int sz, flags;
120: extern int fdiodone();
121:
122: #ifdef DEBUG
123: if (fddebug & FDB_FOLLOW)
124: printf("fdstrategy(%x): unit %d\n", bp, unit);
125: #endif
126: if ((fs->sc_flags & FDF_INITED) == 0) {
127: bp->b_error = ENXIO;
128: bp->b_flags |= B_ERROR;
129: iodone(bp);
130: return;
131: }
132: bn = bp->b_blkno;
133: sz = howmany(bp->b_bcount, DEV_BSIZE);
134: bp->b_resid = bp->b_bcount;
135: if (bn < 0 || bn + sz > fs->sc_size) {
136: if (bn != fs->sc_size) {
137: bp->b_error = EINVAL;
138: bp->b_flags |= B_ERROR;
139: }
140: iodone(bp);
141: return;
142: }
143: bn = dbtob(bn);
144: bsize = fs->sc_vp->v_vfsp->vfs_bsize;
145: addr = bp->b_un.b_addr;
146: flags = bp->b_flags | B_CALL;
147: for (resid = bp->b_resid; resid; resid -= sz) {
148: struct vnode *vp;
149: daddr_t nbn;
150: int off, s;
151:
152: nbp = getfdbuf();
153: off = bn % bsize;
154: sz = MIN(bsize - off, resid);
155: (void) VOP_BMAP(fs->sc_vp, bn / bsize, &vp, &nbn);
156: #ifdef DEBUG
157: if (fddebug & FDB_IO)
158: printf("fdstrategy: vp %x/%x bn %x/%x dev %x\n",
159: fs->sc_vp, vp, bn, nbn, vp->v_rdev);
160: #endif
161: nbp->b_flags = flags;
162: nbp->b_bcount = sz;
163: nbp->b_bufsize = bp->b_bufsize;
164: nbp->b_error = 0;
165: nbp->b_dev = vp->v_rdev;
166: nbp->b_un.b_addr = addr;
167: nbp->b_blkno = nbn + btodb(off);
168: nbp->b_proc = bp->b_proc;
169: nbp->b_iodone = fdiodone;
170: nbp->b_vp = vp;
171: nbp->b_pfcent = (int) bp; /* XXX */
172: /*
173: * Just sort by block number
174: */
175: nbp->b_cylin = nbp->b_blkno;
176: s = splbio();
177: disksort(&fdtab[unit], nbp);
178: if (fdtab[unit].b_active < fs->sc_maxactive) {
179: fdtab[unit].b_active++;
180: fdstart(unit);
181: }
182: splx(s);
183: bn += sz;
184: addr += sz;
185: }
186: }
187:
188: /*
189: * Feed requests sequentially.
190: * We do it this way to keep from flooding NFS servers if we are connected
191: * to an NFS file. This places the burden on the client rather than the
192: * server.
193: */
194: fdstart(unit)
195: {
196: register struct fd_softc *fs = &fd_softc[unit];
197: register struct buf *bp;
198:
199: /*
200: * Dequeue now since lower level strategy routine might
201: * queue using same links
202: */
203: bp = fdtab[unit].b_actf;
204: fdtab[unit].b_actf = bp->b_actf;
205: #ifdef DEBUG
206: if (fddebug & FDB_IO)
207: printf("fdstart(%d): bp %x vp %x blkno %x addr %x cnt %x\n",
208: unit, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr,
209: bp->b_bcount);
210: #endif
211: VOP_STRATEGY(bp);
212: }
213:
214: fdiodone(bp)
215: register struct buf *bp;
216: {
217: register struct buf *pbp = (struct buf *)bp->b_pfcent; /* XXX */
218: register int unit = fdunit(pbp->b_dev);
219: int s;
220:
221: s = splbio();
222: #ifdef DEBUG
223: if (fddebug & FDB_IO)
224: printf("fdiodone(%d): bp %x vp %x blkno %x addr %x cnt %x\n",
225: unit, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr,
226: bp->b_bcount);
227: #endif
228: if (bp->b_error) {
229: #ifdef DEBUG
230: if (fddebug & FDB_IO)
231: printf("fdiodone: bp %x error %d\n", bp, bp->b_error);
232: #endif
233: pbp->b_flags |= B_ERROR;
234: pbp->b_error = geterror(bp);
235: }
236: pbp->b_resid -= bp->b_bcount;
237: putfdbuf(bp);
238: if (pbp->b_resid == 0) {
239: #ifdef DEBUG
240: if (fddebug & FDB_IO)
241: printf("fdiodone: pbp %x iodone\n", pbp);
242: #endif
243: iodone(pbp);
244: }
245: if (fdtab[unit].b_actf)
246: fdstart(unit);
247: else
248: fdtab[unit].b_active--;
249: splx(s);
250: }
251:
252: fdread(dev, uio)
253: dev_t dev;
254: struct uio *uio;
255: {
256: register int unit = fdunit(dev);
257:
258: #ifdef DEBUG
259: if (fddebug & FDB_FOLLOW)
260: printf("fdread(%x, %x)\n", dev, uio);
261: #endif
262: return(physio(fdstrategy, &fdbuf[unit], dev, B_READ, minphys, uio));
263: }
264:
265: fdwrite(dev, uio)
266: dev_t dev;
267: struct uio *uio;
268: {
269: register int unit = fdunit(dev);
270:
271: #ifdef DEBUG
272: if (fddebug & FDB_FOLLOW)
273: printf("fdwrite(%x, %x)\n", dev, uio);
274: #endif
275: return(physio(fdstrategy, &fdbuf[unit], dev, B_WRITE, minphys, uio));
276: }
277:
278: /* ARGSUSED */
279: fdioctl(dev, cmd, data, flag)
280: dev_t dev;
281: u_long cmd;
282: caddr_t data;
283: int flag;
284: {
285: int unit = fdunit(dev);
286: register struct fd_softc *fs;
287: struct fd_ioctl *fio;
288: struct vattr vattr;
289: struct vnode *vp;
290: int error;
291:
292: #ifdef DEBUG
293: if (fddebug & FDB_FOLLOW)
294: printf("fdioctl(%x, %x, %x, %x): unit %d\n",
295: dev, cmd, data, flag, unit);
296: #endif
297: error = suser(u.u_cred, &u.u_acflag);
298: if (error)
299: return (error);
300: if (unit >= NFD)
301: return (ENXIO);
302:
303: fs = &fd_softc[unit];
304: fio = (struct fd_ioctl *)data;
305: switch (cmd) {
306:
307: case FDIOCSET:
308: if (fs->sc_flags & FDF_INITED)
309: return(EBUSY);
310: /*
311: * Always open for read and write.
312: * This is probably bogus, but it lets vn_open()
313: * weed out directories, sockets, etc. so we don't
314: * have to worry about them.
315: */
316: error = vn_open(fio->fd_file, UIO_USERSPACE,
317: FREAD|FWRITE, 0, &vp);
318: if (error)
319: return(error);
320: error = VOP_GETATTR(vp, &vattr, u.u_cred);
321: if (error) {
322: vn_close(vp, FREAD|FWRITE);
323: VN_RELE(vp);
324: return(error);
325: }
326: fs->sc_vp = vp;
327: fs->sc_size = btodb(vattr.va_size); /* note truncation */
328: error = fdsetcred(fs);
329: if (error) {
330: vn_close(vp, FREAD|FWRITE);
331: VN_RELE(vp);
332: return(error);
333: }
334: fdthrottle(fs, vp);
335: fio->fd_size = dbtob(fs->sc_size);
336: fs->sc_flags |= FDF_INITED;
337: #ifdef DEBUG
338: if (fddebug & FDB_INIT)
339: printf("fdioctl: SET vp %x size %x\n",
340: fs->sc_vp, fs->sc_size);
341: #endif
342: break;
343:
344: case FDIOCCLR:
345: if ((fs->sc_flags & FDF_INITED) == 0)
346: return(ENXIO);
347: fdclear(fs);
348: #ifdef DEBUG
349: if (fddebug & FDB_INIT)
350: printf("fdioctl: CLRed\n");
351: #endif
352: break;
353:
354: default:
355: return(ENXIO);
356: }
357: return(0);
358: }
359:
360: /*
361: * Duplicate the current processes' credentials. Since we are called only
362: * as the result of a SET ioctl and only root can do that, any future access
363: * to this "disk" is essentially as root. Note that credentials may change
364: * if some other uid can write directly to the mapped file (NFS).
365: */
366: fdsetcred(fs)
367: register struct fd_softc *fs;
368: {
369: struct uio auio;
370: struct iovec aiov;
371: char tmpbuf[DEV_BSIZE];
372:
373: fs->sc_cred = crdup(u.u_cred);
374: /* XXX: Horrible kludge to establish credentials for NFS */
375: aiov.iov_base = tmpbuf;
376: aiov.iov_len = MIN(DEV_BSIZE, dbtob(fs->sc_size));
377: auio.uio_iov = &aiov;
378: auio.uio_iovcnt = 1;
379: auio.uio_offset = 0;
380: auio.uio_rw = UIO_READ;
381: auio.uio_segflg = UIO_SYSSPACE;
382: auio.uio_resid = aiov.iov_len;
383: return(VOP_READ(fs->sc_vp, &auio, 0, fs->sc_cred));
384: }
385:
386: /*
387: * Set maxactive based on FS type
388: */
389: fdthrottle(fs, vp)
390: register struct fd_softc *fs;
391: struct vnode *vp;
392: {
393: extern struct vnodeops ufs_vnodeops, nfs_vnodeops;
394:
395: if (vp->v_op == &nfs_vnodeops)
396: fs->sc_maxactive = 2;
397: else
398: fs->sc_maxactive = 8;
399:
400: if (fs->sc_maxactive < 1)
401: fs->sc_maxactive = 1;
402: }
403:
404: fdshutdown()
405: {
406: register struct fd_softc *fs;
407:
408: for (fs = &fd_softc[0]; fs < &fd_softc[NFD]; fs++)
409: if (fs->sc_flags & FDF_INITED)
410: fdclear(fs);
411: }
412:
413: fdclear(fs)
414: register struct fd_softc *fs;
415: {
416: register struct vnode *vp = fs->sc_vp;
417:
418: #ifdef DEBUG
419: if (fddebug & FDB_FOLLOW)
420: printf("fdclear(%x): vp %x\n", vp);
421: #endif
422: fs->sc_flags &= ~FDF_INITED;
423: if (vp == (struct vnode *)0)
424: panic("fdioctl: null vp");
425: #if 0
426: /* XXX - this doesn't work right now */
427: (void) VOP_FSYNC(vp, fs->sc_cred);
428: #endif
429: vn_close(vp, FREAD|FWRITE);
430: VN_RELE(vp);
431: crfree(fs->sc_cred);
432: fs->sc_vp = (struct vnode *)0;
433: fs->sc_cred = (struct ucred *)0;
434: fs->sc_size = 0;
435: }
436:
437: fdsize(dev)
438: dev_t dev;
439: {
440: int unit = fdunit(dev);
441: register struct fd_softc *fs = &fd_softc[unit];
442:
443: if (unit >= NFD || (fs->sc_flags & FDF_INITED) == 0)
444: return(-1);
445: return(fs->sc_size);
446: }
447:
448: fddump(dev)
449: {
450: return(ENXIO);
451: }
452: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.