diff options
| author | Carl Hetherington <cth@carlh.net> | 2021-03-12 23:24:01 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2021-03-12 23:24:01 +0100 |
| commit | 9d20ec504c40c79a63c3ffa14dc9152e0ba4ecae (patch) | |
| tree | 168fc18d9b06fe1bc07fadb180d19fb562a28b1d | |
| parent | 3601ea5bae9247add596e2c6920e80a236803964 (diff) | |
| parent | 51774b7c8dcb3968330b28d9368b1b959b873670 (diff) | |
Merge branch 'carl2-opt' into carl2
Apply various optimisations, tested only on macOS.
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | blockdev/linux/file_dev.c | 47 | ||||
| -rw-r--r-- | include/ext4_mkfs.h | 5 | ||||
| -rw-r--r-- | src/ext4_fs.c | 39 | ||||
| -rw-r--r-- | src/ext4_mkfs.c | 155 |
5 files changed, 105 insertions, 143 deletions
@@ -11,3 +11,5 @@ ext_images/ tags *~ +.ccls-cache + diff --git a/blockdev/linux/file_dev.c b/blockdev/linux/file_dev.c index fa29f30..4e4cc67 100644 --- a/blockdev/linux/file_dev.c +++ b/blockdev/linux/file_dev.c @@ -36,10 +36,13 @@ #include <stdio.h> #include <stdbool.h> #include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> #ifdef __APPLE__ #include <fcntl.h> #include <sys/disk.h> -#include <unistd.h> #include <stdlib.h> #include <sys/socket.h> #endif @@ -51,7 +54,7 @@ static const char *fname = "ext2"; #define EXT4_FILEDEV_BSIZE 512 /**@brief Image file descriptor.*/ -static FILE *dev_file; +static int dev_file; #define DROP_LINUXCACHE_BUFFERS 0 @@ -70,39 +73,37 @@ EXT4_BLOCKDEV_STATIC_INSTANCE(file_dev, EXT4_FILEDEV_BSIZE, 0, file_dev_open, /******************************************************************************/ static int file_dev_open(struct ext4_blockdev *bdev) { - dev_file = fopen(fname, "r+b"); + dev_file = open(fname, O_RDWR); - if (!dev_file) { - printf("fopen of %s failed %d\n", fname, errno); + if (dev_file < 0) { + printf("open of %s failed %d\n", fname, errno); return EIO; } - /*No buffering at file.*/ - setbuf(dev_file, 0); - #ifdef __APPLE__ - /* The fseek/ftell approach to finding the device's size does not seem + /* The lseek approach to finding the device's size does not seem * to work on macOS so do it this way instead. */ uint64_t sectors = 0; - if (ioctl(fileno(dev_file), DKIOCGETBLOCKCOUNT, §ors) < 0) { + if (ioctl(dev_file, DKIOCGETBLOCKCOUNT, §ors) < 0) { printf("ioctl DKIOCGETBLOCKCOUNT failed %d\n", errno); - fclose(dev_file); + close(dev_file); return EFAULT; } uint32_t sector_size = 0; - if (ioctl(fileno(dev_file), DKIOCGETBLOCKSIZE, §or_size) < 0) { + if (ioctl(dev_file, DKIOCGETBLOCKSIZE, §or_size) < 0) { printf("ioctl DKIOCGETBLOCKSIZE failed %d\n", errno); - fclose(dev_file); + close(dev_file); return EFAULT; } off_t size = sectors * sector_size; #else - if (fseeko(dev_file, 0, SEEK_END)) + off_t size = lseek(dev_file, 0, SEEK_END); + if (size == ((off_t) -1)) { return EFAULT; + } - off_t size = ftello(dev_file); #endif file_dev.part_offset = 0; @@ -117,14 +118,14 @@ static int file_dev_open(struct ext4_blockdev *bdev) static int file_dev_bread(struct ext4_blockdev *bdev, void *buf, uint64_t blk_id, uint32_t blk_cnt) { - if (fseeko(dev_file, blk_id * bdev->bdif->ph_bsize, SEEK_SET)) { - printf("fseeko failed %d\n", errno); + if (lseek(dev_file, blk_id * bdev->bdif->ph_bsize, SEEK_SET) < 0) { + printf("lseek failed %d\n", errno); return EIO; } if (!blk_cnt) return EOK; - if (!fread(buf, bdev->bdif->ph_bsize * blk_cnt, 1, dev_file)) { - printf("fread failed %d\n", errno); + if (read(dev_file, buf, bdev->bdif->ph_bsize * blk_cnt) < 0) { + printf("read failed %d\n", errno); return EIO; } @@ -148,14 +149,14 @@ static void drop_cache(void) static int file_dev_bwrite(struct ext4_blockdev *bdev, const void *buf, uint64_t blk_id, uint32_t blk_cnt) { - if (fseeko(dev_file, blk_id * bdev->bdif->ph_bsize, SEEK_SET)) { + if (lseek(dev_file, blk_id * bdev->bdif->ph_bsize, SEEK_SET) < 0) { printf("fseeko failed %d\n", errno); return EIO; } if (!blk_cnt) return EOK; - if (!fwrite(buf, bdev->bdif->ph_bsize * blk_cnt, 1, dev_file)) { - printf("fwrite failed %d\n", errno); + if (write(dev_file, buf, bdev->bdif->ph_bsize * blk_cnt) < 0) { + printf("write failed %d\n", errno); return EIO; } @@ -165,7 +166,7 @@ static int file_dev_bwrite(struct ext4_blockdev *bdev, const void *buf, /******************************************************************************/ static int file_dev_close(struct ext4_blockdev *bdev) { - fclose(dev_file); + close(dev_file); return EOK; } diff --git a/include/ext4_mkfs.h b/include/ext4_mkfs.h index 16a05f8..697d645 100644 --- a/include/ext4_mkfs.h +++ b/include/ext4_mkfs.h @@ -71,8 +71,11 @@ struct ext4_mkfs_info { int ext4_mkfs_read_info(struct ext4_blockdev *bd, struct ext4_mkfs_info *info); +/* Callback to report progress from 0 to 1 */ +typedef void (*ext4_progress)(void*, float); + int ext4_mkfs(struct ext4_fs *fs, struct ext4_blockdev *bd, - struct ext4_mkfs_info *info, int fs_type); + struct ext4_mkfs_info *info, int fs_type, ext4_progress progress, void* progress_context); #ifdef __cplusplus } diff --git a/src/ext4_fs.c b/src/ext4_fs.c index 8e229ef..bc19e7f 100644 --- a/src/ext4_fs.c +++ b/src/ext4_fs.c @@ -57,6 +57,7 @@ #include <ext4_extent.h> #include <string.h> +#include <stdlib.h> int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev, bool read_only) @@ -422,11 +423,12 @@ static int ext4_fs_init_inode_bitmap(struct ext4_block_group_ref *bg_ref) return ext4_block_set(bg_ref->fs->bdev, &b); } + /**@brief Initialize i-node table in block group. * @param bg_ref Reference to block group * @return Error code */ -static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref) +static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref, int lazy) { struct ext4_sblock *sb = &bg_ref->fs->sb; struct ext4_bgroup *bg = bg_ref->block_group; @@ -434,6 +436,7 @@ static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref) uint32_t inode_size = ext4_get16(sb, inode_size); uint32_t block_size = ext4_sb_get_block_size(sb); uint32_t inodes_per_block = block_size / inode_size; + uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group); uint32_t inodes_in_group = ext4_inodes_in_group_cnt(sb, bg_ref->index); uint32_t table_blocks = inodes_in_group / inodes_per_block; ext4_fsblk_t fblock; @@ -443,25 +446,15 @@ static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref) /* Compute initialization bounds */ ext4_fsblk_t first_block = ext4_bg_get_inode_table_first_block(bg, sb); - ext4_fsblk_t last_block = first_block + table_blocks - 1; - /* Initialization of all itable blocks */ - for (fblock = first_block; fblock <= last_block; ++fblock) { - struct ext4_block b; - int rc = ext4_trans_block_get_noread(bg_ref->fs->bdev, &b, fblock); - if (rc != EOK) - return rc; - - memset(b.data, 0, block_size); - ext4_trans_set_block_dirty(b.buf); - - rc = ext4_block_set(bg_ref->fs->bdev, &b); - if (rc != EOK) - return rc; + void* zeros = calloc(table_blocks, block_size); + if (!zeros) { + return ENOMEM; } - - return EOK; + int rc = ext4_block_writebytes(bg_ref->fs->bdev, first_block * block_size, zeros, table_blocks * block_size); + free(zeros); + return rc; } static ext4_fsblk_t ext4_fs_get_descriptor_block(struct ext4_sblock *s, @@ -617,13 +610,21 @@ int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid, ext4_bg_clear_flag(bg, EXT4_BLOCK_GROUP_INODE_UNINIT); if (!ext4_bg_has_flag(bg, EXT4_BLOCK_GROUP_ITABLE_ZEROED)) { - rc = ext4_fs_init_inode_table(ref); + /* mke2fs does not initialize inode table blocks to zero, + * unless explicitly set otherwise with the lazy_itable_init + * option being set to 0. It seems that if EXT4_BLOCK_GROUP_ITABLE_ZEROED + * is not set the kernel will zero out these blocks on the first + * mount. Zeroing the blocks takes a long time, so we'll try + * not doing it. + */ +#if 0 + rc = ext4_fs_init_inode_table(ref, lazy); if (rc != EOK) { ext4_block_set(fs->bdev, &ref->block); return rc; } - ext4_bg_set_flag(bg, EXT4_BLOCK_GROUP_ITABLE_ZEROED); +#endif } ref->dirty = true; diff --git a/src/ext4_mkfs.c b/src/ext4_mkfs.c index 0dfc91f..c6b8938 100644 --- a/src/ext4_mkfs.c +++ b/src/ext4_mkfs.c @@ -298,75 +298,39 @@ static void fill_sb(struct fs_aux_info *aux_info, struct ext4_mkfs_info *info) } -static int write_bgroup_block(struct ext4_blockdev *bd, - struct fs_aux_info *aux_info, - struct ext4_mkfs_info *info, - uint32_t blk) +static int write_bgroups(struct ext4_fs *fs, struct ext4_blockdev *bd, struct fs_aux_info *aux_info, + struct ext4_mkfs_info *info, ext4_progress progress, void* progress_context) { - int r = EOK; - uint32_t j; - struct ext4_block b; - + /* size of the group descriptor */ + uint32_t dsc_size = ext4_sb_get_desc_size(aux_info->sb); uint32_t block_size = ext4_sb_get_block_size(aux_info->sb); - for (j = 0; j < aux_info->groups; j++) { - uint64_t bg_start_block = aux_info->first_data_block + - j * info->blocks_per_group; - uint32_t blk_off = 0; - - blk_off += aux_info->bg_desc_blocks; - if (has_superblock(info, j)) { - bg_start_block++; - blk_off += info->bg_desc_reserve_blocks; - } - - uint64_t dsc_blk = bg_start_block + blk; + /* Calculate the group descriptors chunk that will be written to each block group */ - r = ext4_block_get_noread(bd, &b, dsc_blk); - if (r != EOK) - return r; - - memcpy(b.data, aux_info->bg_desc_blk, block_size); - - ext4_bcache_set_dirty(b.buf); - r = ext4_block_set(bd, &b); - if (r != EOK) - return r; + /* The whole set of group descriptors */ + void* all_bg_desc = ext4_calloc(1, aux_info->groups * dsc_size); + if (!all_bg_desc) { + return ENOMEM; } - return r; -} - -static int write_bgroups(struct ext4_blockdev *bd, struct fs_aux_info *aux_info, - struct ext4_mkfs_info *info) -{ - int r = EOK; - - struct ext4_block b; - struct ext4_bgroup *bg_desc; - - uint32_t i; uint32_t bg_free_blk = 0; uint64_t sb_free_blk = 0; - uint32_t block_size = ext4_sb_get_block_size(aux_info->sb); - uint32_t dsc_size = ext4_sb_get_desc_size(aux_info->sb); - uint32_t dsc_per_block = block_size / dsc_size; - uint32_t k = 0; - for (i = 0; i < aux_info->groups; i++) { + for (uint32_t i = 0; i < aux_info->groups; i++) { uint64_t bg_start_block = aux_info->first_data_block + aux_info->first_data_block + i * info->blocks_per_group; uint32_t blk_off = 0; - bg_desc = (void *)(aux_info->bg_desc_blk + k * dsc_size); + struct ext4_bgroup* bg_desc = (struct ext4_bgroup *) (((char *) all_bg_desc) + i * dsc_size); bg_free_blk = info->blocks_per_group - aux_info->inode_table_blocks; bg_free_blk -= 2; blk_off += aux_info->bg_desc_blocks; - if (i == (aux_info->groups - 1)) + if (i == (aux_info->groups - 1)) { bg_free_blk -= aux_info->first_data_block; + } if (has_superblock(info, i)) { bg_start_block++; @@ -398,37 +362,46 @@ static int write_bgroups(struct ext4_blockdev *bd, struct fs_aux_info *aux_info, EXT4_BLOCK_GROUP_INODE_UNINIT); sb_free_blk += bg_free_blk; + } - r = ext4_block_get_noread(bd, &b, bg_start_block + blk_off + 1); - if (r != EOK) - return r; - memset(b.data, 0, block_size); - ext4_bcache_set_dirty(b.buf); - r = ext4_block_set(bd, &b); - if (r != EOK) - return r; - r = ext4_block_get_noread(bd, &b, bg_start_block + blk_off + 2); - if (r != EOK) - return r; - memset(b.data, 0, block_size); - ext4_bcache_set_dirty(b.buf); - r = ext4_block_set(bd, &b); - if (r != EOK) - return r; + /* Write the block group headers */ - if (++k != dsc_per_block) - continue; + int r = EOK; - k = 0; - r = write_bgroup_block(bd, aux_info, info, i / dsc_per_block); - if (r != EOK) - return r; + for (uint32_t i = 0; i < aux_info->groups; i++) { + if (progress) { + progress(progress_context, (float) i / aux_info->groups); + } + + uint64_t bg_start_block = aux_info->first_data_block + + aux_info->first_data_block + i * info->blocks_per_group; + uint32_t blk_off = 0; + + if (has_superblock(info, i)) { + bg_start_block++; + blk_off += info->bg_desc_reserve_blocks; + } + /* Group descriptors */ + ext4_block_writebytes(bd, (bg_start_block + blk_off) * block_size, all_bg_desc, aux_info->groups * dsc_size); + + blk_off += aux_info->bg_desc_blocks; + + struct ext4_block_group_ref ref; + r = ext4_fs_get_block_group_ref(fs, i, &ref); + if (r != EOK) { + free(all_bg_desc); + break; + } + + r = ext4_fs_put_block_group_ref(&ref); + if (r != EOK) { + free(all_bg_desc); + break; + } } - r = write_bgroup_block(bd, aux_info, info, i / dsc_per_block); - if (r != EOK) - return r; + free(all_bg_desc); ext4_sb_set_free_blocks_cnt(aux_info->sb, sb_free_blk); return r; @@ -488,7 +461,7 @@ Finish: return r; } -static int mkfs_init(struct ext4_blockdev *bd, struct ext4_mkfs_info *info) +static int mkfs_init(struct ext4_fs *fs, struct ext4_blockdev *bd, struct ext4_mkfs_info *info, ext4_progress progress, void* progress_context) { int r; struct fs_aux_info aux_info; @@ -499,8 +472,9 @@ static int mkfs_init(struct ext4_blockdev *bd, struct ext4_mkfs_info *info) goto Finish; fill_sb(&aux_info, info); + memcpy(&fs->sb, aux_info.sb, sizeof(struct ext4_sblock)); - r = write_bgroups(bd, &aux_info, info); + r = write_bgroups(fs, bd, &aux_info, info, progress, progress_context); if (r != EOK) goto Finish; @@ -513,24 +487,6 @@ static int mkfs_init(struct ext4_blockdev *bd, struct ext4_mkfs_info *info) return r; } -static int init_bgs(struct ext4_fs *fs) -{ - int r = EOK; - struct ext4_block_group_ref ref; - uint32_t i; - uint32_t bg_count = ext4_block_group_cnt(&fs->sb); - for (i = 0; i < bg_count; ++i) { - r = ext4_fs_get_block_group_ref(fs, i, &ref); - if (r != EOK) - break; - - r = ext4_fs_put_block_group_ref(&ref); - if (r != EOK) - break; - } - return r; -} - static int alloc_inodes(struct ext4_fs *fs) { int r = EOK; @@ -699,7 +655,7 @@ static int create_journal_inode(struct ext4_fs *fs, } int ext4_mkfs(struct ext4_fs *fs, struct ext4_blockdev *bd, - struct ext4_mkfs_info *info, int fs_type) + struct ext4_mkfs_info *info, int fs_type, ext4_progress progress, void* progress_context) { int r; @@ -823,7 +779,10 @@ int ext4_mkfs(struct ext4_fs *fs, struct ext4_blockdev *bd, if (r != EOK) goto cache_fini; - r = mkfs_init(bd, info); + fs->bdev = bd; + fs->read_only = false; + + r = mkfs_init(fs, bd, info, progress, progress_context); if (r != EOK) goto cache_fini; @@ -831,10 +790,6 @@ int ext4_mkfs(struct ext4_fs *fs, struct ext4_blockdev *bd, if (r != EOK) goto cache_fini; - r = init_bgs(fs); - if (r != EOK) - goto fs_fini; - r = alloc_inodes(fs); if (r != EOK) goto fs_fini; |
