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