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