summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext4_utils/ext4_sb.h3
-rw-r--r--ext4_utils/ext4_utils.c77
-rw-r--r--ext4_utils/ext4_utils.h4
-rw-r--r--ext4_utils/make_ext4fs.c9
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();