diff options
-rw-r--r-- | ext4_utils/ext4_sb.h | 3 | ||||
-rw-r--r-- | ext4_utils/ext4_utils.c | 77 | ||||
-rw-r--r-- | ext4_utils/ext4_utils.h | 4 | ||||
-rw-r--r-- | ext4_utils/make_ext4fs.c | 9 |
4 files changed, 73 insertions, 20 deletions
diff --git a/ext4_utils/ext4_sb.h b/ext4_utils/ext4_sb.h index 832fa333..159580da 100644 --- a/ext4_utils/ext4_sb.h +++ b/ext4_utils/ext4_sb.h @@ -25,6 +25,8 @@ extern "C" { #endif +#include <stdbool.h> + struct fs_info { int64_t len; /* If set to 0, ask the block device for the size, * if less than 0, reserve that much space at the @@ -41,6 +43,7 @@ struct fs_info { uint32_t bg_desc_reserve_blocks; const char *label; uint8_t no_journal; + bool block_device; /* target fd is a block device? */ }; int ext4_parse_sb(struct ext4_super_block *sb, struct fs_info *info); diff --git a/ext4_utils/ext4_utils.c b/ext4_utils/ext4_utils.c index 3b22b811..06392932 100644 --- a/ext4_utils/ext4_utils.c +++ b/ext4_utils/ext4_utils.c @@ -168,10 +168,31 @@ void write_sb(int fd, unsigned long long offset, struct ext4_super_block *sb) critical_error("failed to write all of superblock"); } +static void block_device_write_sb(int fd) +{ + unsigned long long offset; + u32 i; + + /* write out the backup superblocks */ + for (i = 1; i < aux_info.groups; i++) { + if (ext4_bg_has_super_block(i)) { + offset = info.block_size * (aux_info.first_data_block + + i * info.blocks_per_group); + write_sb(fd, offset, aux_info.backup_sb[i]); + } + } + + /* write out the primary superblock */ + write_sb(fd, 1024, aux_info.sb); +} + /* Write the filesystem image to a file */ void write_ext4_image(int fd, int gz, int sparse, int crc) { sparse_file_write(ext4_sparse_file, fd, gz, sparse, crc); + + if (info.block_device) + block_device_write_sb(fd); } /* Compute the rest of the parameters of the filesystem from the basic info */ @@ -203,7 +224,27 @@ void ext4_create_fs_aux_info() aux_info.len_blocks -= last_group_size; } - aux_info.sb = calloc(info.block_size, 1); + /* A zero-filled superblock to be written firstly to the block + * device to mark the file-system as invalid + */ + aux_info.sb_zero = calloc(1, info.block_size); + if (!aux_info.sb_zero) + critical_error_errno("calloc"); + + /* The write_data* functions expect only block aligned calls. + * This is not an issue, except when we write out the super + * block on a system with a block size > 1K. So, we need to + * deal with that here. + */ + aux_info.sb_block = calloc(1, info.block_size); + if (!aux_info.sb_block) + critical_error_errno("calloc"); + + if (info.block_size > 1024) + aux_info.sb = (struct ext4_super_block *)((char *)aux_info.sb_block + 1024); + else + aux_info.sb = aux_info.sb_block; + /* Alloc an array to hold the pointers to the backup superblocks */ aux_info.backup_sb = calloc(aux_info.groups, sizeof(char *)); @@ -224,7 +265,8 @@ void ext4_free_fs_aux_info() if (aux_info.backup_sb[i]) free(aux_info.backup_sb[i]); } - free(aux_info.sb); + free(aux_info.sb_block); + free(aux_info.sb_zero); free(aux_info.bg_desc); } @@ -324,8 +366,8 @@ void ext4_fill_in_sb(int real_uuid) 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; - sparse_file_add_data(ext4_sparse_file, aux_info.backup_sb[i], - info.block_size, group_start_block); + ext4_queue_sb(group_start_block, info.block_device ? + aux_info.sb_zero : aux_info.backup_sb[i]); } sparse_file_add_data(ext4_sparse_file, aux_info.bg_desc, aux_info.bg_desc_blocks * info.block_size, @@ -341,22 +383,23 @@ void ext4_fill_in_sb(int real_uuid) aux_info.bg_desc[i].bg_free_inodes_count = sb->s_inodes_per_group; aux_info.bg_desc[i].bg_used_dirs_count = 0; } + + /* Queue the primary superblock to be written out - if it's a block device, + * queue a zero-filled block first, the correct version of superblock will + * be written to the block device after all other blocks are written. + * + * The file-system on the block device will not be valid until the correct + * version of superblocks are written, this is to avoid the likelihood of a + * partially created file-system. + */ + ext4_queue_sb(aux_info.first_data_block, info.block_device ? + aux_info.sb_zero : aux_info.sb_block); } -void ext4_queue_sb(void) + +void ext4_queue_sb(u64 start_block, struct ext4_super_block *sb) { - /* The write_data* functions expect only block aligned calls. - * This is not an issue, except when we write out the super - * block on a system with a block size > 1K. So, we need to - * deal with that here. - */ - if (info.block_size > 1024) { - u8 *buf = calloc(info.block_size, 1); - memcpy(buf + 1024, (u8*)aux_info.sb, 1024); - sparse_file_add_data(ext4_sparse_file, buf, info.block_size, 0); - } else { - sparse_file_add_data(ext4_sparse_file, aux_info.sb, 1024, 1); - } + sparse_file_add_data(ext4_sparse_file, sb, info.block_size, start_block); } void ext4_parse_sb_info(struct ext4_super_block *sb) diff --git a/ext4_utils/ext4_utils.h b/ext4_utils/ext4_utils.h index ea954463..8cc8c2cb 100644 --- a/ext4_utils/ext4_utils.h +++ b/ext4_utils/ext4_utils.h @@ -99,6 +99,8 @@ struct ext2_group_desc { struct fs_aux_info { struct ext4_super_block *sb; + struct ext4_super_block *sb_block; + struct ext4_super_block *sb_zero; struct ext4_super_block **backup_sb; struct ext2_group_desc *bg_desc; struct block_group_info *bgs; @@ -142,7 +144,7 @@ void ext4_fill_in_sb(int real_uuid); void ext4_create_resize_inode(void); void ext4_create_journal_inode(void); void ext4_update_free(void); -void ext4_queue_sb(void); +void ext4_queue_sb(u64 start_block, struct ext4_super_block *sb); u64 get_block_device_size(int fd); int is_block_device_fd(int fd); u64 get_file_size(int fd); diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c index 5c9e2085..5bb1872c 100644 --- a/ext4_utils/make_ext4fs.c +++ b/ext4_utils/make_ext4fs.c @@ -503,6 +503,13 @@ int make_ext4fs_internal(int fd, const char *_directory, if (setjmp(setjmp_env)) return EXIT_FAILURE; /* Handle a call to longjmp() */ + info.block_device = is_block_device_fd(fd); + + if (info.block_device && (sparse || gzip || crc)) { + fprintf(stderr, "No sparse/gzip/crc allowed for block device\n"); + return EXIT_FAILURE; + } + if (_mountpoint == NULL) { mountpoint = strdup(""); } else { @@ -629,8 +636,6 @@ int make_ext4fs_internal(int fd, const char *_directory, ext4_update_free(); - ext4_queue_sb(); - if (block_list_file) { size_t dirlen = directory ? strlen(directory) : 0; struct block_allocation* p = get_saved_allocation_chain(); |