summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2021-03-12 23:24:01 +0100
committerCarl Hetherington <cth@carlh.net>2021-03-12 23:24:01 +0100
commit9d20ec504c40c79a63c3ffa14dc9152e0ba4ecae (patch)
tree168fc18d9b06fe1bc07fadb180d19fb562a28b1d
parent3601ea5bae9247add596e2c6920e80a236803964 (diff)
parent51774b7c8dcb3968330b28d9368b1b959b873670 (diff)
Merge branch 'carl2-opt' into carl2
Apply various optimisations, tested only on macOS.
-rw-r--r--.gitignore2
-rw-r--r--blockdev/linux/file_dev.c47
-rw-r--r--include/ext4_mkfs.h5
-rw-r--r--src/ext4_fs.c39
-rw-r--r--src/ext4_mkfs.c155
5 files changed, 105 insertions, 143 deletions
diff --git a/.gitignore b/.gitignore
index c820e3f..ac36046 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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, &sectors) < 0) {
+ if (ioctl(dev_file, DKIOCGETBLOCKCOUNT, &sectors) < 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, &sector_size) < 0) {
+ if (ioctl(dev_file, DKIOCGETBLOCKSIZE, &sector_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;