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