fix bug that can cause recursive .forward files to fail
[unix-history] / usr / src / sys / kern / kern_physio.c
CommitLineData
5dc2581e 1/*-
436acd38
KB
2 * Copyright (c) 1982, 1986, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
5dc2581e
KB
4 *
5 * %sccs.include.proprietary.c%
da7c5cc6 6 *
cb84e0ab 7 * @(#)kern_physio.c 8.2 (Berkeley) %G%
da7c5cc6 8 */
961945a8 9
251f56ba
KB
10#include <sys/param.h>
11#include <sys/systm.h>
12#include <sys/buf.h>
13#include <sys/conf.h>
14#include <sys/proc.h>
251f56ba 15#include <sys/vnode.h>
d301d150 16
251f56ba
KB
17static void freeswbuf __P((struct buf *));
18static struct buf *getswbuf __P((int));
edc76308 19
663dbc72 20/*
d99a6abd
KM
21 * This routine does device I/O for a user process.
22 *
4fa687fa 23 * If the user has the proper access privileges, the process is
663dbc72 24 * marked 'delayed unlock' and the pages involved in the I/O are
d99a6abd 25 * faulted and locked. After the completion of the I/O, the pages
663dbc72
BJ
26 * are unlocked.
27 */
d6d7360b
BJ
28physio(strat, bp, dev, rw, mincnt, uio)
29 int (*strat)();
30 register struct buf *bp;
31 dev_t dev;
32 int rw;
c5648f55 33 u_int (*mincnt)();
d6d7360b 34 struct uio *uio;
663dbc72 35{
a196746e 36 register struct iovec *iov;
a9fcede9 37 register int requested = 0, done = 0;
8429d022 38 register struct proc *p = curproc;
663dbc72 39 char *a;
c5648f55 40 int s, allocbuf = 0, error = 0;
ec67a3ce
MK
41#ifdef SECSIZE
42 int bsize;
43 struct partinfo dpart;
44#endif SECSIZE
663dbc72 45
ec67a3ce
MK
46#ifdef SECSIZE
47 if ((unsigned)major(dev) < nchrdev &&
48 (*cdevsw[major(dev)].d_ioctl)(dev, DIOCGPART, (caddr_t)&dpart,
49 FREAD) == 0)
50 bsize = dpart.disklab->d_secsize;
51 else
52 bsize = DEV_BSIZE;
53#endif SECSIZE
54 for (;;) {
55 if (uio->uio_iovcnt == 0)
56 return (0);
57 iov = uio->uio_iov;
58 if (useracc(iov->iov_base, (u_int)iov->iov_len,
59 rw==B_READ? B_WRITE : B_READ) == NULL)
60 return (EFAULT);
61 s = splbio();
62 while (bp->b_flags&B_BUSY) {
63 bp->b_flags |= B_WANTED;
64 sleep((caddr_t)bp, PRIBIO+1);
65 }
c5648f55
KB
66 if (!allocbuf) { /* only if sharing caller's buffer */
67 s = splbio();
68 while (bp->b_flags&B_BUSY) {
69 bp->b_flags |= B_WANTED;
70 sleep((caddr_t)bp, PRIBIO+1);
71 }
72 splx(s);
73 }
ec67a3ce
MK
74 bp->b_error = 0;
75 bp->b_proc = u.u_procp;
76#ifdef SECSIZE
77 bp->b_blksize = bsize;
78#endif SECSIZE
79 bp->b_un.b_addr = iov->iov_base;
80 while (iov->iov_len > 0) {
81 bp->b_flags = B_BUSY | B_PHYS | rw;
82 bp->b_dev = dev;
83#ifdef SECSIZE
84 bp->b_blkno = uio->uio_offset / bsize;
85#else SECSIZE
86 bp->b_blkno = btodb(uio->uio_offset);
87#endif SECSIZE
88 bp->b_bcount = iov->iov_len;
89 (*mincnt)(bp);
90 c = bp->b_bcount;
91 u.u_procp->p_flag |= SPHYSIO;
92 vslock(a = bp->b_un.b_addr, c);
93 physstrat(bp, strat, PRIBIO);
94 (void) splbio();
95 vsunlock(a, c, rw);
96 u.u_procp->p_flag &= ~SPHYSIO;
97 if (bp->b_flags&B_WANTED)
98 wakeup((caddr_t)bp);
99 splx(s);
100 c -= bp->b_resid;
101 bp->b_un.b_addr += c;
102 iov->iov_len -= c;
103 uio->uio_resid -= c;
104 uio->uio_offset += c;
105 /* temp kludge for tape drives */
106 if (bp->b_resid || (bp->b_flags&B_ERROR))
107 break;
108 }
109 bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS);
110 error = geterror(bp);
ec67a3ce
MK
111 if (bp->b_resid || error)
112 return (error);
113 uio->uio_iov++;
114 uio->uio_iovcnt--;
663dbc72 115 }
c5648f55
KB
116 if (allocbuf)
117 freeswbuf(bp);
118 return (error);
663dbc72
BJ
119}
120
d99a6abd
KM
121/*
122 * Calculate the maximum size of I/O request that can be requested
123 * in a single operation. This limit is necessary to prevent a single
124 * process from being able to lock more than a fixed amount of memory
125 * in the kernel.
126 */
c5648f55 127u_int
663dbc72 128minphys(bp)
d6d7360b 129 struct buf *bp;
663dbc72 130{
35a494b8
SL
131 if (bp->b_bcount > MAXPHYS)
132 bp->b_bcount = MAXPHYS;
663dbc72 133}
c5648f55 134
251f56ba 135static struct buf *
c5648f55
KB
136getswbuf(prio)
137 int prio;
138{
139 int s;
140 struct buf *bp;
141
142 s = splbio();
360d7067 143 while (bswlist.b_actf == NULL) {
c5648f55
KB
144 bswlist.b_flags |= B_WANTED;
145 sleep((caddr_t)&bswlist, prio);
146 }
360d7067
KM
147 bp = bswlist.b_actf;
148 bswlist.b_actf = bp->b_actf;
c5648f55
KB
149 splx(s);
150 return (bp);
151}
152
251f56ba 153static void
c5648f55
KB
154freeswbuf(bp)
155 struct buf *bp;
156{
157 int s;
158
159 s = splbio();
360d7067
KM
160 bp->b_actf = bswlist.b_actf;
161 bswlist.b_actf = bp;
343a57bd
KM
162 if (bp->b_vp)
163 brelvp(bp);
c5648f55
KB
164 if (bswlist.b_flags & B_WANTED) {
165 bswlist.b_flags &= ~B_WANTED;
166 wakeup((caddr_t)&bswlist);
8429d022 167 wakeup((caddr_t)pageproc);
c5648f55
KB
168 }
169 splx(s);
170}
171
d99a6abd
KM
172/*
173 * Do a read on a device for a user process.
174 */
c5648f55
KB
175rawread(dev, uio)
176 dev_t dev;
177 struct uio *uio;
178{
179 return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
180 dev, B_READ, minphys, uio));
181}
182
d99a6abd
KM
183/*
184 * Do a write on a device for a user process.
185 */
c5648f55
KB
186rawwrite(dev, uio)
187 dev_t dev;
188 struct uio *uio;
189{
190 return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
191 dev, B_WRITE, minphys, uio));
192}