summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Sumrall <ksumrall@android.com>2011-06-29 20:28:30 -0700
committerKen Sumrall <ksumrall@android.com>2011-06-29 20:28:30 -0700
commit107a9f161babc20daf915311146b0e864d3b4157 (patch)
treef9dbc434d9c73b0750da8895ca16ca40f364f15d
parent7e5ff13c55eb29748c07768bd7134819cbcbd4b0 (diff)
downloadextras-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.c17
-rw-r--r--ext4_utils/allocate.h1
-rw-r--r--ext4_utils/backed_block.c30
-rw-r--r--ext4_utils/backed_block.h5
-rw-r--r--ext4_utils/ext4_utils.c38
-rw-r--r--ext4_utils/ext4_utils.h1
-rw-r--r--ext4_utils/make_ext4fs.c16
-rw-r--r--ext4_utils/make_ext4fs.h2
-rw-r--r--ext4_utils/make_ext4fs_main.c10
-rw-r--r--ext4_utils/output_file.c111
-rw-r--r--ext4_utils/output_file.h1
-rw-r--r--ext4_utils/uuid.c3
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;