add POSIX-style byte-level record locking
[unix-history] / usr / src / sys / kern / kern_physio.c
CommitLineData
da7c5cc6 1/*
cef7aa7d
KM
2 * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
3 * All rights reserved.
da7c5cc6 4 *
cef7aa7d
KM
5 * %sccs.include.redist.c%
6 *
7 * @(#)kern_physio.c 7.16 (Berkeley) %G%
da7c5cc6 8 */
961945a8 9
94368568
JB
10#include "param.h"
11#include "systm.h"
94368568
JB
12#include "user.h"
13#include "buf.h"
14#include "conf.h"
15#include "proc.h"
16#include "seg.h"
94368568
JB
17#include "trace.h"
18#include "map.h"
c4ec2128 19#include "vnode.h"
0f93ba7b 20#include "specdev.h"
d301d150 21
663dbc72
BJ
22/*
23 * Raw I/O. The arguments are
24 * The strategy routine for the device
c5648f55
KB
25 * A buffer, which will either be a special buffer header owned
26 * exclusively by the device for this purpose, or NULL,
27 * indicating that we should use a swap buffer
663dbc72
BJ
28 * The device number
29 * Read/write flag
30 * Essentially all the work is computing physical addresses and
31 * validating them.
32 * If the user has the proper access privilidges, the process is
33 * marked 'delayed unlock' and the pages involved in the I/O are
34 * faulted and locked. After the completion of the I/O, the above pages
35 * are unlocked.
36 */
d6d7360b
BJ
37physio(strat, bp, dev, rw, mincnt, uio)
38 int (*strat)();
39 register struct buf *bp;
40 dev_t dev;
41 int rw;
c5648f55 42 u_int (*mincnt)();
d6d7360b 43 struct uio *uio;
663dbc72 44{
a196746e 45 register struct iovec *iov;
58c3cad7 46 register int requested, done;
663dbc72 47 char *a;
c5648f55
KB
48 int s, allocbuf = 0, error = 0;
49 struct buf *getswbuf();
ec67a3ce
MK
50#ifdef SECSIZE
51 int bsize;
52 struct partinfo dpart;
53#endif SECSIZE
663dbc72 54
ec67a3ce
MK
55#ifdef SECSIZE
56 if ((unsigned)major(dev) < nchrdev &&
57 (*cdevsw[major(dev)].d_ioctl)(dev, DIOCGPART, (caddr_t)&dpart,
58 FREAD) == 0)
59 bsize = dpart.disklab->d_secsize;
60 else
61 bsize = DEV_BSIZE;
62#endif SECSIZE
63 for (;;) {
64 if (uio->uio_iovcnt == 0)
65 return (0);
66 iov = uio->uio_iov;
67 if (useracc(iov->iov_base, (u_int)iov->iov_len,
68 rw==B_READ? B_WRITE : B_READ) == NULL)
69 return (EFAULT);
70 s = splbio();
71 while (bp->b_flags&B_BUSY) {
72 bp->b_flags |= B_WANTED;
73 sleep((caddr_t)bp, PRIBIO+1);
74 }
c5648f55
KB
75 if (!allocbuf) { /* only if sharing caller's buffer */
76 s = splbio();
77 while (bp->b_flags&B_BUSY) {
78 bp->b_flags |= B_WANTED;
79 sleep((caddr_t)bp, PRIBIO+1);
80 }
81 splx(s);
82 }
ec67a3ce
MK
83 bp->b_error = 0;
84 bp->b_proc = u.u_procp;
85#ifdef SECSIZE
86 bp->b_blksize = bsize;
87#endif SECSIZE
88 bp->b_un.b_addr = iov->iov_base;
89 while (iov->iov_len > 0) {
90 bp->b_flags = B_BUSY | B_PHYS | rw;
91 bp->b_dev = dev;
92#ifdef SECSIZE
93 bp->b_blkno = uio->uio_offset / bsize;
94#else SECSIZE
95 bp->b_blkno = btodb(uio->uio_offset);
96#endif SECSIZE
97 bp->b_bcount = iov->iov_len;
98 (*mincnt)(bp);
99 c = bp->b_bcount;
100 u.u_procp->p_flag |= SPHYSIO;
101 vslock(a = bp->b_un.b_addr, c);
102 physstrat(bp, strat, PRIBIO);
103 (void) splbio();
104 vsunlock(a, c, rw);
105 u.u_procp->p_flag &= ~SPHYSIO;
106 if (bp->b_flags&B_WANTED)
107 wakeup((caddr_t)bp);
108 splx(s);
109 c -= bp->b_resid;
110 bp->b_un.b_addr += c;
111 iov->iov_len -= c;
112 uio->uio_resid -= c;
113 uio->uio_offset += c;
114 /* temp kludge for tape drives */
115 if (bp->b_resid || (bp->b_flags&B_ERROR))
116 break;
117 }
118 bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS);
119 error = geterror(bp);
ec67a3ce
MK
120 if (bp->b_resid || error)
121 return (error);
122 uio->uio_iov++;
123 uio->uio_iovcnt--;
663dbc72 124 }
cd682858
KM
125#if defined(hp300)
126 DCIU();
127#endif
c5648f55
KB
128 if (allocbuf)
129 freeswbuf(bp);
130 return (error);
663dbc72
BJ
131}
132
c5648f55 133u_int
663dbc72 134minphys(bp)
d6d7360b 135 struct buf *bp;
663dbc72 136{
35a494b8
SL
137 if (bp->b_bcount > MAXPHYS)
138 bp->b_bcount = MAXPHYS;
663dbc72 139}
c5648f55
KB
140
141static
142struct buf *
143getswbuf(prio)
144 int prio;
145{
146 int s;
147 struct buf *bp;
148
149 s = splbio();
150 while (bswlist.av_forw == NULL) {
151 bswlist.b_flags |= B_WANTED;
152 sleep((caddr_t)&bswlist, prio);
153 }
154 bp = bswlist.av_forw;
155 bswlist.av_forw = bp->av_forw;
156 splx(s);
157 return (bp);
158}
159
160static
161freeswbuf(bp)
162 struct buf *bp;
163{
164 int s;
165
166 s = splbio();
167 bp->av_forw = bswlist.av_forw;
168 bswlist.av_forw = bp;
343a57bd
KM
169 if (bp->b_vp)
170 brelvp(bp);
c5648f55
KB
171 if (bswlist.b_flags & B_WANTED) {
172 bswlist.b_flags &= ~B_WANTED;
173 wakeup((caddr_t)&bswlist);
174 wakeup((caddr_t)&proc[2]);
175 }
176 splx(s);
177}
178
179rawread(dev, uio)
180 dev_t dev;
181 struct uio *uio;
182{
183 return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
184 dev, B_READ, minphys, uio));
185}
186
187rawwrite(dev, uio)
188 dev_t dev;
189 struct uio *uio;
190{
191 return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
192 dev, B_WRITE, minphys, uio));
193}