1 Upstream-Status: inappropriate
3 From 29a36b0b91ee009ee4219934c7a70278b1361834 Mon Sep 17 00:00:00 2001
4 From: Corey Minyard <cminyard@mvista.com>
5 Date: Sun, 5 Jun 2011 15:24:57 -0500
6 Subject: [PATCH 10/19] Convert over to keeping the filesystem on disk
8 This makes the actual filesystem be on disk and not in memory. It
9 adds caching of the filesystem data to help keep oft-accessed blocks
10 in memory and byteswapped.
12 cache.h | 128 ++++++++++++++++++++
13 genext2fs.c | 377 +++++++++++++++++++++++++++++++++++++++++++++++++----------
14 list.h | 78 ++++++++++++
15 3 files changed, 521 insertions(+), 62 deletions(-)
16 create mode 100644 cache.h
17 create mode 100644 list.h
19 diff --git a/cache.h b/cache.h
21 index 0000000..5275be6
30 +#define CACHE_LISTS 256
40 + /* LRU list holds unused items */
41 + unsigned int lru_entries;
43 + unsigned int max_free_entries;
45 + unsigned int entries;
46 + list_elem lists[CACHE_LISTS];
47 + unsigned int (*elem_val)(cache_link *elem);
48 + void (*freed)(cache_link *elem);
52 +cache_add(listcache *c, cache_link *elem)
54 + unsigned int hash = c->elem_val(elem) % CACHE_LISTS;
55 + int delcount = c->lru_entries - c->max_free_entries;
58 + /* Delete some unused items. */
59 + list_elem *lru, *next;
61 + list_for_each_elem_safe(&c->lru_list, lru, next) {
62 + l = container_of(lru, cache_link, lru_link);
75 + list_item_init(&elem->lru_link); /* Mark it not in the LRU list */
76 + list_add_after(&c->lists[hash], &elem->link);
80 +cache_item_set_unused(listcache *c, cache_link *elem)
82 + list_add_before(&c->lru_list, &elem->lru_link);
86 +static inline cache_link *
87 +cache_find(listcache *c, unsigned int val)
89 + unsigned int hash = val % CACHE_LISTS;
92 + list_for_each_elem(&c->lists[hash], elem) {
93 + cache_link *l = container_of(elem, cache_link, link);
94 + if (c->elem_val(l) == val) {
95 + if (!list_empty(&l->lru_link)) {
96 + /* It's in the unused list, remove it. */
97 + list_del(&l->lru_link);
98 + list_item_init(&l->lru_link);
108 +cache_flush(listcache *c)
110 + list_elem *elem, *next;
114 + list_for_each_elem_safe(&c->lru_list, elem, next) {
115 + l = container_of(elem, cache_link, lru_link);
117 + list_del(&l->link);
123 + for (i = 0; i < CACHE_LISTS; i++) {
124 + list_for_each_elem_safe(&c->lists[i], elem, next) {
125 + l = container_of(elem, cache_link, link);
126 + list_del(&l->link);
132 + return c->entries || c->lru_entries;
136 +cache_init(listcache *c, unsigned int max_free_entries,
137 + unsigned int (*elem_val)(cache_link *elem),
138 + void (*freed)(cache_link *elem))
143 + c->lru_entries = 0;
144 + c->max_free_entries = max_free_entries;
145 + list_init(&c->lru_list);
146 + for (i = 0; i < CACHE_LISTS; i++)
147 + list_init(&c->lists[i]);
148 + c->elem_val = elem_val;
152 +#endif /* __CACHE_H__ */
153 diff --git a/genext2fs.c b/genext2fs.c
154 index 51403a2..f79438d 100644
164 unsigned long nblocks;
165 unsigned long ninodes;
166 @@ -600,6 +602,7 @@ struct hdlinks_s
167 #if BLOCKSIZE == 1024
174 @@ -607,6 +610,10 @@ typedef struct
177 struct hdlinks_s hdlinks;
184 #error UNHANDLED BLOCKSIZE
185 @@ -848,45 +855,150 @@ allocated(block b, uint32 item)
198 +#define MAX_FREE_CACHE_BLOCKS 100
201 +blk_elem_val(cache_link *elem)
203 + blk_info *bi = container_of(elem, blk_info, link);
208 +blk_freed(cache_link *elem)
210 + blk_info *bi = container_of(elem, blk_info, link);
212 + if (fseeko(bi->fs->f, ((off_t) bi->blk) * BLOCKSIZE, SEEK_SET))
213 + perror_msg_and_die("fseek");
214 + if (fwrite(bi->b, BLOCKSIZE, 1, bi->fs->f) != 1)
215 + perror_msg_and_die("get_blk: write");
220 // Return a given block from a filesystem. Make sure to call
221 // put_blk when you are done with it.
222 static inline uint8 *
223 get_blk(filesystem *fs, uint32 blk, blk_info **rbi)
225 - return fs->data + blk*BLOCKSIZE;
229 + if (blk < fs->nheadblocks)
230 + error_msg_and_die("Internal error, request for head block");
231 + if (blk >= fs->sb->s_blocks_count)
232 + error_msg_and_die("Internal error, block out of range");
234 + curr = cache_find(&fs->blks, blk);
236 + bi = container_of(curr, blk_info, link);
241 + bi = malloc(sizeof(*bi));
243 + error_msg_and_die("get_blk: out of memory");
247 + bi->b = malloc(BLOCKSIZE);
249 + error_msg_and_die("get_blk: out of memory");
250 + cache_add(&fs->blks, &bi->link);
251 + if (fseeko(fs->f, ((off_t) blk) * BLOCKSIZE, SEEK_SET))
252 + perror_msg_and_die("fseek");
253 + if (fread(bi->b, BLOCKSIZE, 1, fs->f) != 1) {
255 + perror_msg_and_die("fread");
256 + memset(bi->b, 0, BLOCKSIZE);
265 put_blk(blk_info *bi)
267 + if (bi->usecount == 0)
268 + error_msg_and_die("Internal error: put_blk usecount zero");
270 + if (bi->usecount == 0)
271 + /* Free happens in the cache code */
272 + cache_item_set_unused(&bi->fs->blks, &bi->link);
275 // Used by get_blkmap/put_blkmap to hold information about an block map
276 // owned by the user.
288 +#define MAX_FREE_CACHE_BLOCKMAPS 100
291 +blkmap_elem_val(cache_link *elem)
293 + blkmap_info *bmi = container_of(elem, blkmap_info, link);
298 +blkmap_freed(cache_link *elem)
300 + blkmap_info *bmi = container_of(elem, blkmap_info, link);
302 + if (bmi->fs->swapit)
303 + swap_block(bmi->b);
308 // Return a given block map from a filesystem. Make sure to call
309 // put_blkmap when you are done with it.
310 static inline uint32 *
311 get_blkmap(filesystem *fs, uint32 blk, blkmap_info **rbmi)
316 + curr = cache_find(&fs->blkmaps, blk);
318 + bmi = container_of(curr, blkmap_info, link);
323 bmi = malloc(sizeof(*bmi));
325 error_msg_and_die("get_blkmap: out of memory");
328 bmi->b = get_blk(fs, blk, &bmi->bi);
329 - if (bmi->fs->swapit)
331 + cache_add(&fs->blkmaps, &bmi->link);
337 return (uint32 *) bmi->b;
339 @@ -894,42 +1006,83 @@ get_blkmap(filesystem *fs, uint32 blk, blkmap_info **rbmi)
341 put_blkmap(blkmap_info *bmi)
343 - if (bmi->fs->swapit)
344 - swap_block(bmi->b);
347 + if (bmi->usecount == 0)
348 + error_msg_and_die("Internal error: put_blkmap usecount zero");
351 + if (bmi->usecount == 0)
352 + /* Free happens in the cache code */
353 + cache_item_set_unused(&bmi->fs->blkmaps, &bmi->link);
356 // Used by get_nod/put_nod to hold information about an inode owned
370 +#define MAX_FREE_CACHE_INODES 100
373 +inode_elem_val(cache_link *elem)
375 + nod_info *ni = container_of(elem, nod_info, link);
380 +inode_freed(cache_link *elem)
382 + nod_info *ni = container_of(elem, nod_info, link);
384 + if (ni->fs->swapit)
385 + swap_nod(ni->itab);
390 // Return a given inode from a filesystem. Make sure to call put_nod()
391 // when you are done with the inode.
392 static inline inode *
393 get_nod(filesystem *fs, uint32 nod, nod_info **rni)
395 int grp, offset, boffset;
400 - offset = GRP_IBM_OFFSET(fs,nod) - 1;
401 - boffset = offset / (BLOCKSIZE / sizeof(inode));
402 - offset %= BLOCKSIZE / sizeof(inode);
403 - grp = GRP_GROUP_OF_INODE(fs,nod);
404 + curr = cache_find(&fs->inodes, nod);
406 + ni = container_of(curr, nod_info, link);
411 ni = malloc(sizeof(*ni));
413 error_msg_and_die("get_nod: out of memory");
415 - b = get_blk(fs, fs->gd[grp].bg_inode_table + boffset, &ni->bi);
416 - ni->itab = ((inode *) b) + offset;
419 + cache_add(&fs->inodes, &ni->link);
421 + offset = GRP_IBM_OFFSET(fs, nod) - 1;
422 + boffset = offset / (BLOCKSIZE / sizeof(inode));
423 + offset %= BLOCKSIZE / sizeof(inode);
424 + grp = GRP_GROUP_OF_INODE(fs,nod);
425 + ni->b = get_blk(fs, fs->gd[grp].bg_inode_table + boffset, &ni->bi);
426 + ni->itab = ((inode *) ni->b) + offset;
434 @@ -937,10 +1090,13 @@ get_nod(filesystem *fs, uint32 nod, nod_info **rni)
436 put_nod(nod_info *ni)
438 - if (ni->fs->swapit)
439 - swap_nod(ni->itab);
442 + if (ni->usecount == 0)
443 + error_msg_and_die("Internal error: put_nod usecount zero");
446 + if (ni->usecount == 0)
447 + /* Free happens in the cache code */
448 + cache_item_set_unused(&ni->fs->inodes, &ni->link);
451 // Used to hold state information while walking a directory inode.
452 @@ -2090,40 +2246,61 @@ add2fs_from_dir(filesystem *fs, uint32 this_nod, int squash_uids, int squash_per
456 -// endianness swap of the whole filesystem
458 -swap_goodfs(filesystem *fs)
459 +swap_gds(filesystem *fs)
463 for(i=0;i<GRP_NBGROUPS(fs);i++)
464 swap_gd(&(fs->gd[i]));
468 +// Copy size blocks from src to dst, putting holes in the output
469 +// file (if possible) if the input block is all zeros.
471 -swap_badfs(filesystem *fs)
472 +copy_file(filesystem *fs, FILE *dst, FILE *src, size_t size)
476 - for(i=0;i<GRP_NBGROUPS(fs);i++)
477 - swap_gd(&(fs->gd[i]));
480 + b = malloc(BLOCKSIZE);
482 + error_msg_and_die("copy_file: out of memory");
483 + if (fseek(src, 0, SEEK_SET))
484 + perror_msg_and_die("fseek");
485 + if (ftruncate(fileno(dst), 0))
486 + perror_msg_and_die("copy_file: ftruncate");
488 + if (fread(b, BLOCKSIZE, 1, src) != 1)
489 + perror_msg_and_die("copy failed on read");
490 + if ((dst != stdout) && is_blk_empty(b)) {
491 + /* Empty block, just skip it */
492 + if (fseek(dst, BLOCKSIZE, SEEK_CUR))
493 + perror_msg_and_die("fseek");
495 + if (fwrite(b, BLOCKSIZE, 1, dst) != 1)
496 + perror_msg_and_die("copy failed on write");
502 // Allocate a new filesystem structure, allocate internal memory,
503 // and initialize the contents.
505 -alloc_fs(uint32 nbblocks, int swapit)
506 +alloc_fs(int swapit, char *fname, uint32 nbblocks, FILE *srcfile)
509 + struct stat srcstat, dststat;
511 fs = malloc(sizeof(*fs));
513 error_msg_and_die("not enough memory for filesystem");
514 memset(fs, 0, sizeof(*fs));
516 - if(!(fs->data = calloc(nbblocks, BLOCKSIZE)))
517 - error_msg_and_die("not enough memory for filesystem");
518 + cache_init(&fs->blks, MAX_FREE_CACHE_BLOCKS, blk_elem_val, blk_freed);
519 + cache_init(&fs->blkmaps, MAX_FREE_CACHE_BLOCKMAPS,
520 + blkmap_elem_val, blkmap_freed);
521 + cache_init(&fs->inodes, MAX_FREE_CACHE_INODES,
522 + inode_elem_val, inode_freed);
523 fs->hdlink_cnt = HDLINK_CNT;
524 fs->hdlinks.hdl = calloc(sizeof(struct hdlink_s), fs->hdlink_cnt);
525 if (!fs->hdlinks.hdl)
526 @@ -2131,12 +2308,44 @@ alloc_fs(uint32 nbblocks, int swapit)
527 fs->hdlinks.count = 0 ;
528 fs->sb = (superblock *) (fs->data + BLOCKSIZE);
529 fs->gd = (groupdescriptor *) (fs->sb + 1);
531 + if (strcmp(fname, "-") == 0)
533 + else if (srcfile) {
534 + if (fstat(fileno(srcfile), &srcstat))
535 + perror_msg_and_die("fstat srcfile");
536 + if (stat(fname, &dststat))
537 + perror_msg_and_die("stat-ing %s", fname);
538 + if (srcstat.st_ino == dststat.st_ino) {
539 + // source and destination are the same file, don't
540 + // truncate or copy, just use the file.
541 + fs->f = fopen(fname, "r+b");
543 + fs->f = fopen(fname, "w+b");
545 + copy_file(fs, fs->f, srcfile,
546 + nbblocks * BLOCKSIZE);
549 + fs->f = fopen(fname, "w+b");
551 + perror_msg_and_die("opening %s", fname);
555 +/* Make sure the output file is the right size */
557 +set_file_size(filesystem *fs)
559 + if (ftruncate(fileno(fs->f),
560 + ((off_t) fs->sb->s_blocks_count) * BLOCKSIZE))
561 + perror_msg_and_die("set_file_size: ftruncate");
564 // initialize an empty filesystem
566 -init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp, int swapit)
567 +init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes,
568 + uint32 fs_timestamp, int swapit, char *fname)
572 @@ -2184,10 +2393,16 @@ init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp
573 free_blocks = nbblocks - overhead_per_group*nbgroups - 1 /*boot block*/;
574 free_blocks_per_group = nbblocks_per_group - overhead_per_group;
576 - fs = alloc_fs(nbblocks, swapit);
577 + fs = alloc_fs(swapit, fname, nbblocks, NULL);
578 fs->nheadblocks = (((nbgroups * sizeof(groupdescriptor))
579 + sizeof(superblock) + (BLOCKSIZE - 1))
581 + fs->sb = (superblock *) malloc(BLOCKSIZE);
583 + error_msg_and_die("error allocating header memory");
584 + fs->gd = (groupdescriptor *) calloc(fs->nheadblocks - 1, BLOCKSIZE);
586 + error_msg_and_die("error allocating header memory");
588 // create the superblock for an empty filesystem
589 fs->sb->s_inodes_count = nbinodes_per_group * nbgroups;
590 @@ -2205,6 +2420,10 @@ init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp
591 fs->sb->s_magic = EXT2_MAGIC_NUMBER;
592 fs->sb->s_lastcheck = fs_timestamp;
594 + fs->sb->s_reserved[200] = 0;
598 // set up groupdescriptors
599 for(i=0, bbmpos=gdsz+2, ibmpos=bbmpos+1, itblpos=ibmpos+1;
601 @@ -2315,27 +2534,49 @@ init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp
603 // loads a filesystem from disk
605 -load_fs(FILE * fh, int swapit)
606 +load_fs(FILE * fh, int swapit, char *fname)
611 - if((fseek(fh, 0, SEEK_END) < 0) || ((ssize_t)(fssize = ftell(fh)) == -1))
613 + if((fseek(fh, 0, SEEK_END) < 0) || ((fssize = ftello(fh)) == -1))
614 perror_msg_and_die("input filesystem image");
616 - fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE;
617 + if ((fssize % BLOCKSIZE) != 0)
618 + error_msg_and_die("Input file not a multiple of block size");
619 + fssize /= BLOCKSIZE;
620 if(fssize < 16) // totally arbitrary
621 error_msg_and_die("too small filesystem");
622 - fs = alloc_fs(fssize, swapit);
623 - if(fread(fs->data, BLOCKSIZE, fssize, fh) != fssize)
624 - perror_msg_and_die("input filesystem image");
626 + fs = alloc_fs(swapit, fname, fssize, fh);
628 + /* Read and check the superblock, then read the superblock
629 + * and all the group descriptors */
630 + fs->sb = malloc(BLOCKSIZE);
632 + error_msg_and_die("error allocating header memory");
633 + if (fseek(fs->f, BLOCKSIZE, SEEK_SET))
634 + perror_msg_and_die("fseek");
635 + if (fread(fs->sb, BLOCKSIZE, 1, fs->f) != 1)
636 + perror_msg_and_die("fread filesystem image superblock");
640 if(fs->sb->s_rev_level || (fs->sb->s_magic != EXT2_MAGIC_NUMBER))
641 error_msg_and_die("not a suitable ext2 filesystem");
642 fs->nheadblocks = (((GRP_NBGROUPS(fs) * sizeof(groupdescriptor))
643 + sizeof(superblock) + (BLOCKSIZE - 1))
646 + fs->gd = calloc(fs->nheadblocks - 1, BLOCKSIZE);
648 + error_msg_and_die("error allocating header memory");
649 + if (fread(fs->gd, BLOCKSIZE, fs->nheadblocks - 1, fs->f)
650 + != (fs->nheadblocks - 1))
651 + perror_msg_and_die("fread filesystem image group descriptors");
660 @@ -2343,7 +2584,9 @@ static void
661 free_fs(filesystem *fs)
663 free(fs->hdlinks.hdl);
671 @@ -2631,16 +2874,30 @@ print_fs(filesystem *fs)
675 -dump_fs(filesystem *fs, FILE * fh, int swapit)
677 - uint32 nbblocks = fs->sb->s_blocks_count;
678 +finish_fs(filesystem *fs)
680 + if (cache_flush(&fs->inodes))
681 + error_msg_and_die("entry mismatch on inode cache flush");
682 + if (cache_flush(&fs->blkmaps))
683 + error_msg_and_die("entry mismatch on blockmap cache flush");
684 + if (cache_flush(&fs->blks))
685 + error_msg_and_die("entry mismatch on block cache flush");
686 fs->sb->s_reserved[200] = 0;
689 - if(fwrite(fs->data, BLOCKSIZE, nbblocks, fh) < nbblocks)
690 - perror_msg_and_die("output filesystem image");
697 + if (fseek(fs->f, BLOCKSIZE, SEEK_SET))
698 + perror_msg_and_die("fseek");
699 + if(fwrite(fs->sb, BLOCKSIZE, 1, fs->f) != 1)
700 + perror_msg_and_die("output filesystem superblock");
701 + if(fwrite(fs->gd, BLOCKSIZE, fs->nheadblocks - 1, fs->f)
702 + != (fs->nheadblocks - 1))
703 + perror_msg_and_die("output filesystem group descriptors");
711 @@ -2851,11 +3108,11 @@ main(int argc, char **argv)
712 if(strcmp(fsin, "-"))
714 FILE * fh = xfopen(fsin, "rb");
715 - fs = load_fs(fh, bigendian);
716 + fs = load_fs(fh, bigendian, fsout);
720 - fs = load_fs(stdin, bigendian);
721 + fs = load_fs(stdin, bigendian, fsout);
725 @@ -2886,7 +3143,7 @@ main(int argc, char **argv)
726 if(fs_timestamp == -1)
727 fs_timestamp = time(NULL);
728 fs = init_fs(nbblocks, nbinodes, nbresrvd, holes, fs_timestamp,
733 populate_fs(fs, dopt, didx, squash_uids, squash_perms, fs_timestamp, NULL);
734 @@ -2925,14 +3182,10 @@ main(int argc, char **argv)
735 flist_blocks(fs, nod, fh);
738 - if(strcmp(fsout, "-"))
740 - FILE * fh = xfopen(fsout, "wb");
741 - dump_fs(fs, fh, bigendian);
745 - dump_fs(fs, stdout, bigendian);
747 + if(strcmp(fsout, "-") == 0)
748 + copy_file(fs, stdout, fs->f, fs->sb->s_blocks_count);
753 diff --git a/list.h b/list.h
755 index 0000000..52bb181
763 +# include <stdlib.h>
764 +# include <stddef.h>
767 +# include <stdlib.h>
770 +# include <stddef.h>
775 +#define offsetof(st, m) \
776 + ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
779 +#define container_of(ptr, type, member) ({ \
780 + const typeof( ((type *)0)->member ) *__mptr = (ptr); \
781 + (type *)( (char *)__mptr - offsetof(type,member) );})
783 +typedef struct list_elem
785 + struct list_elem *next;
786 + struct list_elem *prev;
789 +static inline void list_init(list_elem *list)
795 +static inline void list_add_after(list_elem *pos, list_elem *elem)
797 + elem->next = pos->next;
799 + pos->next->prev = elem;
803 +static inline void list_add_before(list_elem *pos, list_elem *elem)
805 + elem->prev = pos->prev;
807 + pos->prev->next = elem;
811 +static inline void list_del(list_elem *elem)
813 + elem->next->prev = elem->prev;
814 + elem->prev->next = elem->next;
817 +static inline void list_item_init(list_elem *elem)
823 +static inline int list_empty(list_elem *elem)
825 + return elem->next == elem;
828 +#define list_for_each_elem(list, curr) \
829 + for ((curr) = (list)->next; (curr) != (list); (curr) = (curr)->next)
831 +#define list_for_each_elem_safe(list, curr, next) \
832 + for ((curr) = (list)->next, (next) = (curr)->next; \
833 + (curr) != (list); \
834 + (curr) = (next), (next) = (curr)->next)
836 +#endif /* __LIST_H__ */