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