diff options
author | Ken Sumrall <ksumrall@android.com> | 2011-06-29 20:28:30 -0700 |
---|---|---|
committer | Ken Sumrall <ksumrall@android.com> | 2011-06-29 20:28:30 -0700 |
commit | 107a9f161babc20daf915311146b0e864d3b4157 (patch) | |
tree | f9dbc434d9c73b0750da8895ca16ca40f364f15d | |
parent | 7e5ff13c55eb29748c07768bd7134819cbcbd4b0 (diff) | |
download | extras-107a9f161babc20daf915311146b0e864d3b4157.tar.gz |
Bug fixes to make_ext4fs
Fix definition of uuid struct.
Properly set the block_group number in each backup copy of the superblock.
Adjust the info.total_inodes field after rounding up the inodes per block group.
Add the option -t to initialize all the inode tables. If also specified with
the -s option, use the CHUNK_TYPE_FILL sparse records to initialize them.
Change-Id: Idd8bcee1b9bde3e82ad8da89ef974fbc12d7a6c6
-rw-r--r-- | ext4_utils/allocate.c | 17 | ||||
-rw-r--r-- | ext4_utils/allocate.h | 1 | ||||
-rw-r--r-- | ext4_utils/backed_block.c | 30 | ||||
-rw-r--r-- | ext4_utils/backed_block.h | 5 | ||||
-rw-r--r-- | ext4_utils/ext4_utils.c | 38 | ||||
-rw-r--r-- | ext4_utils/ext4_utils.h | 1 | ||||
-rw-r--r-- | ext4_utils/make_ext4fs.c | 16 | ||||
-rw-r--r-- | ext4_utils/make_ext4fs.h | 2 | ||||
-rw-r--r-- | ext4_utils/make_ext4fs_main.c | 10 | ||||
-rw-r--r-- | ext4_utils/output_file.c | 111 | ||||
-rw-r--r-- | ext4_utils/output_file.h | 1 | ||||
-rw-r--r-- | ext4_utils/uuid.c | 3 |
12 files changed, 221 insertions, 14 deletions
diff --git a/ext4_utils/allocate.c b/ext4_utils/allocate.c index 9377e3c1..0e162851 100644 --- a/ext4_utils/allocate.c +++ b/ext4_utils/allocate.c @@ -158,6 +158,23 @@ static void allocate_bg_inode_table(struct block_group_info *bg) * info.block_size, block); } +void init_unused_inode_tables(void) +{ + unsigned int i; + u32 block; + struct block_group_info *bg; + + for (i = 0; i < aux_info.groups; i++) { + if (!aux_info.bgs[i].inode_table) { + bg = &aux_info.bgs[i]; + block = bg->first_block + 2; + if (bg->has_superblock) + block += aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks + 1; + queue_fill_block(0, aux_info.inode_table_blocks * info.block_size, block); + } + } +} + static int bitmap_set_bit(u8 *bitmap, u32 bit) { if (bitmap[bit / 8] & 1 << (bit % 8)) diff --git a/ext4_utils/allocate.h b/ext4_utils/allocate.h index 16dc33c6..fb6e0f75 100644 --- a/ext4_utils/allocate.h +++ b/ext4_utils/allocate.h @@ -41,6 +41,7 @@ u32 get_free_inodes(u32 bg); u32 reserve_inodes(int bg, u32 inodes); void add_directory(u32 inode); u16 get_directories(int bg); +void init_unused_inode_tables(void); u32 allocate_inode(); void free_alloc(struct block_allocation *alloc); int reserve_oob_blocks(struct block_allocation *alloc, int blocks); diff --git a/ext4_utils/backed_block.c b/ext4_utils/backed_block.c index 473cce2a..f8399efc 100644 --- a/ext4_utils/backed_block.c +++ b/ext4_utils/backed_block.c @@ -26,6 +26,10 @@ struct data_block { const char *filename; off64_t offset; struct data_block *next; + u32 fill_val; + u8 fill; + u8 pad1; + u16 pad2; }; static struct data_block *data_blocks = NULL; @@ -66,6 +70,24 @@ static void queue_db(struct data_block *new_db) } } +/* Queues a fill block of memory to be written to the specified data blocks */ +void queue_fill_block(u32 fill_val, u32 len, u32 block) +{ + struct data_block *db = malloc(sizeof(struct data_block)); + if (db == NULL) + critical_error_errno("malloc"); + + db->block = block; + db->len = len; + db->fill = 1; + db->fill_val = fill_val; + db->data = NULL; + db->filename = NULL; + db->next = NULL; + + queue_db(db); +} + /* Queues a block of memory to be written to the specified data blocks */ void queue_data_block(u8 *data, u32 len, u32 block) { @@ -77,6 +99,7 @@ void queue_data_block(u8 *data, u32 len, u32 block) db->len = len; db->data = data; db->filename = NULL; + db->fill = 0; db->next = NULL; queue_db(db); @@ -94,6 +117,8 @@ void queue_data_file(const char *filename, off64_t offset, u32 len, db->len = len; db->filename = strdup(filename); db->offset = offset; + db->data = NULL; + db->fill = 0; db->next = NULL; queue_db(db); @@ -102,7 +127,8 @@ void queue_data_file(const char *filename, off64_t offset, u32 len, /* Iterates over the queued data blocks, calling data_func for each contiguous data block, and file_func for each contiguous file block */ void for_each_data_block(data_block_callback_t data_func, - data_block_file_callback_t file_func, void *priv) + data_block_file_callback_t file_func, + data_block_fill_callback_t fill_func, void *priv) { struct data_block *db; u32 last_block = 0; @@ -114,6 +140,8 @@ void for_each_data_block(data_block_callback_t data_func, if (db->filename) file_func(priv, (u64)db->block * info.block_size, db->filename, db->offset, db->len); + else if (db->fill) + fill_func(priv, (u64)db->block * info.block_size, db->fill_val, db->len); else data_func(priv, (u64)db->block * info.block_size, db->data, db->len); } diff --git a/ext4_utils/backed_block.h b/ext4_utils/backed_block.h index d131dc69..e3c4ac4a 100644 --- a/ext4_utils/backed_block.h +++ b/ext4_utils/backed_block.h @@ -21,15 +21,18 @@ #include "output_file.h" typedef void (*data_block_callback_t)(void *priv, u64 off, u8 *data, int len); +typedef void (*data_block_fill_callback_t)(void *priv, u64 off, u32 fill_val, int len); typedef void (*data_block_file_callback_t)(void *priv, u64 off, const char *file, off64_t offset, int len); void queue_data_block(u8 *data, u32 len, u32 block); +void queue_fill_block(u32 fill_val, u32 len, u32 block); void queue_data_file(const char *filename, off64_t offset, u32 len, u32 block); void for_each_data_block(data_block_callback_t data_func, - data_block_file_callback_t file_func, void *priv); + data_block_file_callback_t file_func, + data_block_fill_callback_t fill_func, void *priv); void free_data_blocks(); #endif diff --git a/ext4_utils/ext4_utils.c b/ext4_utils/ext4_utils.c index 5563acab..d41b92d5 100644 --- a/ext4_utils/ext4_utils.c +++ b/ext4_utils/ext4_utils.c @@ -89,6 +89,15 @@ void count_data_block(void *priv, u64 off, u8 *data, int len) count_chunks->chunks++; } +void count_fill_block(void *priv, u64 off, u32 fill_val, int len) +{ + struct count_chunks *count_chunks = priv; + if (off > count_chunks->cur_ptr) + count_chunks->chunks++; + count_chunks->cur_ptr = off + ALIGN(len, info.block_size); + count_chunks->chunks++; +} + void count_file_block(void *priv, u64 off, const char *file, off64_t offset, int len) { @@ -103,7 +112,7 @@ int count_sparse_chunks() { struct count_chunks count_chunks = {0, 0}; - for_each_data_block(count_data_block, count_file_block, &count_chunks); + for_each_data_block(count_data_block, count_file_block, count_fill_block, &count_chunks); if (count_chunks.cur_ptr != (u64) info.len) count_chunks.chunks++; @@ -115,6 +124,12 @@ static void ext4_write_data_block(void *priv, u64 off, u8 *data, int len) { write_data_block(priv, off, data, len); } + +static void ext4_write_fill_block(void *priv, u64 off, u32 fill_val, int len) +{ + write_fill_block(priv, off, fill_val, len); +} + static void ext4_write_data_file(void *priv, u64 off, const char *file, off64_t offset, int len) { @@ -132,7 +147,7 @@ void write_ext4_image(const char *filename, int gz, int sparse, int crc, if (!out) return; - for_each_data_block(ext4_write_data_block, ext4_write_data_file, out); + for_each_data_block(ext4_write_data_block, ext4_write_data_file, ext4_write_fill_block, out); pad_output_file(out, info.len); @@ -169,6 +184,9 @@ void ext4_create_fs_aux_info() } aux_info.sb = calloc(info.block_size, 1); + /* Alloc an array to hold the pointers to the backup superblocks */ + aux_info.backup_sb = calloc(aux_info.groups, sizeof(char *)); + if (!aux_info.sb) critical_error_errno("calloc"); @@ -179,6 +197,12 @@ void ext4_create_fs_aux_info() void ext4_free_fs_aux_info() { + unsigned int i; + + for (i=0; i<aux_info.groups; i++) { + if (aux_info.backup_sb[i]) + free(aux_info.backup_sb[i]); + } free(aux_info.sb); free(aux_info.bg_desc); } @@ -265,8 +289,14 @@ void ext4_fill_in_sb() info.blocks_per_group; u32 header_size = 0; if (ext4_bg_has_super_block(i)) { - if (i != 0) - queue_data_block((u8 *)sb, info.block_size, group_start_block); + if (i != 0) { + aux_info.backup_sb[i] = calloc(info.block_size, 1); + memcpy(aux_info.backup_sb[i], sb, info.block_size); + /* Update the block group nr of this backup superblock */ + aux_info.backup_sb[i]->s_block_group_nr = i; + queue_data_block((u8 *)aux_info.backup_sb[i], + info.block_size, group_start_block); + } queue_data_block((u8 *)aux_info.bg_desc, aux_info.bg_desc_blocks * info.block_size, group_start_block + 1); diff --git a/ext4_utils/ext4_utils.h b/ext4_utils/ext4_utils.h index 4518b98d..94f4bc9f 100644 --- a/ext4_utils/ext4_utils.h +++ b/ext4_utils/ext4_utils.h @@ -115,6 +115,7 @@ struct fs_info { struct fs_aux_info { struct ext4_super_block *sb; + struct ext4_super_block **backup_sb; struct ext2_group_desc *bg_desc; struct block_group_info *bgs; u32 first_data_block; diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c index 22c94244..298a02af 100644 --- a/ext4_utils/make_ext4fs.c +++ b/ext4_utils/make_ext4fs.c @@ -215,7 +215,14 @@ static u32 compute_inodes_per_group() u32 blocks = DIV_ROUND_UP(info.len, info.block_size); u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group); u32 inodes = DIV_ROUND_UP(info.inodes, block_groups); - return ALIGN(inodes, (info.block_size / info.inode_size)); + inodes = ALIGN(inodes, (info.block_size / info.inode_size)); + + /* After properly rounding up the number of inodes/group, + * make sure to update the total inodes field in the info struct. + */ + info.inodes = inodes * block_groups; + + return inodes; } static u32 compute_bg_desc_reserve_blocks() @@ -247,12 +254,12 @@ int make_ext4fs(const char *filename, s64 len) { reset_ext4fs_info(); info.len = len; - return make_ext4fs_internal(filename, NULL, NULL, 0, 0, 0, 0, 1); + return make_ext4fs_internal(filename, NULL, NULL, 0, 0, 0, 0, 1, 0); } int make_ext4fs_internal(const char *filename, const char *directory, char *mountpoint, int android, int gzip, int sparse, - int crc, int wipe) + int crc, int wipe, int init_itabs) { u32 root_inode_num; u16 root_mode; @@ -345,6 +352,9 @@ int make_ext4fs_internal(const char *filename, const char *directory, ext4_update_free(); + if (init_itabs) + init_unused_inode_tables(); + ext4_queue_sb(); printf("Created filesystem with %d/%d inodes and %d/%d blocks\n", diff --git a/ext4_utils/make_ext4fs.h b/ext4_utils/make_ext4fs.h index 3a26c3f5..adad58e5 100644 --- a/ext4_utils/make_ext4fs.h +++ b/ext4_utils/make_ext4fs.h @@ -24,6 +24,6 @@ void reset_ext4fs_info(); int make_ext4fs(const char *filename, s64 len); int make_ext4fs_internal(const char *filename, const char *directory, char *mountpoint, int android, int gzip, int sparse, - int crc, int wipe); + int crc, int wipe, int init_itabs); #endif diff --git a/ext4_utils/make_ext4fs_main.c b/ext4_utils/make_ext4fs_main.c index 8742e611..d616c6d4 100644 --- a/ext4_utils/make_ext4fs_main.c +++ b/ext4_utils/make_ext4fs_main.c @@ -33,7 +33,7 @@ static void usage(char *path) fprintf(stderr, "%s [ -l <len> ] [ -j <journal size> ] [ -b <block_size> ]\n", basename(path)); fprintf(stderr, " [ -g <blocks per group> ] [ -i <inodes> ] [ -I <inode size> ]\n"); fprintf(stderr, " [ -L <label> ] [ -f ] [ -a <android mountpoint> ]\n"); - fprintf(stderr, " [ -z | -s ] [ -J ]\n"); + fprintf(stderr, " [ -z | -s ] [ -t ] [ -w ] [ -c ] [ -J ]\n"); fprintf(stderr, " <filename> [<directory>]\n"); } @@ -48,8 +48,9 @@ int main(int argc, char **argv) int sparse = 0; int crc = 0; int wipe = 0; + int init_itabs = 0; - while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fwzJsc")) != -1) { + while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fwzJsct")) != -1) { switch (opt) { case 'l': info.len = parse_num(optarg); @@ -94,6 +95,9 @@ int main(int argc, char **argv) case 's': sparse = 1; break; + case 't': + init_itabs = 1; + break; default: /* '?' */ usage(argv[0]); exit(EXIT_FAILURE); @@ -136,5 +140,5 @@ int main(int argc, char **argv) } return make_ext4fs_internal(filename, directory, mountpoint, android, gzip, - sparse, crc, wipe); + sparse, crc, wipe, init_itabs); } diff --git a/ext4_utils/output_file.c b/ext4_utils/output_file.c index abe8414c..39a6007b 100644 --- a/ext4_utils/output_file.c +++ b/ext4_utils/output_file.c @@ -175,6 +175,79 @@ static int emit_skip_chunk(struct output_file *out, u64 skip_len) return 0; } +static int write_chunk_fill(struct output_file *out, u64 off, u32 fill_val, int len) +{ + chunk_header_t chunk_header; + int rnd_up_len, zero_len, count; + int ret; + unsigned int i; + u32 fill_buf[4096/sizeof(u32)]; /* Maximum size of a block */ + + /* We can assume that all the chunks to be written are in + * ascending order, block-size aligned, and non-overlapping. + * So, if the offset is less than the current output pointer, + * throw an error, and if there is a gap, emit a "don't care" + * chunk. The first write (of the super block) may not be + * blocksize aligned, so we need to deal with that too. + */ + //DBG printf("write chunk: offset 0x%llx, length 0x%x bytes\n", off, len); + + if (off < out->cur_out_ptr) { + error("offset %llu is less than the current output offset %llu", + off, out->cur_out_ptr); + return -1; + } + + if (off > out->cur_out_ptr) { + emit_skip_chunk(out, off - out->cur_out_ptr); + } + + if (off % info.block_size) { + error("write chunk offset %llu is not a multiple of the block size %u", + off, info.block_size); + return -1; + } + + if (off != out->cur_out_ptr) { + error("internal error, offset accounting screwy in write_chunk_raw()"); + return -1; + } + + /* Round up the file length to a multiple of the block size */ + rnd_up_len = (len + (info.block_size - 1)) & (~(info.block_size -1)); + + /* Finally we can safely emit a chunk of data */ + chunk_header.chunk_type = CHUNK_TYPE_FILL; + chunk_header.reserved1 = 0; + chunk_header.chunk_sz = rnd_up_len / info.block_size; + chunk_header.total_sz = CHUNK_HEADER_LEN + sizeof(fill_val); + ret = out->ops->write(out, (u8 *)&chunk_header, sizeof(chunk_header)); + + if (ret < 0) + return -1; + ret = out->ops->write(out, (u8 *)&fill_val, sizeof(fill_val)); + if (ret < 0) + return -1; + + if (out->use_crc) { + /* Initialize fill_buf with the fill_val */ + for (i = 0; i < (info.block_size / sizeof(u32)); i++) { + fill_buf[i] = fill_val; + } + + count = chunk_header.chunk_sz; + while (count) { + out->crc32 = sparse_crc32(out->crc32, fill_buf, info.block_size); + count--; + } + } + + out->cur_out_ptr += rnd_up_len; + out->chunk_cnt++; + + return 0; +} + static int write_chunk_raw(struct output_file *out, u64 off, u8 *data, int len) { chunk_header_t chunk_header; @@ -393,6 +466,44 @@ void write_data_block(struct output_file *out, u64 off, u8 *data, int len) } } +/* Write a contiguous region of data blocks with a fill value */ +void write_fill_block(struct output_file *out, u64 off, u32 fill_val, int len) +{ + int ret; + unsigned int i; + int write_len; + u32 fill_buf[4096/sizeof(u32)]; /* Maximum size of a block */ + + if (off + len > (u64) info.len) { + error("attempted to write block %llu past end of filesystem", + off + len - info.len); + return; + } + + if (out->sparse) { + write_chunk_fill(out, off, fill_val, len); + } else { + /* Initialize fill_buf with the fill_val */ + for (i = 0; i < sizeof(fill_buf)/sizeof(u32); i++) { + fill_buf[i] = fill_val; + } + + ret = out->ops->seek(out, off); + if (ret < 0) + return; + + while (len) { + write_len = (len > (int)sizeof(fill_buf) ? (int)sizeof(fill_buf) : len); + ret = out->ops->write(out, (u8 *)fill_buf, write_len); + if (ret < 0) { + return; + } else { + len -= write_len; + } + } + } +} + /* Write a contiguous region of data blocks from a file */ void write_data_file(struct output_file *out, u64 off, const char *file, off64_t offset, int len) diff --git a/ext4_utils/output_file.h b/ext4_utils/output_file.h index 7866c6a6..b4487066 100644 --- a/ext4_utils/output_file.h +++ b/ext4_utils/output_file.h @@ -22,6 +22,7 @@ struct output_file; struct output_file *open_output_file(const char *filename, int gz, int sparse, int chunks, int crc, int wipe); void write_data_block(struct output_file *out, u64 off, u8 *data, int len); +void write_fill_block(struct output_file *out, u64 off, u32 fill_val, int len); void write_data_file(struct output_file *out, u64 off, const char *file, off64_t offset, int len); void pad_output_file(struct output_file *out, u64 len); diff --git a/ext4_utils/uuid.c b/ext4_utils/uuid.c index ac9b518c..d518476a 100644 --- a/ext4_utils/uuid.c +++ b/ext4_utils/uuid.c @@ -21,9 +21,10 @@ #include "sha1.h" #include "uuid.h" +/* Definition from RFC-4122 */ struct uuid { u32 time_low; - u32 time_mid; + u16 time_mid; u16 time_hi_and_version; u8 clk_seq_hi_res; u8 clk_seq_low; |