Blame


1 a0d146ed 2005-07-12 devnull /*
2 a0d146ed 2005-07-12 devnull * Disk cache.
3 fa325e9b 2020-01-10 cross *
4 a0d146ed 2005-07-12 devnull * Caches raw disk blocks. Getdblock() gets a block, putdblock puts it back.
5 a0d146ed 2005-07-12 devnull * Getdblock has a mode parameter that determines i/o and access to a block:
6 a0d146ed 2005-07-12 devnull * if mode is OREAD or ORDWR, it is read from disk if not already in memory.
7 a0d146ed 2005-07-12 devnull * If mode is ORDWR or OWRITE, it is locked for exclusive use before being returned.
8 a0d146ed 2005-07-12 devnull * It is *not* marked dirty -- once changes have been made, they should be noted
9 fa325e9b 2020-01-10 cross * by using dirtydblock() before putdblock().
10 a0d146ed 2005-07-12 devnull *
11 fa325e9b 2020-01-10 cross * There is a global cache lock as well as a lock on each block.
12 a0d146ed 2005-07-12 devnull * Within a thread, the cache lock can be acquired while holding a block lock,
13 a0d146ed 2005-07-12 devnull * but not vice versa; and a block cannot be locked if you already hold the lock
14 a0d146ed 2005-07-12 devnull * on another block.
15 fa325e9b 2020-01-10 cross *
16 a0d146ed 2005-07-12 devnull * The flush proc writes out dirty blocks in batches, one batch per dirty tag.
17 a0d146ed 2005-07-12 devnull * For example, the DirtyArena blocks are all written to disk before any of the
18 a0d146ed 2005-07-12 devnull * DirtyArenaCib blocks.
19 a0d146ed 2005-07-12 devnull *
20 fa325e9b 2020-01-10 cross * This code used to be in charge of flushing the dirty index blocks out to
21 a0d146ed 2005-07-12 devnull * disk, but updating the index turned out to benefit from extra care.
22 a0d146ed 2005-07-12 devnull * Now cached index blocks are never marked dirty. The index.c code takes
23 a0d146ed 2005-07-12 devnull * care of updating them behind our back, and uses _getdblock to update any
24 a0d146ed 2005-07-12 devnull * cached copies of the blocks as it changes them on disk.
25 a0d146ed 2005-07-12 devnull */
26 a0d146ed 2005-07-12 devnull
27 a0d146ed 2005-07-12 devnull #include "stdinc.h"
28 a0d146ed 2005-07-12 devnull #include "dat.h"
29 a0d146ed 2005-07-12 devnull #include "fns.h"
30 a0d146ed 2005-07-12 devnull
31 a0d146ed 2005-07-12 devnull typedef struct DCache DCache;
32 a0d146ed 2005-07-12 devnull
33 a0d146ed 2005-07-12 devnull enum
34 a0d146ed 2005-07-12 devnull {
35 a0d146ed 2005-07-12 devnull HashLog = 9,
36 a0d146ed 2005-07-12 devnull HashSize = 1<<HashLog,
37 28b49df3 2006-07-18 devnull HashMask = HashSize - 1,
38 a0d146ed 2005-07-12 devnull };
39 a0d146ed 2005-07-12 devnull
40 a0d146ed 2005-07-12 devnull struct DCache
41 a0d146ed 2005-07-12 devnull {
42 a0d146ed 2005-07-12 devnull QLock lock;
43 a0d146ed 2005-07-12 devnull RWLock dirtylock; /* must be held to inspect or set b->dirty */
44 a0d146ed 2005-07-12 devnull Rendez full;
45 a0d146ed 2005-07-12 devnull Round round;
46 a0d146ed 2005-07-12 devnull DBlock *free; /* list of available lumps */
47 a0d146ed 2005-07-12 devnull u32int now; /* ticks for usage timestamps */
48 a0d146ed 2005-07-12 devnull int size; /* max. size of any block; allocated to each block */
49 a0d146ed 2005-07-12 devnull DBlock **heads; /* hash table for finding address */
50 a0d146ed 2005-07-12 devnull int nheap; /* number of available victims */
51 a0d146ed 2005-07-12 devnull DBlock **heap; /* heap for locating victims */
52 a0d146ed 2005-07-12 devnull int nblocks; /* number of blocks allocated */
53 a0d146ed 2005-07-12 devnull DBlock *blocks; /* array of block descriptors */
54 a0d146ed 2005-07-12 devnull DBlock **write; /* array of block pointers to be written */
55 a0d146ed 2005-07-12 devnull u8int *mem; /* memory for all block descriptors */
56 a0d146ed 2005-07-12 devnull int ndirty; /* number of dirty blocks */
57 a0d146ed 2005-07-12 devnull int maxdirty; /* max. number of dirty blocks */
58 a0d146ed 2005-07-12 devnull };
59 a0d146ed 2005-07-12 devnull
60 a0d146ed 2005-07-12 devnull typedef struct Ra Ra;
61 a0d146ed 2005-07-12 devnull struct Ra
62 a0d146ed 2005-07-12 devnull {
63 a0d146ed 2005-07-12 devnull Part *part;
64 a0d146ed 2005-07-12 devnull u64int addr;
65 a0d146ed 2005-07-12 devnull };
66 a0d146ed 2005-07-12 devnull
67 a0d146ed 2005-07-12 devnull static DCache dcache;
68 a0d146ed 2005-07-12 devnull
69 a0d146ed 2005-07-12 devnull static int downheap(int i, DBlock *b);
70 a0d146ed 2005-07-12 devnull static int upheap(int i, DBlock *b);
71 a0d146ed 2005-07-12 devnull static DBlock *bumpdblock(void);
72 a0d146ed 2005-07-12 devnull static void delheap(DBlock *db);
73 a0d146ed 2005-07-12 devnull static void fixheap(int i, DBlock *b);
74 a0d146ed 2005-07-12 devnull static void flushproc(void*);
75 a0d146ed 2005-07-12 devnull static void writeproc(void*);
76 a0d146ed 2005-07-12 devnull
77 a0d146ed 2005-07-12 devnull void
78 a0d146ed 2005-07-12 devnull initdcache(u32int mem)
79 a0d146ed 2005-07-12 devnull {
80 a0d146ed 2005-07-12 devnull DBlock *b, *last;
81 a0d146ed 2005-07-12 devnull u32int nblocks, blocksize;
82 a0d146ed 2005-07-12 devnull int i;
83 a0d146ed 2005-07-12 devnull u8int *p;
84 a0d146ed 2005-07-12 devnull
85 a0d146ed 2005-07-12 devnull if(mem < maxblocksize * 2)
86 a0d146ed 2005-07-12 devnull sysfatal("need at least %d bytes for the disk cache", maxblocksize * 2);
87 a0d146ed 2005-07-12 devnull if(maxblocksize == 0)
88 a0d146ed 2005-07-12 devnull sysfatal("no max. block size given for disk cache");
89 a0d146ed 2005-07-12 devnull blocksize = maxblocksize;
90 a0d146ed 2005-07-12 devnull nblocks = mem / blocksize;
91 a0d146ed 2005-07-12 devnull dcache.full.l = &dcache.lock;
92 a0d146ed 2005-07-12 devnull dcache.nblocks = nblocks;
93 a0d146ed 2005-07-12 devnull dcache.maxdirty = (nblocks * 2) / 3;
94 a0d146ed 2005-07-12 devnull trace(TraceProc, "initialize disk cache with %d blocks of %d bytes, maximum %d dirty blocks\n",
95 a0d146ed 2005-07-12 devnull nblocks, blocksize, dcache.maxdirty);
96 a0d146ed 2005-07-12 devnull dcache.size = blocksize;
97 a0d146ed 2005-07-12 devnull dcache.heads = MKNZ(DBlock*, HashSize);
98 a0d146ed 2005-07-12 devnull dcache.heap = MKNZ(DBlock*, nblocks);
99 a0d146ed 2005-07-12 devnull dcache.blocks = MKNZ(DBlock, nblocks);
100 a0d146ed 2005-07-12 devnull dcache.write = MKNZ(DBlock*, nblocks);
101 a0d146ed 2005-07-12 devnull dcache.mem = MKNZ(u8int, (nblocks+1+128) * blocksize);
102 a0d146ed 2005-07-12 devnull
103 a0d146ed 2005-07-12 devnull last = nil;
104 54dd92be 2008-01-30 rsc p = (u8int*)(((uintptr)dcache.mem+blocksize-1)&~(uintptr)(blocksize-1));
105 a0d146ed 2005-07-12 devnull for(i = 0; i < nblocks; i++){
106 a0d146ed 2005-07-12 devnull b = &dcache.blocks[i];
107 a0d146ed 2005-07-12 devnull b->data = &p[i * blocksize];
108 a0d146ed 2005-07-12 devnull b->heap = TWID32;
109 a0d146ed 2005-07-12 devnull b->writedonechan = chancreate(sizeof(void*), 1);
110 a0d146ed 2005-07-12 devnull b->next = last;
111 a0d146ed 2005-07-12 devnull last = b;
112 a0d146ed 2005-07-12 devnull }
113 a0d146ed 2005-07-12 devnull
114 a0d146ed 2005-07-12 devnull dcache.free = last;
115 a0d146ed 2005-07-12 devnull dcache.nheap = 0;
116 a0d146ed 2005-07-12 devnull setstat(StatDcacheSize, nblocks);
117 a0d146ed 2005-07-12 devnull initround(&dcache.round, "dcache", 120*1000);
118 a0d146ed 2005-07-12 devnull
119 a0d146ed 2005-07-12 devnull vtproc(flushproc, nil);
120 a0d146ed 2005-07-12 devnull vtproc(delaykickroundproc, &dcache.round);
121 a0d146ed 2005-07-12 devnull }
122 a0d146ed 2005-07-12 devnull
123 a0d146ed 2005-07-12 devnull static u32int
124 a0d146ed 2005-07-12 devnull pbhash(u64int addr)
125 a0d146ed 2005-07-12 devnull {
126 a0d146ed 2005-07-12 devnull u32int h;
127 a0d146ed 2005-07-12 devnull
128 a0d146ed 2005-07-12 devnull #define hashit(c) ((((c) * 0x6b43a9b5) >> (32 - HashLog)) & HashMask)
129 a0d146ed 2005-07-12 devnull h = (addr >> 32) ^ addr;
130 a0d146ed 2005-07-12 devnull return hashit(h);
131 a0d146ed 2005-07-12 devnull }
132 a0d146ed 2005-07-12 devnull
133 a0d146ed 2005-07-12 devnull DBlock*
134 a0d146ed 2005-07-12 devnull getdblock(Part *part, u64int addr, int mode)
135 a0d146ed 2005-07-12 devnull {
136 a0d146ed 2005-07-12 devnull DBlock *b;
137 fa325e9b 2020-01-10 cross
138 a0d146ed 2005-07-12 devnull b = _getdblock(part, addr, mode, 1);
139 a0d146ed 2005-07-12 devnull if(mode == OREAD || mode == ORDWR)
140 a0d146ed 2005-07-12 devnull addstat(StatDcacheRead, 1);
141 a0d146ed 2005-07-12 devnull if(mode == OWRITE || mode == ORDWR)
142 a0d146ed 2005-07-12 devnull addstat(StatDcacheWrite, 1);
143 a0d146ed 2005-07-12 devnull return b;
144 a0d146ed 2005-07-12 devnull }
145 a0d146ed 2005-07-12 devnull
146 a0d146ed 2005-07-12 devnull DBlock*
147 a0d146ed 2005-07-12 devnull _getdblock(Part *part, u64int addr, int mode, int load)
148 a0d146ed 2005-07-12 devnull {
149 a0d146ed 2005-07-12 devnull DBlock *b;
150 54dd92be 2008-01-30 rsc u32int h, size, ms;
151 a0d146ed 2005-07-12 devnull
152 54dd92be 2008-01-30 rsc ms = 0;
153 a0d146ed 2005-07-12 devnull trace(TraceBlock, "getdblock enter %s 0x%llux", part->name, addr);
154 a0d146ed 2005-07-12 devnull size = part->blocksize;
155 a0d146ed 2005-07-12 devnull if(size > dcache.size){
156 a0d146ed 2005-07-12 devnull seterr(EAdmin, "block size %d too big for cache with size %d", size, dcache.size);
157 54dd92be 2008-01-30 rsc if(load)
158 54dd92be 2008-01-30 rsc addstat(StatDcacheLookup, 1);
159 a0d146ed 2005-07-12 devnull return nil;
160 a0d146ed 2005-07-12 devnull }
161 a0d146ed 2005-07-12 devnull h = pbhash(addr);
162 a0d146ed 2005-07-12 devnull
163 a0d146ed 2005-07-12 devnull /*
164 a0d146ed 2005-07-12 devnull * look for the block in the cache
165 a0d146ed 2005-07-12 devnull */
166 a0d146ed 2005-07-12 devnull qlock(&dcache.lock);
167 a0d146ed 2005-07-12 devnull again:
168 a0d146ed 2005-07-12 devnull for(b = dcache.heads[h]; b != nil; b = b->next){
169 a0d146ed 2005-07-12 devnull if(b->part == part && b->addr == addr){
170 12c0e45f 2007-09-25 rsc if(load)
171 54dd92be 2008-01-30 rsc addstat2(StatDcacheHit, 1, StatDcacheLookup, 1);
172 a0d146ed 2005-07-12 devnull goto found;
173 a0d146ed 2005-07-12 devnull }
174 a0d146ed 2005-07-12 devnull }
175 a0d146ed 2005-07-12 devnull
176 a0d146ed 2005-07-12 devnull /*
177 a0d146ed 2005-07-12 devnull * missed: locate the block with the oldest second to last use.
178 a0d146ed 2005-07-12 devnull * remove it from the heap, and fix up the heap.
179 a0d146ed 2005-07-12 devnull */
180 a0d146ed 2005-07-12 devnull if(!load){
181 a0d146ed 2005-07-12 devnull qunlock(&dcache.lock);
182 a0d146ed 2005-07-12 devnull return nil;
183 a0d146ed 2005-07-12 devnull }
184 a0d146ed 2005-07-12 devnull
185 54dd92be 2008-01-30 rsc /*
186 54dd92be 2008-01-30 rsc * Only start timer here, on cache miss - calling msec() on plain cache hits
187 54dd92be 2008-01-30 rsc * makes cache hits system-call bound.
188 54dd92be 2008-01-30 rsc */
189 54dd92be 2008-01-30 rsc ms = msec();
190 54dd92be 2008-01-30 rsc addstat2(StatDcacheLookup, 1, StatDcacheMiss, 1);
191 a0d146ed 2005-07-12 devnull
192 a0d146ed 2005-07-12 devnull b = bumpdblock();
193 a0d146ed 2005-07-12 devnull if(b == nil){
194 a0d146ed 2005-07-12 devnull trace(TraceBlock, "all disk cache blocks in use");
195 a0d146ed 2005-07-12 devnull addstat(StatDcacheStall, 1);
196 a0d146ed 2005-07-12 devnull rsleep(&dcache.full);
197 a0d146ed 2005-07-12 devnull addstat(StatDcacheStall, -1);
198 a0d146ed 2005-07-12 devnull goto again;
199 a0d146ed 2005-07-12 devnull }
200 a0d146ed 2005-07-12 devnull
201 a0d146ed 2005-07-12 devnull assert(!b->dirty);
202 a0d146ed 2005-07-12 devnull
203 a0d146ed 2005-07-12 devnull /*
204 a0d146ed 2005-07-12 devnull * the new block has no last use, so assume it happens sometime in the middle
205 a0d146ed 2005-07-12 devnull ZZZ this is not reasonable
206 a0d146ed 2005-07-12 devnull */
207 a0d146ed 2005-07-12 devnull b->used = (b->used2 + dcache.now) / 2;
208 a0d146ed 2005-07-12 devnull
209 a0d146ed 2005-07-12 devnull /*
210 a0d146ed 2005-07-12 devnull * rechain the block on the correct hash chain
211 a0d146ed 2005-07-12 devnull */
212 a0d146ed 2005-07-12 devnull b->next = dcache.heads[h];
213 a0d146ed 2005-07-12 devnull dcache.heads[h] = b;
214 a0d146ed 2005-07-12 devnull if(b->next != nil)
215 a0d146ed 2005-07-12 devnull b->next->prev = b;
216 a0d146ed 2005-07-12 devnull b->prev = nil;
217 a0d146ed 2005-07-12 devnull
218 a0d146ed 2005-07-12 devnull b->addr = addr;
219 a0d146ed 2005-07-12 devnull b->part = part;
220 a0d146ed 2005-07-12 devnull b->size = 0;
221 a0d146ed 2005-07-12 devnull
222 a0d146ed 2005-07-12 devnull found:
223 a0d146ed 2005-07-12 devnull b->ref++;
224 a0d146ed 2005-07-12 devnull b->used2 = b->used;
225 a0d146ed 2005-07-12 devnull b->used = dcache.now++;
226 a0d146ed 2005-07-12 devnull if(b->heap != TWID32)
227 a0d146ed 2005-07-12 devnull fixheap(b->heap, b);
228 a0d146ed 2005-07-12 devnull
229 12c0e45f 2007-09-25 rsc if((mode == ORDWR || mode == OWRITE) && part->writechan == nil){
230 12c0e45f 2007-09-25 rsc trace(TraceBlock, "getdblock allocwriteproc %s", part->name);
231 12c0e45f 2007-09-25 rsc part->writechan = chancreate(sizeof(DBlock*), dcache.nblocks);
232 12c0e45f 2007-09-25 rsc vtproc(writeproc, part);
233 12c0e45f 2007-09-25 rsc }
234 a0d146ed 2005-07-12 devnull qunlock(&dcache.lock);
235 a0d146ed 2005-07-12 devnull
236 a0d146ed 2005-07-12 devnull trace(TraceBlock, "getdblock lock");
237 a0d146ed 2005-07-12 devnull addstat(StatDblockStall, 1);
238 a0d146ed 2005-07-12 devnull if(mode == OREAD)
239 a0d146ed 2005-07-12 devnull rlock(&b->lock);
240 a0d146ed 2005-07-12 devnull else
241 a0d146ed 2005-07-12 devnull wlock(&b->lock);
242 a0d146ed 2005-07-12 devnull addstat(StatDblockStall, -1);
243 a0d146ed 2005-07-12 devnull trace(TraceBlock, "getdblock locked");
244 a0d146ed 2005-07-12 devnull
245 a0d146ed 2005-07-12 devnull if(b->size != size){
246 a0d146ed 2005-07-12 devnull if(mode == OREAD){
247 a0d146ed 2005-07-12 devnull addstat(StatDblockStall, 1);
248 a0d146ed 2005-07-12 devnull runlock(&b->lock);
249 a0d146ed 2005-07-12 devnull wlock(&b->lock);
250 a0d146ed 2005-07-12 devnull addstat(StatDblockStall, -1);
251 a0d146ed 2005-07-12 devnull }
252 a0d146ed 2005-07-12 devnull if(b->size < size){
253 a0d146ed 2005-07-12 devnull if(mode == OWRITE)
254 a0d146ed 2005-07-12 devnull memset(&b->data[b->size], 0, size - b->size);
255 a0d146ed 2005-07-12 devnull else{
256 a0d146ed 2005-07-12 devnull trace(TraceBlock, "getdblock readpart %s 0x%llux", part->name, addr);
257 12c0e45f 2007-09-25 rsc diskaccess(0);
258 12c0e45f 2007-09-25 rsc if(readpart(part, addr + b->size, &b->data[b->size], size - b->size) < 0){
259 a0d146ed 2005-07-12 devnull b->mode = ORDWR; /* so putdblock wunlocks */
260 a0d146ed 2005-07-12 devnull putdblock(b);
261 a0d146ed 2005-07-12 devnull return nil;
262 a0d146ed 2005-07-12 devnull }
263 a0d146ed 2005-07-12 devnull trace(TraceBlock, "getdblock readpartdone");
264 a0d146ed 2005-07-12 devnull addstat(StatApartRead, 1);
265 a0d146ed 2005-07-12 devnull addstat(StatApartReadBytes, size-b->size);
266 a0d146ed 2005-07-12 devnull }
267 a0d146ed 2005-07-12 devnull }
268 a0d146ed 2005-07-12 devnull b->size = size;
269 a0d146ed 2005-07-12 devnull if(mode == OREAD){
270 a0d146ed 2005-07-12 devnull addstat(StatDblockStall, 1);
271 a0d146ed 2005-07-12 devnull wunlock(&b->lock);
272 a0d146ed 2005-07-12 devnull rlock(&b->lock);
273 a0d146ed 2005-07-12 devnull addstat(StatDblockStall, -1);
274 a0d146ed 2005-07-12 devnull }
275 a0d146ed 2005-07-12 devnull }
276 a0d146ed 2005-07-12 devnull
277 a0d146ed 2005-07-12 devnull b->mode = mode;
278 a0d146ed 2005-07-12 devnull trace(TraceBlock, "getdblock exit");
279 54dd92be 2008-01-30 rsc if(ms)
280 54dd92be 2008-01-30 rsc addstat(StatDcacheLookupTime, msec() - ms);
281 a0d146ed 2005-07-12 devnull return b;
282 a0d146ed 2005-07-12 devnull }
283 a0d146ed 2005-07-12 devnull
284 a0d146ed 2005-07-12 devnull void
285 a0d146ed 2005-07-12 devnull putdblock(DBlock *b)
286 a0d146ed 2005-07-12 devnull {
287 a0d146ed 2005-07-12 devnull if(b == nil)
288 a0d146ed 2005-07-12 devnull return;
289 a0d146ed 2005-07-12 devnull
290 a0d146ed 2005-07-12 devnull trace(TraceBlock, "putdblock %s 0x%llux", b->part->name, b->addr);
291 a0d146ed 2005-07-12 devnull
292 a0d146ed 2005-07-12 devnull if(b->mode == OREAD)
293 a0d146ed 2005-07-12 devnull runlock(&b->lock);
294 a0d146ed 2005-07-12 devnull else
295 a0d146ed 2005-07-12 devnull wunlock(&b->lock);
296 a0d146ed 2005-07-12 devnull
297 a0d146ed 2005-07-12 devnull qlock(&dcache.lock);
298 a0d146ed 2005-07-12 devnull if(--b->ref == 0 && !b->dirty){
299 a0d146ed 2005-07-12 devnull if(b->heap == TWID32)
300 a0d146ed 2005-07-12 devnull upheap(dcache.nheap++, b);
301 a0d146ed 2005-07-12 devnull rwakeupall(&dcache.full);
302 a0d146ed 2005-07-12 devnull }
303 a0d146ed 2005-07-12 devnull qunlock(&dcache.lock);
304 a0d146ed 2005-07-12 devnull }
305 a0d146ed 2005-07-12 devnull
306 a0d146ed 2005-07-12 devnull void
307 a0d146ed 2005-07-12 devnull dirtydblock(DBlock *b, int dirty)
308 a0d146ed 2005-07-12 devnull {
309 a0d146ed 2005-07-12 devnull int odirty;
310 a0d146ed 2005-07-12 devnull
311 12c0e45f 2007-09-25 rsc trace(TraceBlock, "dirtydblock enter %s 0x%llux %d from 0x%lux",
312 12c0e45f 2007-09-25 rsc b->part->name, b->addr, dirty, getcallerpc(&b));
313 a0d146ed 2005-07-12 devnull assert(b->ref != 0);
314 a0d146ed 2005-07-12 devnull assert(b->mode==ORDWR || b->mode==OWRITE);
315 a0d146ed 2005-07-12 devnull
316 a0d146ed 2005-07-12 devnull odirty = b->dirty;
317 a0d146ed 2005-07-12 devnull if(b->dirty)
318 a0d146ed 2005-07-12 devnull assert(b->dirty == dirty);
319 a0d146ed 2005-07-12 devnull else
320 a0d146ed 2005-07-12 devnull b->dirty = dirty;
321 a0d146ed 2005-07-12 devnull
322 a0d146ed 2005-07-12 devnull qlock(&dcache.lock);
323 a0d146ed 2005-07-12 devnull if(!odirty){
324 a0d146ed 2005-07-12 devnull dcache.ndirty++;
325 a0d146ed 2005-07-12 devnull setstat(StatDcacheDirty, dcache.ndirty);
326 a0d146ed 2005-07-12 devnull if(dcache.ndirty >= dcache.maxdirty)
327 a0d146ed 2005-07-12 devnull kickround(&dcache.round, 0);
328 a0d146ed 2005-07-12 devnull else
329 a0d146ed 2005-07-12 devnull delaykickround(&dcache.round);
330 a0d146ed 2005-07-12 devnull }
331 a0d146ed 2005-07-12 devnull qunlock(&dcache.lock);
332 a0d146ed 2005-07-12 devnull }
333 a0d146ed 2005-07-12 devnull
334 28b49df3 2006-07-18 devnull static void
335 28b49df3 2006-07-18 devnull unchain(DBlock *b)
336 28b49df3 2006-07-18 devnull {
337 28b49df3 2006-07-18 devnull ulong h;
338 fa325e9b 2020-01-10 cross
339 28b49df3 2006-07-18 devnull /*
340 28b49df3 2006-07-18 devnull * unchain the block
341 28b49df3 2006-07-18 devnull */
342 28b49df3 2006-07-18 devnull if(b->prev == nil){
343 28b49df3 2006-07-18 devnull h = pbhash(b->addr);
344 28b49df3 2006-07-18 devnull if(dcache.heads[h] != b)
345 28b49df3 2006-07-18 devnull sysfatal("bad hash chains in disk cache");
346 28b49df3 2006-07-18 devnull dcache.heads[h] = b->next;
347 28b49df3 2006-07-18 devnull }else
348 28b49df3 2006-07-18 devnull b->prev->next = b->next;
349 28b49df3 2006-07-18 devnull if(b->next != nil)
350 28b49df3 2006-07-18 devnull b->next->prev = b->prev;
351 28b49df3 2006-07-18 devnull }
352 28b49df3 2006-07-18 devnull
353 a0d146ed 2005-07-12 devnull /*
354 a0d146ed 2005-07-12 devnull * remove some block from use and update the free list and counters
355 a0d146ed 2005-07-12 devnull */
356 a0d146ed 2005-07-12 devnull static DBlock*
357 a0d146ed 2005-07-12 devnull bumpdblock(void)
358 a0d146ed 2005-07-12 devnull {
359 a0d146ed 2005-07-12 devnull DBlock *b;
360 a0d146ed 2005-07-12 devnull
361 a0d146ed 2005-07-12 devnull trace(TraceBlock, "bumpdblock enter");
362 a0d146ed 2005-07-12 devnull b = dcache.free;
363 a0d146ed 2005-07-12 devnull if(b != nil){
364 a0d146ed 2005-07-12 devnull dcache.free = b->next;
365 a0d146ed 2005-07-12 devnull return b;
366 a0d146ed 2005-07-12 devnull }
367 a0d146ed 2005-07-12 devnull
368 a0d146ed 2005-07-12 devnull if(dcache.ndirty >= dcache.maxdirty)
369 a0d146ed 2005-07-12 devnull kickdcache();
370 a0d146ed 2005-07-12 devnull
371 a0d146ed 2005-07-12 devnull /*
372 a0d146ed 2005-07-12 devnull * remove blocks until we find one that is unused
373 a0d146ed 2005-07-12 devnull * referenced blocks are left in the heap even though
374 a0d146ed 2005-07-12 devnull * they can't be scavenged; this is simple a speed optimization
375 a0d146ed 2005-07-12 devnull */
376 a0d146ed 2005-07-12 devnull for(;;){
377 a0d146ed 2005-07-12 devnull if(dcache.nheap == 0){
378 a0d146ed 2005-07-12 devnull kickdcache();
379 a0d146ed 2005-07-12 devnull trace(TraceBlock, "bumpdblock gotnothing");
380 a0d146ed 2005-07-12 devnull return nil;
381 a0d146ed 2005-07-12 devnull }
382 a0d146ed 2005-07-12 devnull b = dcache.heap[0];
383 a0d146ed 2005-07-12 devnull delheap(b);
384 a0d146ed 2005-07-12 devnull if(!b->ref && !b->dirty)
385 a0d146ed 2005-07-12 devnull break;
386 a0d146ed 2005-07-12 devnull }
387 a0d146ed 2005-07-12 devnull
388 a0d146ed 2005-07-12 devnull trace(TraceBlock, "bumpdblock bumping %s 0x%llux", b->part->name, b->addr);
389 a0d146ed 2005-07-12 devnull
390 28b49df3 2006-07-18 devnull unchain(b);
391 a0d146ed 2005-07-12 devnull return b;
392 28b49df3 2006-07-18 devnull }
393 28b49df3 2006-07-18 devnull
394 28b49df3 2006-07-18 devnull void
395 28b49df3 2006-07-18 devnull emptydcache(void)
396 28b49df3 2006-07-18 devnull {
397 28b49df3 2006-07-18 devnull DBlock *b;
398 fa325e9b 2020-01-10 cross
399 28b49df3 2006-07-18 devnull qlock(&dcache.lock);
400 28b49df3 2006-07-18 devnull while(dcache.nheap > 0){
401 28b49df3 2006-07-18 devnull b = dcache.heap[0];
402 28b49df3 2006-07-18 devnull delheap(b);
403 28b49df3 2006-07-18 devnull if(!b->ref && !b->dirty){
404 28b49df3 2006-07-18 devnull unchain(b);
405 28b49df3 2006-07-18 devnull b->next = dcache.free;
406 28b49df3 2006-07-18 devnull dcache.free = b;
407 28b49df3 2006-07-18 devnull }
408 28b49df3 2006-07-18 devnull }
409 28b49df3 2006-07-18 devnull qunlock(&dcache.lock);
410 a0d146ed 2005-07-12 devnull }
411 a0d146ed 2005-07-12 devnull
412 a0d146ed 2005-07-12 devnull /*
413 a0d146ed 2005-07-12 devnull * delete an arbitrary block from the heap
414 a0d146ed 2005-07-12 devnull */
415 a0d146ed 2005-07-12 devnull static void
416 a0d146ed 2005-07-12 devnull delheap(DBlock *db)
417 a0d146ed 2005-07-12 devnull {
418 a0d146ed 2005-07-12 devnull if(db->heap == TWID32)
419 a0d146ed 2005-07-12 devnull return;
420 a0d146ed 2005-07-12 devnull fixheap(db->heap, dcache.heap[--dcache.nheap]);
421 a0d146ed 2005-07-12 devnull db->heap = TWID32;
422 a0d146ed 2005-07-12 devnull }
423 a0d146ed 2005-07-12 devnull
424 a0d146ed 2005-07-12 devnull /*
425 a0d146ed 2005-07-12 devnull * push an element up or down to it's correct new location
426 a0d146ed 2005-07-12 devnull */
427 a0d146ed 2005-07-12 devnull static void
428 a0d146ed 2005-07-12 devnull fixheap(int i, DBlock *b)
429 a0d146ed 2005-07-12 devnull {
430 a0d146ed 2005-07-12 devnull if(upheap(i, b) == i)
431 a0d146ed 2005-07-12 devnull downheap(i, b);
432 a0d146ed 2005-07-12 devnull }
433 a0d146ed 2005-07-12 devnull
434 a0d146ed 2005-07-12 devnull static int
435 a0d146ed 2005-07-12 devnull upheap(int i, DBlock *b)
436 a0d146ed 2005-07-12 devnull {
437 a0d146ed 2005-07-12 devnull DBlock *bb;
438 a0d146ed 2005-07-12 devnull u32int now;
439 a0d146ed 2005-07-12 devnull int p;
440 a0d146ed 2005-07-12 devnull
441 a0d146ed 2005-07-12 devnull now = dcache.now;
442 a0d146ed 2005-07-12 devnull for(; i != 0; i = p){
443 a0d146ed 2005-07-12 devnull p = (i - 1) >> 1;
444 a0d146ed 2005-07-12 devnull bb = dcache.heap[p];
445 a0d146ed 2005-07-12 devnull if(b->used2 - now >= bb->used2 - now)
446 a0d146ed 2005-07-12 devnull break;
447 a0d146ed 2005-07-12 devnull dcache.heap[i] = bb;
448 a0d146ed 2005-07-12 devnull bb->heap = i;
449 a0d146ed 2005-07-12 devnull }
450 a0d146ed 2005-07-12 devnull
451 a0d146ed 2005-07-12 devnull dcache.heap[i] = b;
452 a0d146ed 2005-07-12 devnull b->heap = i;
453 a0d146ed 2005-07-12 devnull return i;
454 a0d146ed 2005-07-12 devnull }
455 a0d146ed 2005-07-12 devnull
456 a0d146ed 2005-07-12 devnull static int
457 a0d146ed 2005-07-12 devnull downheap(int i, DBlock *b)
458 a0d146ed 2005-07-12 devnull {
459 a0d146ed 2005-07-12 devnull DBlock *bb;
460 a0d146ed 2005-07-12 devnull u32int now;
461 a0d146ed 2005-07-12 devnull int k;
462 a0d146ed 2005-07-12 devnull
463 a0d146ed 2005-07-12 devnull now = dcache.now;
464 a0d146ed 2005-07-12 devnull for(; ; i = k){
465 a0d146ed 2005-07-12 devnull k = (i << 1) + 1;
466 a0d146ed 2005-07-12 devnull if(k >= dcache.nheap)
467 a0d146ed 2005-07-12 devnull break;
468 a0d146ed 2005-07-12 devnull if(k + 1 < dcache.nheap && dcache.heap[k]->used2 - now > dcache.heap[k + 1]->used2 - now)
469 a0d146ed 2005-07-12 devnull k++;
470 a0d146ed 2005-07-12 devnull bb = dcache.heap[k];
471 a0d146ed 2005-07-12 devnull if(b->used2 - now <= bb->used2 - now)
472 a0d146ed 2005-07-12 devnull break;
473 a0d146ed 2005-07-12 devnull dcache.heap[i] = bb;
474 a0d146ed 2005-07-12 devnull bb->heap = i;
475 a0d146ed 2005-07-12 devnull }
476 a0d146ed 2005-07-12 devnull
477 a0d146ed 2005-07-12 devnull dcache.heap[i] = b;
478 a0d146ed 2005-07-12 devnull b->heap = i;
479 a0d146ed 2005-07-12 devnull return i;
480 a0d146ed 2005-07-12 devnull }
481 a0d146ed 2005-07-12 devnull
482 a0d146ed 2005-07-12 devnull static void
483 a0d146ed 2005-07-12 devnull findblock(DBlock *bb)
484 a0d146ed 2005-07-12 devnull {
485 a0d146ed 2005-07-12 devnull DBlock *b, *last;
486 a0d146ed 2005-07-12 devnull int h;
487 a0d146ed 2005-07-12 devnull
488 a0d146ed 2005-07-12 devnull last = nil;
489 a0d146ed 2005-07-12 devnull h = pbhash(bb->addr);
490 a0d146ed 2005-07-12 devnull for(b = dcache.heads[h]; b != nil; b = b->next){
491 a0d146ed 2005-07-12 devnull if(last != b->prev)
492 a0d146ed 2005-07-12 devnull sysfatal("bad prev link");
493 a0d146ed 2005-07-12 devnull if(b == bb)
494 a0d146ed 2005-07-12 devnull return;
495 a0d146ed 2005-07-12 devnull last = b;
496 a0d146ed 2005-07-12 devnull }
497 a0d146ed 2005-07-12 devnull sysfatal("block missing from hash table");
498 a0d146ed 2005-07-12 devnull }
499 a0d146ed 2005-07-12 devnull
500 a0d146ed 2005-07-12 devnull void
501 a0d146ed 2005-07-12 devnull checkdcache(void)
502 a0d146ed 2005-07-12 devnull {
503 a0d146ed 2005-07-12 devnull DBlock *b;
504 a0d146ed 2005-07-12 devnull u32int size, now;
505 a0d146ed 2005-07-12 devnull int i, k, refed, nfree;
506 a0d146ed 2005-07-12 devnull
507 a0d146ed 2005-07-12 devnull qlock(&dcache.lock);
508 a0d146ed 2005-07-12 devnull size = dcache.size;
509 a0d146ed 2005-07-12 devnull now = dcache.now;
510 a0d146ed 2005-07-12 devnull for(i = 0; i < dcache.nheap; i++){
511 a0d146ed 2005-07-12 devnull if(dcache.heap[i]->heap != i)
512 a0d146ed 2005-07-12 devnull sysfatal("dc: mis-heaped at %d: %d", i, dcache.heap[i]->heap);
513 a0d146ed 2005-07-12 devnull if(i > 0 && dcache.heap[(i - 1) >> 1]->used2 - now > dcache.heap[i]->used2 - now)
514 a0d146ed 2005-07-12 devnull sysfatal("dc: bad heap ordering");
515 a0d146ed 2005-07-12 devnull k = (i << 1) + 1;
516 a0d146ed 2005-07-12 devnull if(k < dcache.nheap && dcache.heap[i]->used2 - now > dcache.heap[k]->used2 - now)
517 a0d146ed 2005-07-12 devnull sysfatal("dc: bad heap ordering");
518 a0d146ed 2005-07-12 devnull k++;
519 a0d146ed 2005-07-12 devnull if(k < dcache.nheap && dcache.heap[i]->used2 - now > dcache.heap[k]->used2 - now)
520 a0d146ed 2005-07-12 devnull sysfatal("dc: bad heap ordering");
521 a0d146ed 2005-07-12 devnull }
522 a0d146ed 2005-07-12 devnull
523 a0d146ed 2005-07-12 devnull refed = 0;
524 a0d146ed 2005-07-12 devnull for(i = 0; i < dcache.nblocks; i++){
525 a0d146ed 2005-07-12 devnull b = &dcache.blocks[i];
526 a0d146ed 2005-07-12 devnull if(b->data != &dcache.mem[i * size])
527 a0d146ed 2005-07-12 devnull sysfatal("dc: mis-blocked at %d", i);
528 a0d146ed 2005-07-12 devnull if(b->ref && b->heap == TWID32)
529 a0d146ed 2005-07-12 devnull refed++;
530 a0d146ed 2005-07-12 devnull if(b->addr)
531 a0d146ed 2005-07-12 devnull findblock(b);
532 a0d146ed 2005-07-12 devnull if(b->heap != TWID32
533 a0d146ed 2005-07-12 devnull && dcache.heap[b->heap] != b)
534 a0d146ed 2005-07-12 devnull sysfatal("dc: spurious heap value");
535 a0d146ed 2005-07-12 devnull }
536 a0d146ed 2005-07-12 devnull
537 a0d146ed 2005-07-12 devnull nfree = 0;
538 a0d146ed 2005-07-12 devnull for(b = dcache.free; b != nil; b = b->next){
539 a0d146ed 2005-07-12 devnull if(b->addr != 0 || b->heap != TWID32)
540 a0d146ed 2005-07-12 devnull sysfatal("dc: bad free list");
541 a0d146ed 2005-07-12 devnull nfree++;
542 a0d146ed 2005-07-12 devnull }
543 a0d146ed 2005-07-12 devnull
544 a0d146ed 2005-07-12 devnull if(dcache.nheap + nfree + refed != dcache.nblocks)
545 a0d146ed 2005-07-12 devnull sysfatal("dc: missing blocks: %d %d %d", dcache.nheap, refed, dcache.nblocks);
546 a0d146ed 2005-07-12 devnull qunlock(&dcache.lock);
547 a0d146ed 2005-07-12 devnull }
548 a0d146ed 2005-07-12 devnull
549 a0d146ed 2005-07-12 devnull void
550 a0d146ed 2005-07-12 devnull flushdcache(void)
551 a0d146ed 2005-07-12 devnull {
552 a0d146ed 2005-07-12 devnull trace(TraceProc, "flushdcache enter");
553 a0d146ed 2005-07-12 devnull kickround(&dcache.round, 1);
554 a0d146ed 2005-07-12 devnull trace(TraceProc, "flushdcache exit");
555 a0d146ed 2005-07-12 devnull }
556 a0d146ed 2005-07-12 devnull
557 a0d146ed 2005-07-12 devnull void
558 a0d146ed 2005-07-12 devnull kickdcache(void)
559 a0d146ed 2005-07-12 devnull {
560 a0d146ed 2005-07-12 devnull kickround(&dcache.round, 0);
561 a0d146ed 2005-07-12 devnull }
562 a0d146ed 2005-07-12 devnull
563 a0d146ed 2005-07-12 devnull static int
564 a0d146ed 2005-07-12 devnull parallelwrites(DBlock **b, DBlock **eb, int dirty)
565 a0d146ed 2005-07-12 devnull {
566 a0d146ed 2005-07-12 devnull DBlock **p, **q;
567 7e452401 2007-04-27 devnull Part *part;
568 28b49df3 2006-07-18 devnull
569 a0d146ed 2005-07-12 devnull for(p=b; p<eb && (*p)->dirty == dirty; p++){
570 a0d146ed 2005-07-12 devnull assert(b<=p && p<eb);
571 a0d146ed 2005-07-12 devnull sendp((*p)->part->writechan, *p);
572 a0d146ed 2005-07-12 devnull }
573 a0d146ed 2005-07-12 devnull q = p;
574 a0d146ed 2005-07-12 devnull for(p=b; p<q; p++){
575 a0d146ed 2005-07-12 devnull assert(b<=p && p<eb);
576 a0d146ed 2005-07-12 devnull recvp((*p)->writedonechan);
577 7e452401 2007-04-27 devnull }
578 fa325e9b 2020-01-10 cross
579 7e452401 2007-04-27 devnull /*
580 7e452401 2007-04-27 devnull * Flush the partitions that have been written to.
581 7e452401 2007-04-27 devnull */
582 7e452401 2007-04-27 devnull part = nil;
583 7e452401 2007-04-27 devnull for(p=b; p<q; p++){
584 7e452401 2007-04-27 devnull if(part != (*p)->part){
585 7e452401 2007-04-27 devnull part = (*p)->part;
586 e46cacb0 2007-04-27 devnull flushpart(part); /* what if it fails? */
587 7e452401 2007-04-27 devnull }
588 a0d146ed 2005-07-12 devnull }
589 a0d146ed 2005-07-12 devnull
590 a0d146ed 2005-07-12 devnull return p-b;
591 a0d146ed 2005-07-12 devnull }
592 a0d146ed 2005-07-12 devnull
593 a0d146ed 2005-07-12 devnull /*
594 a0d146ed 2005-07-12 devnull * Sort first by dirty flag, then by partition, then by address in partition.
595 a0d146ed 2005-07-12 devnull */
596 a0d146ed 2005-07-12 devnull static int
597 a0d146ed 2005-07-12 devnull writeblockcmp(const void *va, const void *vb)
598 a0d146ed 2005-07-12 devnull {
599 a0d146ed 2005-07-12 devnull DBlock *a, *b;
600 a0d146ed 2005-07-12 devnull
601 a0d146ed 2005-07-12 devnull a = *(DBlock**)va;
602 a0d146ed 2005-07-12 devnull b = *(DBlock**)vb;
603 a0d146ed 2005-07-12 devnull
604 a0d146ed 2005-07-12 devnull if(a->dirty != b->dirty)
605 a0d146ed 2005-07-12 devnull return a->dirty - b->dirty;
606 a0d146ed 2005-07-12 devnull if(a->part != b->part){
607 a0d146ed 2005-07-12 devnull if(a->part < b->part)
608 a0d146ed 2005-07-12 devnull return -1;
609 a0d146ed 2005-07-12 devnull if(a->part > b->part)
610 a0d146ed 2005-07-12 devnull return 1;
611 a0d146ed 2005-07-12 devnull }
612 a0d146ed 2005-07-12 devnull if(a->addr < b->addr)
613 a0d146ed 2005-07-12 devnull return -1;
614 a0d146ed 2005-07-12 devnull return 1;
615 a0d146ed 2005-07-12 devnull }
616 a0d146ed 2005-07-12 devnull
617 a0d146ed 2005-07-12 devnull static void
618 a0d146ed 2005-07-12 devnull flushproc(void *v)
619 a0d146ed 2005-07-12 devnull {
620 a0d146ed 2005-07-12 devnull int i, j, n;
621 a0d146ed 2005-07-12 devnull ulong t0;
622 a0d146ed 2005-07-12 devnull DBlock *b, **write;
623 a0d146ed 2005-07-12 devnull
624 a0d146ed 2005-07-12 devnull USED(v);
625 a0d146ed 2005-07-12 devnull threadsetname("flushproc");
626 a0d146ed 2005-07-12 devnull for(;;){
627 a0d146ed 2005-07-12 devnull waitforkick(&dcache.round);
628 a0d146ed 2005-07-12 devnull
629 a0d146ed 2005-07-12 devnull trace(TraceWork, "start");
630 12c0e45f 2007-09-25 rsc t0 = nsec()/1000;
631 12c0e45f 2007-09-25 rsc trace(TraceProc, "build t=%lud", (ulong)(nsec()/1000)-t0);
632 a0d146ed 2005-07-12 devnull
633 a0d146ed 2005-07-12 devnull write = dcache.write;
634 a0d146ed 2005-07-12 devnull n = 0;
635 a0d146ed 2005-07-12 devnull for(i=0; i<dcache.nblocks; i++){
636 a0d146ed 2005-07-12 devnull b = &dcache.blocks[i];
637 a0d146ed 2005-07-12 devnull if(b->dirty)
638 a0d146ed 2005-07-12 devnull write[n++] = b;
639 a0d146ed 2005-07-12 devnull }
640 a0d146ed 2005-07-12 devnull
641 a0d146ed 2005-07-12 devnull qsort(write, n, sizeof(write[0]), writeblockcmp);
642 a0d146ed 2005-07-12 devnull
643 a0d146ed 2005-07-12 devnull /* Write each stage of blocks out. */
644 a0d146ed 2005-07-12 devnull trace(TraceProc, "writeblocks t=%lud", (ulong)(nsec()/1000)-t0);
645 a0d146ed 2005-07-12 devnull i = 0;
646 a0d146ed 2005-07-12 devnull for(j=1; j<DirtyMax; j++){
647 12c0e45f 2007-09-25 rsc trace(TraceProc, "writeblocks.%d t=%lud",
648 12c0e45f 2007-09-25 rsc j, (ulong)(nsec()/1000)-t0);
649 a0d146ed 2005-07-12 devnull i += parallelwrites(write+i, write+n, j);
650 a0d146ed 2005-07-12 devnull }
651 a0d146ed 2005-07-12 devnull if(i != n){
652 a0d146ed 2005-07-12 devnull fprint(2, "in flushproc i=%d n=%d\n", i, n);
653 a0d146ed 2005-07-12 devnull for(i=0; i<n; i++)
654 12c0e45f 2007-09-25 rsc fprint(2, "\tblock %d: dirty=%d\n",
655 12c0e45f 2007-09-25 rsc i, write[i]->dirty);
656 a0d146ed 2005-07-12 devnull abort();
657 a0d146ed 2005-07-12 devnull }
658 a0d146ed 2005-07-12 devnull
659 12c0e45f 2007-09-25 rsc /*
660 12c0e45f 2007-09-25 rsc * b->dirty is protected by b->lock while ndirty is protected
661 12c0e45f 2007-09-25 rsc * by dcache.lock, so the --ndirty below is the delayed one
662 12c0e45f 2007-09-25 rsc * from clearing b->dirty in the write proc. It may happen
663 12c0e45f 2007-09-25 rsc * that some other proc has come along and redirtied b since
664 12c0e45f 2007-09-25 rsc * the write. That's okay, it just means that ndirty may be
665 12c0e45f 2007-09-25 rsc * one too high until we catch up and do the decrement.
666 12c0e45f 2007-09-25 rsc */
667 a0d146ed 2005-07-12 devnull trace(TraceProc, "undirty.%d t=%lud", j, (ulong)(nsec()/1000)-t0);
668 a0d146ed 2005-07-12 devnull qlock(&dcache.lock);
669 a0d146ed 2005-07-12 devnull for(i=0; i<n; i++){
670 a0d146ed 2005-07-12 devnull b = write[i];
671 a0d146ed 2005-07-12 devnull --dcache.ndirty;
672 a0d146ed 2005-07-12 devnull if(b->ref == 0 && b->heap == TWID32){
673 a0d146ed 2005-07-12 devnull upheap(dcache.nheap++, b);
674 a0d146ed 2005-07-12 devnull rwakeupall(&dcache.full);
675 a0d146ed 2005-07-12 devnull }
676 a0d146ed 2005-07-12 devnull }
677 a0d146ed 2005-07-12 devnull setstat(StatDcacheDirty, dcache.ndirty);
678 a0d146ed 2005-07-12 devnull qunlock(&dcache.lock);
679 a0d146ed 2005-07-12 devnull addstat(StatDcacheFlush, 1);
680 a0d146ed 2005-07-12 devnull trace(TraceWork, "finish");
681 a0d146ed 2005-07-12 devnull }
682 a0d146ed 2005-07-12 devnull }
683 a0d146ed 2005-07-12 devnull
684 a0d146ed 2005-07-12 devnull static void
685 a0d146ed 2005-07-12 devnull writeproc(void *v)
686 a0d146ed 2005-07-12 devnull {
687 a0d146ed 2005-07-12 devnull DBlock *b;
688 a0d146ed 2005-07-12 devnull Part *p;
689 a0d146ed 2005-07-12 devnull
690 a0d146ed 2005-07-12 devnull p = v;
691 a0d146ed 2005-07-12 devnull
692 a0d146ed 2005-07-12 devnull threadsetname("writeproc:%s", p->name);
693 a0d146ed 2005-07-12 devnull for(;;){
694 a0d146ed 2005-07-12 devnull b = recvp(p->writechan);
695 a0d146ed 2005-07-12 devnull trace(TraceWork, "start");
696 a0d146ed 2005-07-12 devnull assert(b->part == p);
697 a0d146ed 2005-07-12 devnull trace(TraceProc, "wlock %s 0x%llux", p->name, b->addr);
698 a0d146ed 2005-07-12 devnull wlock(&b->lock);
699 a0d146ed 2005-07-12 devnull trace(TraceProc, "writepart %s 0x%llux", p->name, b->addr);
700 28b49df3 2006-07-18 devnull diskaccess(0);
701 a0d146ed 2005-07-12 devnull if(writepart(p, b->addr, b->data, b->size) < 0)
702 12c0e45f 2007-09-25 rsc fprint(2, "%s: writeproc: part %s addr 0x%llux: write error: %r\n",
703 12c0e45f 2007-09-25 rsc argv0, p->name, b->addr);
704 a0d146ed 2005-07-12 devnull addstat(StatApartWrite, 1);
705 a0d146ed 2005-07-12 devnull addstat(StatApartWriteBytes, b->size);
706 a0d146ed 2005-07-12 devnull b->dirty = 0;
707 a0d146ed 2005-07-12 devnull wunlock(&b->lock);
708 a0d146ed 2005-07-12 devnull trace(TraceProc, "finish %s 0x%llux", p->name, b->addr);
709 a0d146ed 2005-07-12 devnull trace(TraceWork, "finish");
710 a0d146ed 2005-07-12 devnull sendp(b->writedonechan, b);
711 a0d146ed 2005-07-12 devnull }
712 a0d146ed 2005-07-12 devnull }