1 /*
2 * The AFFLIB page abstraction.
3 * Distributed under the Berkeley 4-part license
4 */
5
6 #include "affconfig.h"
7 #include "afflib.h"
8 #include "afflib_i.h"
9
10
11 /* af_read_sizes:
12 * Get the page sizes if they are set in the file.
13 */
af_read_sizes(AFFILE * af)14 void af_read_sizes(AFFILE *af)
15 {
16 af_get_seg(af,AF_SECTORSIZE,&af->image_sectorsize,0,0);
17 if(af->image_sectorsize==0) af->image_sectorsize = 512; // reasonable default
18
19 if(af_get_seg(af,AF_PAGESIZE,&af->image_pagesize,0,0)){
20 af_get_seg(af,AF_SEGSIZE_D,&af->image_pagesize,0,0); // try old name
21 }
22
23 /* Read the badflag if it is present.
24 * Be sure to adjust badflag size to current sector size (which may have changed).
25 */
26 if(af->badflag!=0) free(af->badflag);
27 af->badflag = (unsigned char *)malloc(af->image_sectorsize);
28 size_t sectorsize = af->image_sectorsize;
29 if(af_get_seg(af,AF_BADFLAG,0,af->badflag,(size_t *)§orsize)==0){
30 af->badflag_set = 1;
31 }
32
33 /* Read the image file segment if it is present.
34 * If it isn't, scan through the disk image to figure out the size of the disk image.
35 */
36
37 if(af_get_segq(af,AF_IMAGESIZE,(int64_t *)&af->image_size)){
38
39 /* Calculate the imagesize by scanning all of the pages that are in
40 * the disk image and finding the highest page number.
41 * Then read that page to find the last allocated byte.
42 */
43 char segname[AF_MAX_NAME_LEN];
44 size_t datalen = 0;
45 af_rewind_seg(af); // start at the beginning
46 int64_t highest_page_number = 0;
47 while(af_get_next_seg(af,segname,sizeof(segname),0,0,&datalen)==0){
48 if(segname[0]==0) continue; // ignore sector
49 int64_t pagenum = af_segname_page_number(segname);
50 if(pagenum > highest_page_number) highest_page_number = pagenum;
51 }
52 size_t highest_page_len = 0;
53 if(af_get_page(af,highest_page_number,0,&highest_page_len)==0){
54 af->image_size = af->image_pagesize * highest_page_number + highest_page_len;
55 }
56 }
57 af->image_size_in_file = af->image_size;
58 }
59
60
af_page_size(AFFILE * af)61 int af_page_size(AFFILE *af)
62 {
63 return af->image_pagesize;
64 }
65
af_get_pagesize(AFFILE * af)66 int af_get_pagesize(AFFILE *af)
67 {
68 return af->image_pagesize;
69 }
70
71 /* af_set_sectorsize:
72 * Sets the sectorsize.
73 * Fails with -1 if imagesize >=0 unless these changes permitted
74 */
af_set_sectorsize(AFFILE * af,int sectorsize)75 int af_set_sectorsize(AFFILE *af,int sectorsize)
76 {
77 struct af_vnode_info vni;
78 af_vstat(af,&vni);
79 if(vni.changable_pagesize==0 && af->image_size>0){
80 errno = EINVAL;
81 return -1;
82 }
83 af->image_sectorsize =sectorsize;
84 if(af->badflag==0) af->badflag = (unsigned char *)malloc(sectorsize);
85 else af->badflag = (unsigned char *)realloc(af->badflag,sectorsize);
86 af->badflag_set = 0;
87
88 if(af_update_seg(af,AF_SECTORSIZE,sectorsize,0,0)){
89 if(errno != ENOTSUP) return -1;
90 }
91 return 0;
92 }
93
af_get_sectorsize(AFFILE * af)94 int af_get_sectorsize(AFFILE *af) // returns sector size
95 {
96 return af->image_sectorsize;
97 }
98
99 /*
100 * af_set_pagesize:
101 * Sets the pagesize. Fails with -1 if it can't be changed.
102 */
af_set_pagesize(AFFILE * af,uint32_t pagesize)103 int af_set_pagesize(AFFILE *af,uint32_t pagesize)
104 {
105 /* Allow the pagesize to be changed if it hasn't been set yet
106 * and if this format doesn't support metadata updating (which is the raw formats)
107 */
108 struct af_vnode_info vni;
109
110 af_vstat(af,&vni);
111
112 if(vni.changable_pagesize==0 && af->image_size>0){
113 if(pagesize==af->image_pagesize) return 0; // it's already set to this, so let it pass
114 errno = EINVAL;
115 return -1;
116 }
117 if(pagesize % af->image_sectorsize != 0){
118 (*af->error_reporter)("Cannot set pagesize to %d (sectorsize=%d)\n",
119 pagesize,af->image_sectorsize);
120 errno = EINVAL;
121 return -1;
122 }
123
124 af->image_pagesize = pagesize;
125 if(af_update_seg(af,AF_PAGESIZE,pagesize,0,0)){
126 if(errno != ENOTSUP) return -1; // error updating (don't report ENOTSUP);
127 }
128 return 0;
129 }
130
131
132 /****************************************************************
133 *** page-level interface
134 ****************************************************************/
135
af_get_page_raw(AFFILE * af,int64_t pagenum,uint32_t * arg,unsigned char * data,size_t * bytes)136 int af_get_page_raw(AFFILE *af,int64_t pagenum,uint32_t *arg,
137 unsigned char *data,size_t *bytes)
138 {
139 char segname[AF_MAX_NAME_LEN];
140
141 memset(segname,0,sizeof(segname));
142 sprintf(segname,AF_PAGE,pagenum);
143 int r = af_get_seg(af,segname,arg,data,bytes);
144 if(r < 0 && errno == ENOENT)
145 {
146 /* Couldn't read with AF_PAGE; try AF_SEG_D.
147 * This is legacy for the old AFF files. Perhaps we should delete it.
148 */
149 sprintf(segname,AF_SEG_D,pagenum);
150 r = af_get_seg(af,segname,arg,data,bytes);
151 }
152 /* Update the counters */
153 if(r==0 && bytes && *bytes>0) af->pages_read++; // note that we read a page
154 return r;
155 }
156
157 /* af_get_page:
158 * Get a page from its named segment.
159 * If the page is compressed, uncompress it.
160 * data points to a segmenet of at least *bytes;
161 * *bytes is then modified to indicate the actual amount of bytes read.
162 * Return 0 if success, -1 if fail.
163 */
164
af_get_page(AFFILE * af,int64_t pagenum,unsigned char * data,size_t * bytes)165 int af_get_page(AFFILE *af,int64_t pagenum,unsigned char *data,size_t *bytes)
166 {
167 uint32_t arg=0;
168 size_t page_len=0;
169
170 if (af_trace){
171 fprintf(af_trace,"af_get_page(%p,pagenum=%" I64d ",buf=%p,bytes=%u)\n",af,pagenum,data,(int)*bytes);
172 }
173
174 /* Find out the size of the segment and if it is compressed or not.
175 * If we can't find it with new nomenclature, try the old one...
176 */
177 int r = af_get_page_raw(af,pagenum,&arg,0,&page_len);
178 if(r){
179 /* Segment doesn't exist.
180 * If we have been provided with a buffer,
181 * fill buffer with the 'bad segment' flag and return.
182 */
183 if(data && (af->openmode & AF_BADBLOCK_FILL) && errno == ENOENT)
184 {
185 for(size_t i = 0;i <= af->image_pagesize - af->image_sectorsize;
186 i+= af->image_sectorsize){
187 memcpy(data+i,af->badflag,af->image_sectorsize);
188 af->bytes_memcpy += af->image_sectorsize;
189 }
190
191 r = 0;
192 }
193 return r; // segment doesn't exist
194 }
195
196
197 /* If the segment isn't compressed, just get it*/
198 uint32_t pageflag = 0;
199 if((arg & AF_PAGE_COMPRESSED)==0){
200 if(data==0){ // if no data provided, just return size of the segment if requested
201 if(bytes) *bytes = page_len; // set the number of bytes in the page if requested
202 return 0;
203 }
204 int ret = af_get_page_raw(af,pagenum,&pageflag,data,bytes);
205 if(*bytes > page_len) *bytes = page_len; // we only read this much
206 if(ret!=0) return ret; // some error happened?
207 }
208 else {
209 /* Allocate memory to hold the compressed segment */
210 unsigned char *compressed_data = (unsigned char *)malloc(page_len);
211 size_t compressed_data_len = page_len;
212 if(compressed_data==0){
213 return -2; // memory error
214 }
215
216 /* Get the data */
217 if(af_get_page_raw(af,pagenum,&pageflag,compressed_data,&compressed_data_len)){
218 free(compressed_data);
219 return -3; // read error
220 }
221
222 /* Now uncompress directly into the buffer provided by the caller, unless the caller didn't
223 * provide a buffer. If that happens, allocate our own...
224 */
225 int res = -1; // 0 is success
226 bool free_data = false;
227 if(data==0){
228 data = (unsigned char *)malloc(af->image_pagesize);
229 free_data = true;
230 *bytes = af->image_pagesize; // I can hold this much
231 }
232
233 switch((pageflag & AF_PAGE_COMP_ALG_MASK)){
234 case AF_PAGE_COMP_ALG_ZERO:
235 if(compressed_data_len != 4){
236 (*af->error_reporter)("ALG_ZERO compressed data is %d bytes, expected 4.",compressed_data_len);
237 break;
238 }
239 memset(data,0,af->image_pagesize);
240 *bytes = ntohl(*(long *)compressed_data);
241 res = 0; // not very hard to decompress with the ZERO compressor.
242 break;
243
244 case AF_PAGE_COMP_ALG_ZLIB:
245 res = uncompress(data,(uLongf *)bytes,compressed_data,compressed_data_len);
246 switch(res){
247 case Z_OK:
248 break;
249 case Z_ERRNO:
250 (*af->error_reporter)("Z_ERRNOR decompressing segment %" I64d,pagenum);
251 case Z_STREAM_ERROR:
252 (*af->error_reporter)("Z_STREAM_ERROR decompressing segment %" I64d,pagenum);
253 case Z_DATA_ERROR:
254 (*af->error_reporter)("Z_DATA_ERROR decompressing segment %" I64d,pagenum);
255 case Z_MEM_ERROR:
256 (*af->error_reporter)("Z_MEM_ERROR decompressing segment %" I64d,pagenum);
257 case Z_BUF_ERROR:
258 (*af->error_reporter)("Z_BUF_ERROR decompressing segment %" I64d,pagenum);
259 case Z_VERSION_ERROR:
260 (*af->error_reporter)("Z_VERSION_ERROR decompressing segment %" I64d,pagenum);
261 default:
262 (*af->error_reporter)("uncompress returned an invalid value in get_segment");
263 }
264 break;
265
266 #ifdef USE_LZMA
267 case AF_PAGE_COMP_ALG_LZMA:
268 res = lzma_uncompress(data,bytes,compressed_data,compressed_data_len);
269 if (af_trace) fprintf(af_trace," LZMA decompressed page %" I64d ". %d bytes => %u bytes\n",
270 pagenum,(int)compressed_data_len,(int)*bytes);
271 switch(res){
272 case 0:break; // OK
273 case 1:(*af->error_reporter)("LZMA header error decompressing segment %" I64d "\n",pagenum);
274 break;
275 case 2:(*af->error_reporter)("LZMA memory error decompressing segment %" I64d "\n",pagenum);
276 break;
277 }
278 break;
279 #endif
280
281 default:
282 (*af->error_reporter)("Unknown compression algorithm 0x%d",
283 pageflag & AF_PAGE_COMP_ALG_MASK);
284 break;
285 }
286
287 if(free_data){
288 free(data);
289 data = 0; // restore the way it was
290 }
291 free(compressed_data); // don't need this one anymore
292 af->pages_decompressed++;
293 if(res!=Z_OK) return -1;
294 }
295
296 /* If the page size is larger than the sector_size,
297 * make sure that the rest of the sector is zeroed, and that the
298 * rest after that has the 'bad block' notation.
299 */
300 if(data && (af->image_pagesize > af->image_sectorsize)){
301 const int SECTOR_SIZE = af->image_sectorsize; // for ease of typing
302 size_t bytes_left_in_sector = (SECTOR_SIZE - (*bytes % SECTOR_SIZE)) % SECTOR_SIZE;
303 for(size_t i=0;i<bytes_left_in_sector;i++){
304 data[*bytes + i] = 0;
305 }
306 size_t end_of_data = *bytes + bytes_left_in_sector;
307
308 /* Now fill to the end of the page... */
309 for(size_t i = end_of_data; i <= af->image_pagesize-SECTOR_SIZE; i+=SECTOR_SIZE){
310 memcpy(data+i,af->badflag,SECTOR_SIZE);
311 af->bytes_memcpy += SECTOR_SIZE;
312 }
313 }
314 return 0;
315 }
316
317
is_buffer_zero(unsigned char * buf,int buflen)318 static bool is_buffer_zero(unsigned char *buf,int buflen)
319 {
320 if(buflen >= (int)sizeof(long))
321 {
322 // align to word boundary
323 buflen -= (intptr_t)buf % sizeof(long);
324
325 while((intptr_t)buf % sizeof(long))
326 {
327 if(*buf++)
328 return false;
329 }
330
331 // read in words
332 long *ptr = (long*)buf;
333 buf += buflen - buflen % sizeof(long);
334 buflen %= sizeof(long);
335
336 while(ptr < (long*)buf)
337 {
338 if(*ptr++)
339 return false;
340 }
341 }
342
343 while(buflen--)
344 {
345 if(*buf++)
346 return false;
347 }
348
349 return true;
350 }
351
352 /* Write a actual data segment to the disk and sign if necessary. */
af_update_page(AFFILE * af,int64_t pagenum,unsigned char * data,int datalen)353 int af_update_page(AFFILE *af,int64_t pagenum,unsigned char *data,int datalen)
354 {
355 char segname_buf[32];
356 snprintf(segname_buf,sizeof(segname_buf),AF_PAGE,pagenum); // determine segment name
357
358 #ifdef USE_AFFSIGS
359 /* Write out the signature if we have a private key */
360 if(af->crypto && af->crypto->sign_privkey){
361 af_sign_seg3(af,segname_buf,0,data,datalen,AF_SIGNATURE_MODE1);
362 }
363 #endif
364
365 #ifdef HAVE_MD5
366 /* Write out MD5 if requested */
367 if(af->write_md5){
368 unsigned char md5_buf[16];
369 char md5name_buf[32];
370 MD5(data,datalen,md5_buf);
371 snprintf(md5name_buf,sizeof(md5name_buf),AF_PAGE_MD5,pagenum);
372 af_update_segf(af,md5name_buf,0,md5_buf,sizeof(md5_buf),AF_SIGFLAG_NOSIG); // ignore failure
373 }
374 #endif
375 #ifdef HAVE_SHA1
376 /* Write out SHA1 if requested */
377 if(af->write_sha1){
378 unsigned char sha1_buf[20];
379 char sha1name_buf[32];
380 SHA1(data,datalen,sha1_buf);
381 snprintf(sha1name_buf,sizeof(sha1name_buf),AF_PAGE_SHA1,pagenum);
382 af_update_segf(af,sha1name_buf,0,sha1_buf,sizeof(sha1_buf),AF_SIGFLAG_NOSIG); // ignore failure
383 }
384 #endif
385 /* Write out SHA256 if requested and if SHA256 is available */
386 if(af->write_sha256){
387 unsigned char sha256_buf[32];
388 if(af_SHA256(data,datalen,sha256_buf)==0){
389 char sha256name_buf[32];
390 snprintf(sha256name_buf,sizeof(sha256name_buf),AF_PAGE_SHA256,pagenum);
391 af_update_segf(af,sha256name_buf,0,sha256_buf,sizeof(sha256_buf),AF_SIGFLAG_NOSIG); // ignore failure
392 }
393 }
394
395 /* Check for bypass */
396 if(af->v->write){
397 int r = (*af->v->write)(af,data,af->image_pagesize * pagenum,datalen);
398 if(r!=datalen) return -1;
399 return 0;
400 }
401
402 struct affcallback_info acbi;
403 int ret = 0;
404 uint64_t starting_pages_written = af->pages_written;
405
406 /* Setup the callback structure */
407 memset(&acbi,0,sizeof(acbi));
408 acbi.info_version = 1;
409 acbi.af = af->parent ? af->parent : af;
410 acbi.pagenum = pagenum;
411 acbi.bytes_to_write = datalen;
412
413 size_t destLen = af->image_pagesize; // it could be this big.
414
415 /* Compress and write the data, if we are allowed to compress */
416 if(af->compression_type != AF_COMPRESSION_ALG_NONE){
417 unsigned char *cdata = (unsigned char *)malloc(destLen); // compressed data
418 uint32_t *ldata = (uint32_t *)cdata; // allows me to reference as a buffer of uint32_ts
419 if(cdata!=0){ // If data could be allocated
420 int cres = -1; // compression results
421 uint32_t flag = 0; // flag for data segment
422 int dont_compress = 0;
423
424 /* Try zero compression first; it's the best algorithm we have */
425 if(is_buffer_zero(data,datalen)){
426 acbi.compression_alg = AF_PAGE_COMP_ALG_ZERO;
427 acbi.compression_level = AF_COMPRESSION_MAX;
428
429 if(af->w_callback) { acbi.phase = 1; (*af->w_callback)(&acbi); }
430
431 *ldata = htonl(datalen); // store the data length
432 destLen = 4; // 4 bytes
433 flag = AF_PAGE_COMPRESSED | AF_PAGE_COMP_ALG_ZERO | AF_PAGE_COMP_MAX;
434 cres = 0;
435
436 acbi.compressed = 1; // it was compressed
437 if(af->w_callback) {acbi.phase = 2;(*af->w_callback)(&acbi);}
438 }
439
440 #ifdef USE_LZMA
441 if(cres!=0 && af->compression_type==AF_COMPRESSION_ALG_LZMA){ // try to compress with LZMA
442 acbi.compression_alg = AF_PAGE_COMP_ALG_LZMA;
443 acbi.compression_level = 7; // right now, this is the level we use
444 if(af->w_callback) { acbi.phase = 1; (*af->w_callback)(&acbi); }
445
446 cres = lzma_compress(cdata,&destLen,data,datalen,9);
447 #if 0
448 switch(cres){
449 case 0:break; // OKAY
450 case 1: (*af->error_reporter)("LZMA: Unspecified Error\n");break;
451 case 2: (*af->error_reporter)("LZMA: Memory Allocating Error\n");break;
452 case 3: (*af->error_reporter)("LZMA: Output buffer OVERFLOW\n"); break;
453 default: (*af->error_reporter)("LZMA: Unknown error %d\n",cres);break;
454 }
455 #endif
456 if(cres==0){
457 flag = AF_PAGE_COMPRESSED | AF_PAGE_COMP_ALG_LZMA;
458 acbi.compressed = 1;
459 if(af->w_callback) {acbi.phase = 2;(*af->w_callback)(&acbi);}
460 }
461 else {
462 /* Don't bother reporting LZMA errors; we just won't compress */
463 dont_compress = 1;
464 if(af->w_callback) {acbi.phase = 2;(*af->w_callback)(&acbi);}
465 }
466 }
467 #endif
468
469 if(cres!=0
470 && af->compression_type==AF_COMPRESSION_ALG_ZLIB
471 && dont_compress==0){ // try to compress with zlib
472 acbi.compression_alg = AF_PAGE_COMP_ALG_ZLIB; // only one that we support
473 acbi.compression_level = af->compression_level;
474 if(af->w_callback) { acbi.phase = 1; (*af->w_callback)(&acbi); }
475
476 cres = compress2((Bytef *)cdata, (uLongf *)&destLen,
477 (Bytef *)data,datalen, af->compression_level);
478
479 if(cres==0){
480 flag = AF_PAGE_COMPRESSED | AF_PAGE_COMP_ALG_ZLIB;
481 if(af->compression_level == AF_COMPRESSION_MAX){
482 flag |= AF_PAGE_COMP_MAX; // useful to know it can't be better
483 }
484 }
485 acbi.compressed = 1; // it was compressed (or not compressed)
486 if(af->w_callback) {acbi.phase = 2;(*af->w_callback)(&acbi);}
487 }
488
489 if(cres==0 && destLen < af->image_pagesize){
490 /* Prepare to write out the compressed segment with compression */
491 if(af->w_callback) {acbi.phase = 3;(*af->w_callback)(&acbi);}
492 ret = af_update_segf(af,segname_buf,flag,cdata,destLen,AF_SIGFLAG_NOSIG);
493 acbi.bytes_written = destLen;
494 if(af->w_callback) {acbi.phase = 4;(*af->w_callback)(&acbi);}
495 if(ret==0){
496 af->pages_written++;
497 af->pages_compressed++;
498 }
499 }
500 free(cdata);
501 cdata = 0;
502 }
503 }
504
505 /* If a compressed segment was not written, write it uncompressed */
506 if(af->pages_written == starting_pages_written){
507 if(af->w_callback) {acbi.phase = 3;(*af->w_callback)(&acbi);}
508 ret = af_update_segf(af,segname_buf,0,data,datalen,AF_SIGFLAG_NOSIG);
509 acbi.bytes_written = datalen;
510 if(af->w_callback) {acbi.phase = 4;(*af->w_callback)(&acbi);}
511 if(ret==0){
512 acbi.bytes_written = datalen; // because that is how much we wrote
513 af->pages_written++;
514 }
515 }
516 return ret;
517 }
518
519 /****************************************************************
520 *** Cache interface
521 ****************************************************************/
522
523 /* The page cache is a read/write cache.
524 *
525 * Pages that are read are cached after they are decompressed.
526 * When new pages are fetched, we check the cache first to see if they are there;
527 * if so, they are satsfied by the cache.
528 *
529 * Modifications are written to the cache, then dumped to the disk.
530 *
531 * The cache is managed by two functions:
532 * af_cache_flush(af) - (prevously af_purge)
533 * - Makes sure that all dirty buffers are written.
534 * - Sets af->pb=NULL (no current page)
535 * - (returns 0 if success, -1 if failure.)
536 *
537 * af_cache_writethrough(af,page,buf,buflen)
538 * - used for write bypass
539 *
540 */
541
542 static int cachetime = 0;
543
544
af_cache_flush(AFFILE * af)545 int af_cache_flush(AFFILE *af)
546 {
547 if(af_trace) fprintf(af_trace,"af_cache_flush()\n");
548 int ret = 0;
549 for(int i=0;i<af->num_pbufs;i++){
550 struct aff_pagebuf *p = &af->pbcache[i];
551 if(p->pagebuf_valid && p->pagebuf_dirty){
552 if(af_update_page(af,p->pagenum,p->pagebuf,p->pagebuf_bytes)){
553 ret = -1; // got an error; keep going, though
554 }
555 p->pagebuf_dirty = 0;
556 if(af_trace) fprintf(af_trace,"af_cache_flush: slot %d page %" PRIu64 " flushed.\n",i,p->pagenum);
557 }
558 }
559 return ret; // now return the error that I might have gotten
560 }
561
562 /* If the page being written is in the cache, update it.
563 * Question: would it make sense to copy the data anyway? I don't think so, because
564 * the main use of writethrough is when imaging, and in that event you probably don't
565 * want the extra memcpy.
566 */
af_cache_writethrough(AFFILE * af,int64_t pagenum,const unsigned char * buf,int bufflen)567 void af_cache_writethrough(AFFILE *af,int64_t pagenum,const unsigned char *buf,int bufflen)
568 {
569 for(int i=0;i<af->num_pbufs;i++){
570 struct aff_pagebuf *p = &af->pbcache[i];
571 if(p->pagenum_valid && p->pagenum == pagenum){
572 if(p->pagebuf_dirty){
573 (*af->error_reporter)("af_cache_writethrough: overwriting page %" I64u ".\n",pagenum);
574 exit(-1); // this shouldn't happen
575 }
576 memcpy(p->pagebuf,buf,bufflen);
577 memset(p->pagebuf+bufflen,0,af->image_pagesize-bufflen); // zero fill the rest
578 af->bytes_memcpy += bufflen;
579 p->pagebuf_valid = 1; // we have a copy of it now.
580 p->pagebuf_dirty = 0; // but it isn't dirty
581 p->last = cachetime++;
582 }
583 }
584 }
585
586 #ifdef HAVE_MALLOC_H
587 #include <malloc.h>
588 #endif
589
590 #ifndef HAVE_VALLOC
591 #define valloc malloc
592 #endif
593
af_cache_alloc(AFFILE * af,int64_t pagenum)594 struct aff_pagebuf *af_cache_alloc(AFFILE *af,int64_t pagenum)
595 {
596 if(af_trace) fprintf(af_trace,"af_cache_alloc(%p,%" I64d ")\n",af,pagenum);
597
598 /* Make sure nothing in the cache is dirty */
599 if(af_cache_flush(af) < 0)
600 return 0;
601
602 /* See if this page is already in the cache */
603 for(int i=0;i<af->num_pbufs;i++){
604 struct aff_pagebuf *p = &af->pbcache[i];
605 if(p->pagenum_valid && p->pagenum==pagenum){
606 af->cache_hits++;
607 if(af_trace) fprintf(af_trace," page %" I64d " satisfied fromcache\n",pagenum);
608 p->last = cachetime++;
609 return p;
610 }
611 }
612
613 af->cache_misses++;
614 int slot = -1;
615 /* See if there is an empty slot in the cache */
616 for(int i=0;i<af->num_pbufs;i++){
617 struct aff_pagebuf *p = &af->pbcache[i];
618 if(p->pagenum_valid==0){
619 slot = i;
620 if(af_trace) fprintf(af_trace," slot %d given to page %" I64d "\n",slot,pagenum);
621 break;
622 }
623 }
624 if(slot==-1){
625 /* Find the oldest cache entry */
626 int oldest_i = 0;
627 int oldest_t = af->pbcache[0].last;
628 for(int i=1;i<af->num_pbufs;i++){
629 if(af->pbcache[i].last < oldest_t){
630 oldest_t = af->pbcache[i].last;
631 oldest_i = i;
632 }
633 }
634 slot = oldest_i;
635 if(af_trace) fprintf(af_trace," slot %d assigned to page %" I64d "\n",slot,pagenum);
636 }
637 /* take over this slot */
638 struct aff_pagebuf *p = &af->pbcache[slot];
639 if(p->pagebuf==0){
640 p->pagebuf = (unsigned char *)valloc(af->image_pagesize); // allocate to a page boundary
641 if(p->pagebuf==0){
642 /* Malloc failed; See if we can just use the first slot */
643 slot = 0;
644 if(af->pbcache[0].pagebuf==0) return 0; // ugh. Cannot malloc?
645
646 /* First slot is available. Just use it. */
647 p = &af->pbcache[0];
648 }
649 }
650 memset(p->pagebuf,0,af->image_pagesize); // clean object reuse
651 p->pagenum = pagenum;
652 p->pagenum_valid = 1;
653 p->pagebuf_valid = 0;
654 p->pagebuf_dirty = 0;
655 p->last = cachetime++;
656 if(af_trace){
657 fprintf(af_trace," current pages in cache: ");
658 for(int i=0;i<af->num_pbufs;i++){
659 fprintf(af_trace," %" I64d,af->pbcache[i].pagenum);
660 }
661 fprintf(af_trace,"\n");
662 }
663 return p;
664 }
665
666
667
668
669