since it replaces cu, put it in usr/bin
[unix-history] / usr / src / sys / kern / kern_physio.c
CommitLineData
ca1f746a 1/* kern_physio.c 4.36 82/11/02 */
663dbc72
BJ
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/dir.h"
6#include "../h/user.h"
7#include "../h/buf.h"
8#include "../h/conf.h"
9#include "../h/proc.h"
10#include "../h/seg.h"
11#include "../h/pte.h"
12#include "../h/vm.h"
973ecc4f 13#include "../h/trace.h"
d6d7360b 14#include "../h/uio.h"
663dbc72 15
663dbc72
BJ
16/*
17 * Swap IO headers -
18 * They contain the necessary information for the swap I/O.
19 * At any given time, a swap header can be in three
20 * different lists. When free it is in the free list,
21 * when allocated and the I/O queued, it is on the swap
22 * device list, and finally, if the operation was a dirty
23 * page push, when the I/O completes, it is inserted
24 * in a list of cleaned pages to be processed by the pageout daemon.
25 */
4c05b581
BJ
26struct buf *swbuf;
27short *swsize; /* CAN WE JUST USE B_BCOUNT? */
28int *swpf;
663dbc72 29
663dbc72
BJ
30/*
31 * swap I/O -
32 *
33 * If the flag indicates a dirty page push initiated
34 * by the pageout daemon, we map the page into the i th
35 * virtual page of process 2 (the daemon itself) where i is
36 * the index of the swap header that has been allocated.
37 * We simply initialize the header and queue the I/O but
38 * do not wait for completion. When the I/O completes,
39 * iodone() will link the header to a list of cleaned
40 * pages to be processed by the pageout daemon.
41 */
42swap(p, dblkno, addr, nbytes, rdflg, flag, dev, pfcent)
43 struct proc *p;
44 swblk_t dblkno;
45 caddr_t addr;
39d536e6 46 int nbytes, rdflg, flag;
663dbc72 47 dev_t dev;
39d536e6 48 u_int pfcent;
663dbc72
BJ
49{
50 register struct buf *bp;
e438ed8e 51 register u_int c;
663dbc72
BJ
52 int p2dp;
53 register struct pte *dpte, *vpte;
530d0032 54 int s;
663dbc72 55
530d0032 56 s = spl6();
663dbc72
BJ
57 while (bswlist.av_forw == NULL) {
58 bswlist.b_flags |= B_WANTED;
59 sleep((caddr_t)&bswlist, PSWP+1);
60 }
61 bp = bswlist.av_forw;
62 bswlist.av_forw = bp->av_forw;
530d0032 63 splx(s);
663dbc72
BJ
64
65 bp->b_flags = B_BUSY | B_PHYS | rdflg | flag;
66 if ((bp->b_flags & (B_DIRTY|B_PGIN)) == 0)
67 if (rdflg == B_READ)
68 sum.v_pswpin += btoc(nbytes);
69 else
70 sum.v_pswpout += btoc(nbytes);
71 bp->b_proc = p;
72 if (flag & B_DIRTY) {
73 p2dp = ((bp - swbuf) * CLSIZE) * KLMAX;
74 dpte = dptopte(&proc[2], p2dp);
75 vpte = vtopte(p, btop(addr));
76 for (c = 0; c < nbytes; c += NBPG) {
77 if (vpte->pg_pfnum == 0 || vpte->pg_fod)
78 panic("swap bad pte");
79 *dpte++ = *vpte++;
80 }
81 bp->b_un.b_addr = (caddr_t)ctob(p2dp);
82 } else
83 bp->b_un.b_addr = addr;
84 while (nbytes > 0) {
e438ed8e
BJ
85 bp->b_bcount = nbytes;
86 minphys(bp);
87 c = bp->b_bcount;
663dbc72
BJ
88 bp->b_blkno = dblkno;
89 bp->b_dev = dev;
d2f87136
BJ
90 if (flag & B_DIRTY) {
91 swpf[bp - swbuf] = pfcent;
92 swsize[bp - swbuf] = nbytes;
93 }
53f9ca20
BJ
94#ifdef TRACE
95 trace(TR_SWAPIO, dev, bp->b_blkno);
96#endif
ca1f746a 97 physstrat(bp, bdevsw[major(dev)].d_strategy, PSWP);
663dbc72
BJ
98 if (flag & B_DIRTY) {
99 if (c < nbytes)
100 panic("big push");
663dbc72
BJ
101 return;
102 }
663dbc72
BJ
103 bp->b_un.b_addr += c;
104 bp->b_flags &= ~B_DONE;
105 if (bp->b_flags & B_ERROR) {
106 if ((flag & (B_UAREA|B_PAGET)) || rdflg == B_WRITE)
107 panic("hard IO err in swap");
108 swkill(p, (char *)0);
109 }
110 nbytes -= c;
e438ed8e 111 dblkno += c / DEV_BSIZE;
663dbc72 112 }
530d0032 113 s = spl6();
663dbc72
BJ
114 bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
115 bp->av_forw = bswlist.av_forw;
116 bswlist.av_forw = bp;
117 if (bswlist.b_flags & B_WANTED) {
118 bswlist.b_flags &= ~B_WANTED;
119 wakeup((caddr_t)&bswlist);
120 wakeup((caddr_t)&proc[2]);
121 }
530d0032 122 splx(s);
663dbc72
BJ
123}
124
125/*
126 * If rout == 0 then killed on swap error, else
127 * rout is the name of the routine where we ran out of
128 * swap space.
129 */
130swkill(p, rout)
131 struct proc *p;
132 char *rout;
133{
444f631c 134 char *mesg;
663dbc72 135
444f631c 136 printf("pid %d: ", p->p_pid);
663dbc72 137 if (rout)
444f631c 138 printf(mesg = "killed due to no swap space\n");
663dbc72 139 else
444f631c
BJ
140 printf(mesg = "killed on swap error\n");
141 uprintf("sorry, pid %d was %s", p->p_pid, mesg);
663dbc72
BJ
142 /*
143 * To be sure no looping (e.g. in vmsched trying to
144 * swap out) mark process locked in core (as though
145 * done by user) after killing it so noone will try
146 * to swap it out.
147 */
a30d2e97 148 psignal(p, SIGKILL);
663dbc72
BJ
149 p->p_flag |= SULOCK;
150}
151
663dbc72
BJ
152/*
153 * Raw I/O. The arguments are
154 * The strategy routine for the device
155 * A buffer, which will always be a special buffer
156 * header owned exclusively by the device for this purpose
157 * The device number
158 * Read/write flag
159 * Essentially all the work is computing physical addresses and
160 * validating them.
161 * If the user has the proper access privilidges, the process is
162 * marked 'delayed unlock' and the pages involved in the I/O are
163 * faulted and locked. After the completion of the I/O, the above pages
164 * are unlocked.
165 */
d6d7360b
BJ
166physio(strat, bp, dev, rw, mincnt, uio)
167 int (*strat)();
168 register struct buf *bp;
169 dev_t dev;
170 int rw;
171 unsigned (*mincnt)();
172 struct uio *uio;
663dbc72 173{
406ddcbe 174 register struct iovec *iov = uio->uio_iov;
663dbc72
BJ
175 register int c;
176 char *a;
d6d7360b 177 int s, error = 0;
663dbc72 178
d6d7360b 179nextiov:
406ddcbe 180 if (uio->uio_iovcnt == 0)
d6d7360b 181 return (0);
406ddcbe 182 if (useracc(iov->iov_base,(u_int)iov->iov_len,rw==B_READ?B_WRITE:B_READ) == NULL)
d6d7360b 183 return (EFAULT);
530d0032 184 s = spl6();
663dbc72
BJ
185 while (bp->b_flags&B_BUSY) {
186 bp->b_flags |= B_WANTED;
187 sleep((caddr_t)bp, PRIBIO+1);
188 }
ef3b3d5a 189 splx(s);
663dbc72
BJ
190 bp->b_error = 0;
191 bp->b_proc = u.u_procp;
d6d7360b
BJ
192 bp->b_un.b_addr = iov->iov_base;
193 while (iov->iov_len > 0) {
663dbc72
BJ
194 bp->b_flags = B_BUSY | B_PHYS | rw;
195 bp->b_dev = dev;
e438ed8e 196 bp->b_blkno = uio->uio_offset / DEV_BSIZE;
d6d7360b 197 bp->b_bcount = iov->iov_len;
663dbc72
BJ
198 (*mincnt)(bp);
199 c = bp->b_bcount;
200 u.u_procp->p_flag |= SPHYSIO;
201 vslock(a = bp->b_un.b_addr, c);
e438ed8e 202 physstrat(bp, strat, PRIBIO);
81263dba 203 (void) spl6();
663dbc72
BJ
204 vsunlock(a, c, rw);
205 u.u_procp->p_flag &= ~SPHYSIO;
206 if (bp->b_flags&B_WANTED)
207 wakeup((caddr_t)bp);
530d0032 208 splx(s);
d6d7360b 209 c -= bp->b_resid;
663dbc72 210 bp->b_un.b_addr += c;
d6d7360b
BJ
211 iov->iov_len -= c;
212 uio->uio_resid -= c;
213 uio->uio_offset += c;
52a593fa
BJ
214 if (bp->b_flags&B_ERROR)
215 break;
663dbc72
BJ
216 }
217 bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS);
d6d7360b 218 error = geterror(bp);
406ddcbe 219 if (error)
d6d7360b 220 return (error);
d6d7360b
BJ
221 uio->uio_iov++;
222 uio->uio_iovcnt--;
223 goto nextiov;
663dbc72
BJ
224}
225
663dbc72
BJ
226unsigned
227minphys(bp)
d6d7360b 228 struct buf *bp;
663dbc72
BJ
229{
230
2ec65c94
BJ
231 if (bp->b_bcount > 63 * 1024)
232 bp->b_bcount = 63 * 1024;
663dbc72
BJ
233}
234