From 9cbdd375f644894add66ebdc3e790a56d54ee695 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Thu, 3 Sep 2020 13:40:25 -0700 Subject: [PATCH] ANDROID: Incremental fs: Fix filled block count from get filled blocks Bug: 165929150 Test: incfs_test passes Signed-off-by: Paul Lawrence Change-Id: I8845adcafcc3a3f01730e8b5534fb25ea3d551db --- fs/incfs/data_mgmt.c | 69 +++--- fs/incfs/data_mgmt.h | 19 +- fs/incfs/format.c | 9 - fs/incfs/format.h | 5 +- fs/incfs/pseudo_files.c | 7 +- fs/incfs/vfs.c | 45 +++- fs/incfs/vfs.h | 5 - .../selftests/filesystems/incfs/incfs_test.c | 230 +++++++++++++++--- 8 files changed, 281 insertions(+), 108 deletions(-) diff --git a/fs/incfs/data_mgmt.c b/fs/incfs/data_mgmt.c index 35362d450d15..d8c02a413e44 100644 --- a/fs/incfs/data_mgmt.c +++ b/fs/incfs/data_mgmt.c @@ -686,36 +686,9 @@ static int copy_one_range(struct incfs_filled_range *range, void __user *buffer, return 0; } -static int update_file_header_flags(struct data_file *df, u32 bits_to_reset, - u32 bits_to_set) -{ - int result; - u32 new_flags; - struct backing_file_context *bfc; - - if (!df) - return -EFAULT; - bfc = df->df_backing_file_context; - if (!bfc) - return -EFAULT; - - result = mutex_lock_interruptible(&bfc->bc_mutex); - if (result) - return result; - - new_flags = (df->df_header_flags & ~bits_to_reset) | bits_to_set; - if (new_flags != df->df_header_flags) { - df->df_header_flags = new_flags; - result = incfs_write_file_header_flags(bfc, new_flags); - } - - mutex_unlock(&bfc->bc_mutex); - - return result; -} - #define READ_BLOCKMAP_ENTRIES 512 int incfs_get_filled_blocks(struct data_file *df, + struct incfs_file_data *fd, struct incfs_get_filled_blocks_args *arg) { int error = 0; @@ -729,6 +702,8 @@ int incfs_get_filled_blocks(struct data_file *df, int i = READ_BLOCKMAP_ENTRIES - 1; int entries_read = 0; struct incfs_blockmap_entry *bme; + int data_blocks_filled = 0; + int hash_blocks_filled = 0; *size_out = 0; if (end_index > df->df_total_block_count) @@ -736,7 +711,8 @@ int incfs_get_filled_blocks(struct data_file *df, arg->total_blocks_out = df->df_total_block_count; arg->data_blocks_out = df->df_data_block_count; - if (df->df_header_flags & INCFS_FILE_COMPLETE) { + if (atomic_read(&df->df_data_blocks_written) == + df->df_data_block_count) { pr_debug("File marked full, fast get_filled_blocks"); if (arg->start_index > end_index) { arg->index_out = arg->start_index; @@ -789,6 +765,12 @@ int incfs_get_filled_blocks(struct data_file *df, convert_data_file_block(bme + i, &dfb); + if (is_data_block_present(&dfb)) + if (arg->index_out >= df->df_data_block_count) + ++hash_blocks_filled; + else + ++data_blocks_filled; + if (is_data_block_present(&dfb) == in_range) continue; @@ -818,13 +800,28 @@ int incfs_get_filled_blocks(struct data_file *df, arg->index_out = range.begin; } - if (!error && in_range && arg->start_index == 0 && - end_index == df->df_total_block_count && - *size_out == sizeof(struct incfs_filled_range)) { - int result = - update_file_header_flags(df, 0, INCFS_FILE_COMPLETE); - /* Log failure only, since it's just a failed optimization */ - pr_debug("Marked file full with result %d", result); + if (arg->start_index == 0) { + fd->fd_get_block_pos = 0; + fd->fd_filled_data_blocks = 0; + fd->fd_filled_hash_blocks = 0; + } + + if (arg->start_index == fd->fd_get_block_pos) { + fd->fd_get_block_pos = arg->index_out + 1; + fd->fd_filled_data_blocks += data_blocks_filled; + fd->fd_filled_hash_blocks += hash_blocks_filled; + } + + if (fd->fd_get_block_pos == df->df_total_block_count + 1) { + if (fd->fd_filled_data_blocks > + atomic_read(&df->df_data_blocks_written)) + atomic_set(&df->df_data_blocks_written, + fd->fd_filled_data_blocks); + + if (fd->fd_filled_hash_blocks > + atomic_read(&df->df_hash_blocks_written)) + atomic_set(&df->df_hash_blocks_written, + fd->fd_filled_hash_blocks); } kfree(bme); diff --git a/fs/incfs/data_mgmt.h b/fs/incfs/data_mgmt.h index 1d8a0aec4330..a57ae4c9a31c 100644 --- a/fs/incfs/data_mgmt.h +++ b/fs/incfs/data_mgmt.h @@ -161,7 +161,6 @@ struct mount_info { /* Number of blocks written since mount */ atomic_t mi_blocks_written; - }; struct data_file_block { @@ -289,6 +288,23 @@ struct dentry_info { struct path backing_path; }; +enum FILL_PERMISSION { + CANT_FILL = 0, + CAN_FILL = 1, +}; + +struct incfs_file_data { + /* Does this file handle have INCFS_IOC_FILL_BLOCKS permission */ + enum FILL_PERMISSION fd_fill_permission; + + /* If INCFS_IOC_GET_FILLED_BLOCKS has been called, where are we */ + int fd_get_block_pos; + + /* And how many filled blocks are there up to that point */ + int fd_filled_data_blocks; + int fd_filled_hash_blocks; +}; + struct mount_info *incfs_alloc_mount_info(struct super_block *sb, struct mount_options *options, struct path *backing_dir_path); @@ -313,6 +329,7 @@ ssize_t incfs_read_data_file_block(struct mem_range dst, struct file *f, struct mem_range tmp); int incfs_get_filled_blocks(struct data_file *df, + struct incfs_file_data *fd, struct incfs_get_filled_blocks_args *arg); int incfs_read_file_signature(struct data_file *df, struct mem_range dst); diff --git a/fs/incfs/format.c b/fs/incfs/format.c index 37a41c8162de..691d7e474328 100644 --- a/fs/incfs/format.c +++ b/fs/incfs/format.c @@ -205,15 +205,6 @@ static int append_md_to_backing_file(struct backing_file_context *bfc, return result; } -int incfs_write_file_header_flags(struct backing_file_context *bfc, u32 flags) -{ - if (!bfc) - return -EFAULT; - - return write_to_bf(bfc, &flags, sizeof(flags), - offsetof(struct incfs_file_header, fh_flags)); -} - /* * Reserve 0-filled space for the blockmap body, and append * incfs_blockmap metadata record pointing to it. diff --git a/fs/incfs/format.h b/fs/incfs/format.h index fcff0f73e416..ba54bad0eea7 100644 --- a/fs/incfs/format.h +++ b/fs/incfs/format.h @@ -123,7 +123,6 @@ enum incfs_metadata_type { }; enum incfs_file_header_flags { - INCFS_FILE_COMPLETE = 1 << 0, INCFS_FILE_MAPPED = 1 << 1, }; @@ -254,7 +253,7 @@ struct incfs_status { __le32 is_hash_blocks_written; /* Number of hash blocks written */ __le32 is_dummy[6]; /* Spare fields */ -}; +} __packed; /* State of the backing file. */ struct backing_file_context { @@ -330,8 +329,6 @@ int incfs_write_status_to_backing_file(struct backing_file_context *bfc, u32 data_blocks_written, u32 hash_blocks_written); -int incfs_write_file_header_flags(struct backing_file_context *bfc, u32 flags); - int incfs_make_empty_backing_file(struct backing_file_context *bfc, incfs_uuid_t *uuid, u64 file_size); diff --git a/fs/incfs/pseudo_files.c b/fs/incfs/pseudo_files.c index ca8d1b206158..0993829cbe2d 100644 --- a/fs/incfs/pseudo_files.c +++ b/fs/incfs/pseudo_files.c @@ -274,6 +274,7 @@ static long ioctl_permit_fill(struct file *f, void __user *arg) struct incfs_permit_fill permit_fill; long error = 0; struct file *file = NULL; + struct incfs_file_data *fd; if (copy_from_user(&permit_fill, usr_permit_fill, sizeof(permit_fill))) return -EFAULT; @@ -292,9 +293,11 @@ static long ioctl_permit_fill(struct file *f, void __user *arg) goto out; } - switch ((uintptr_t)file->private_data) { + fd = file->private_data; + + switch (fd->fd_fill_permission) { case CANT_FILL: - file->private_data = (void *)CAN_FILL; + fd->fd_fill_permission = CAN_FILL; break; case CAN_FILL: diff --git a/fs/incfs/vfs.c b/fs/incfs/vfs.c index 99212a447ab4..89b9884cf02a 100644 --- a/fs/incfs/vfs.c +++ b/fs/incfs/vfs.c @@ -526,6 +526,7 @@ static long ioctl_fill_blocks(struct file *f, void __user *arg) struct incfs_fill_blocks fill_blocks; struct incfs_fill_block __user *usr_fill_block_array; struct data_file *df = get_incfs_data_file(f); + struct incfs_file_data *fd = f->private_data; const ssize_t data_buf_size = 2 * INCFS_DATA_FILE_BLOCK_SIZE; u8 *data_buf = NULL; ssize_t error = 0; @@ -534,7 +535,7 @@ static long ioctl_fill_blocks(struct file *f, void __user *arg) if (!df) return -EBADF; - if ((uintptr_t)f->private_data != CAN_FILL) + if (!fd || fd->fd_fill_permission != CAN_FILL) return -EPERM; if (copy_from_user(&fill_blocks, usr_fill_blocks, sizeof(fill_blocks))) @@ -643,18 +644,19 @@ static long ioctl_get_filled_blocks(struct file *f, void __user *arg) struct incfs_get_filled_blocks_args __user *args_usr_ptr = arg; struct incfs_get_filled_blocks_args args = {}; struct data_file *df = get_incfs_data_file(f); + struct incfs_file_data *fd = f->private_data; int error; - if (!df) + if (!df || !fd) return -EINVAL; - if ((uintptr_t)f->private_data != CAN_FILL) + if (fd->fd_fill_permission != CAN_FILL) return -EPERM; if (copy_from_user(&args, args_usr_ptr, sizeof(args)) > 0) return -EINVAL; - error = incfs_get_filled_blocks(df, &args); + error = incfs_get_filled_blocks(df, fd, &args); if (copy_to_user(args_usr_ptr, &args, sizeof(args))) return -EFAULT; @@ -1116,6 +1118,8 @@ static int file_open(struct inode *inode, struct file *file) int flags = O_NOATIME | O_LARGEFILE | (S_ISDIR(inode->i_mode) ? O_RDONLY : O_RDWR); + WARN_ON(file->private_data); + if (!mi) return -EBADF; @@ -1133,8 +1137,20 @@ static int file_open(struct inode *inode, struct file *file) } if (S_ISREG(inode->i_mode)) { + struct incfs_file_data *fd = kzalloc(sizeof(*fd), GFP_NOFS); + + if (!fd) { + err = -ENOMEM; + goto out; + } + + *fd = (struct incfs_file_data) { + .fd_fill_permission = CANT_FILL, + }; + file->private_data = fd; + err = make_inode_ready_for_data_ops(mi, inode, backing_file); - file->private_data = (void *)CANT_FILL; + } else if (S_ISDIR(inode->i_mode)) { struct dir_file *dir = NULL; @@ -1147,9 +1163,17 @@ static int file_open(struct inode *inode, struct file *file) err = -EBADF; out: - if (err) - pr_debug("incfs: %s name:%s err: %d\n", __func__, - file->f_path.dentry->d_name.name, err); + if (err) { + pr_debug("name:%s err: %d\n", + file->f_path.dentry->d_name.name, err); + if (S_ISREG(inode->i_mode)) + kfree(file->private_data); + else if (S_ISDIR(inode->i_mode)) + incfs_free_dir_file(file->private_data); + + file->private_data = NULL; + } + if (backing_file) fput(backing_file); return err; @@ -1158,9 +1182,8 @@ out: static int file_release(struct inode *inode, struct file *file) { if (S_ISREG(inode->i_mode)) { - /* Do nothing. - * data_file is released only by inode eviction. - */ + kfree(file->private_data); + file->private_data = NULL; } else if (S_ISDIR(inode->i_mode)) { struct dir_file *dir = get_incfs_dir_file(file); diff --git a/fs/incfs/vfs.h b/fs/incfs/vfs.h index d5dc5ebe99de..79fdf243733d 100644 --- a/fs/incfs/vfs.h +++ b/fs/incfs/vfs.h @@ -6,11 +6,6 @@ #ifndef _INCFS_VFS_H #define _INCFS_VFS_H -enum FILL_PERMISSION { - CANT_FILL = 0, - CAN_FILL = 1, -}; - extern const struct file_operations incfs_file_ops; extern const struct inode_operations incfs_file_inode_ops; diff --git a/tools/testing/selftests/filesystems/incfs/incfs_test.c b/tools/testing/selftests/filesystems/incfs/incfs_test.c index ed2e1c05f2ab..46f56556e8bf 100644 --- a/tools/testing/selftests/filesystems/incfs/incfs_test.c +++ b/tools/testing/selftests/filesystems/incfs/incfs_test.c @@ -33,6 +33,14 @@ #define INCFS_ROOT_INODE 0 +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define le16_to_cpu(x) (x) +#define le32_to_cpu(x) (x) +#define le64_to_cpu(x) (x) +#else +#error Big endian not supported! +#endif + struct hash_block { char data[INCFS_DATA_FILE_BLOCK_SIZE]; }; @@ -3026,11 +3034,14 @@ static const char v1_file[] = { #define TESTEQUAL(statement, res) \ TESTCOND((statement) == (res)) +#define TESTNE(statement, res) \ + TESTCOND((statement) != (res)) + static int compatibility_test(const char *mount_dir) { - char *backing_dir = NULL; static const char *name = "file"; int result = TEST_FAILURE; + char *backing_dir = NULL; char *filename = NULL; int fd = -1; uint64_t size = 0x0c; @@ -3056,51 +3067,167 @@ out: return result; } -static int validate_block_count(const char *mount_dir, struct test_file *file) +static int zero_blocks_written_count(int fd, uint32_t data_blocks_written, + uint32_t hash_blocks_written) { - int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; - char *filename = concat_file_name(mount_dir, file->name); - int fd; + int test_result = TEST_FAILURE; + uint64_t offset; + uint8_t type; + uint32_t bw; + + /* Get first md record */ + TESTEQUAL(pread(fd, &offset, sizeof(offset), 24), sizeof(offset)); + + /* Find status md record */ + for (;;) { + TESTNE(offset, 0); + TESTEQUAL(pread(fd, &type, sizeof(type), le64_to_cpu(offset)), + sizeof(type)); + if (type == 4) + break; + TESTEQUAL(pread(fd, &offset, sizeof(offset), + le64_to_cpu(offset) + 7), + sizeof(offset)); + } + + /* Read blocks_written */ + offset = le64_to_cpu(offset); + TESTEQUAL(pread(fd, &bw, sizeof(bw), offset + 23), sizeof(bw)); + TESTEQUAL(le32_to_cpu(bw), data_blocks_written); + TESTEQUAL(pread(fd, &bw, sizeof(bw), offset + 27), sizeof(bw)); + TESTEQUAL(le32_to_cpu(bw), hash_blocks_written); + + /* Write out zero */ + bw = 0; + TESTEQUAL(pwrite(fd, &bw, sizeof(bw), offset + 23), sizeof(bw)); + TESTEQUAL(pwrite(fd, &bw, sizeof(bw), offset + 27), sizeof(bw)); + + test_result = TEST_SUCCESS; +out: + return test_result; +} + +static int validate_block_count(const char *mount_dir, const char *backing_dir, + struct test_file *file, + int total_data_blocks, int filled_data_blocks, + int total_hash_blocks, int filled_hash_blocks) +{ + char *filename = NULL; + char *backing_filename = NULL; + int fd = -1; struct incfs_get_block_count_args bca = {}; int test_result = TEST_FAILURE; + struct incfs_filled_range ranges[128]; + struct incfs_get_filled_blocks_args fba = { + .range_buffer = ptr_to_u64(ranges), + .range_buffer_size = sizeof(ranges), + }; + int cmd_fd = -1; + struct incfs_permit_fill permit_fill; + + TEST(filename = concat_file_name(mount_dir, file->name), filename); + TEST(backing_filename = concat_file_name(backing_dir, file->name), + backing_filename); + TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1); + + TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0); + TESTEQUAL(bca.total_data_blocks_out, total_data_blocks); + TESTEQUAL(bca.filled_data_blocks_out, filled_data_blocks); + TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks); + TESTEQUAL(bca.filled_hash_blocks_out, filled_hash_blocks); + + close(fd); + TESTEQUAL(umount(mount_dir), 0); + TEST(fd = open(backing_filename, O_RDWR | O_CLOEXEC), fd != -1); + TESTEQUAL(zero_blocks_written_count(fd, filled_data_blocks, + filled_hash_blocks), + TEST_SUCCESS); + close(fd); + fd = -1; + TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false), + 0); + TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1); + + TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0); + TESTEQUAL(bca.total_data_blocks_out, total_data_blocks); + TESTEQUAL(bca.filled_data_blocks_out, 0); + TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks); + TESTEQUAL(bca.filled_hash_blocks_out, 0); + + TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1); + permit_fill.file_descriptor = fd; + TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_PERMIT_FILL, &permit_fill), 0); + do { + ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba); + fba.start_index = fba.index_out + 1; + } while (fba.index_out < fba.total_blocks_out); + + TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0); + TESTEQUAL(bca.total_data_blocks_out, total_data_blocks); + TESTEQUAL(bca.filled_data_blocks_out, filled_data_blocks); + TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks); + TESTEQUAL(bca.filled_hash_blocks_out, filled_hash_blocks); + + test_result = TEST_SUCCESS; +out: + close(cmd_fd); + close(fd); + free(filename); + free(backing_filename); + return test_result; +} + + + +static int validate_data_block_count(const char *mount_dir, + const char *backing_dir, + struct test_file *file) +{ + const int total_data_blocks = 1 + (file->size - 1) / + INCFS_DATA_FILE_BLOCK_SIZE; + const int filled_data_blocks = (total_data_blocks + 1) / 2; + + int test_result = TEST_FAILURE; + char *filename = NULL; + int fd = -1; + struct incfs_get_block_count_args bca = {}; int i; + TEST(filename = concat_file_name(mount_dir, file->name), filename); TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1); TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0); - TESTEQUAL(bca.total_data_blocks_out, block_cnt); + TESTEQUAL(bca.total_data_blocks_out, total_data_blocks); TESTEQUAL(bca.filled_data_blocks_out, 0); TESTEQUAL(bca.total_hash_blocks_out, 0); TESTEQUAL(bca.filled_hash_blocks_out, 0); - for (i = 0; i < block_cnt; i += 2) + for (i = 0; i < total_data_blocks; i += 2) TESTEQUAL(emit_test_block(mount_dir, file, i), 0); TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0); - TESTEQUAL(bca.total_data_blocks_out, block_cnt); - TESTEQUAL(bca.filled_data_blocks_out, (block_cnt + 1) / 2); + TESTEQUAL(bca.total_data_blocks_out, total_data_blocks); + TESTEQUAL(bca.filled_data_blocks_out, filled_data_blocks); TESTEQUAL(bca.total_hash_blocks_out, 0); TESTEQUAL(bca.filled_hash_blocks_out, 0); - close(fd); - TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1); + fd = -1; - TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0); - TESTEQUAL(bca.total_data_blocks_out, block_cnt); - TESTEQUAL(bca.filled_data_blocks_out, (block_cnt + 1) / 2); - TESTEQUAL(bca.total_hash_blocks_out, 0); - TESTEQUAL(bca.filled_hash_blocks_out, 0); + TESTEQUAL(validate_block_count(mount_dir, backing_dir, file, + total_data_blocks, filled_data_blocks, + 0, 0), + 0); test_result = TEST_SUCCESS; out: - free(filename); close(fd); + free(filename); return test_result; } -static int block_count_test(const char *mount_dir) +static int data_block_count_test(const char *mount_dir) { - char *backing_dir; int result = TEST_FAILURE; + char *backing_dir; int cmd_fd = -1; int i; struct test_files_set test = get_test_files_set(); @@ -3109,15 +3236,19 @@ static int block_count_test(const char *mount_dir) TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false), 0); - TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1); - for (i = 0; i < test.files_count; ++i) { struct test_file *file = &test.files[i]; + TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1); TESTEQUAL(emit_file(cmd_fd, NULL, file->name, &file->id, - file->size, NULL), 0); + file->size, NULL), + 0); + close(cmd_fd); + cmd_fd = -1; - TESTEQUAL(validate_block_count(mount_dir, file), 0); + TESTEQUAL(validate_data_block_count(mount_dir, backing_dir, + file), + 0); } result = TEST_SUCCESS; @@ -3129,33 +3260,52 @@ out: } static int validate_hash_block_count(const char *mount_dir, + const char *backing_dir, struct test_file *file) { const int digest_size = SHA256_DIGEST_SIZE; const int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size; + const int total_data_blocks = 1 + (file->size - 1) / + INCFS_DATA_FILE_BLOCK_SIZE; int result = TEST_FAILURE; - int block_count = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; - int hash_block_count = block_count; - int total_hash_block_count = 0; + int hash_layer = total_data_blocks; + int total_hash_blocks = 0; + int filled_hash_blocks; char *filename = NULL; int fd = -1; struct incfs_get_block_count_args bca = {}; - while (hash_block_count > 1) { - hash_block_count = (hash_block_count + hash_per_block - 1) - / hash_per_block; - total_hash_block_count += hash_block_count; + while (hash_layer > 1) { + hash_layer = (hash_layer + hash_per_block - 1) / hash_per_block; + total_hash_blocks += hash_layer; } + filled_hash_blocks = total_hash_blocks > 1 ? 1 : 0; TEST(filename = concat_file_name(mount_dir, file->name), filename); TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1); + TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0); - TESTEQUAL(bca.total_data_blocks_out, block_count); + TESTEQUAL(bca.total_data_blocks_out, total_data_blocks); TESTEQUAL(bca.filled_data_blocks_out, 0); - TESTEQUAL(bca.total_hash_blocks_out, total_hash_block_count); - TESTEQUAL(bca.filled_hash_blocks_out, - total_hash_block_count > 1 ? 1 : 0); + TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks); + TESTEQUAL(bca.filled_hash_blocks_out, 0); + + TESTEQUAL(emit_partial_test_file_hash(mount_dir, file), 0); + + TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0); + TESTEQUAL(bca.total_data_blocks_out, total_data_blocks); + TESTEQUAL(bca.filled_data_blocks_out, 0); + TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks); + TESTEQUAL(bca.filled_hash_blocks_out, filled_hash_blocks); + close(fd); + fd = -1; + + if (filled_hash_blocks) + TESTEQUAL(validate_block_count(mount_dir, backing_dir, file, + total_data_blocks, 0, + total_hash_blocks, filled_hash_blocks), + 0); result = TEST_SUCCESS; out: @@ -3171,29 +3321,29 @@ static int hash_block_count_test(const char *mount_dir) int cmd_fd = -1; int i; struct test_files_set test = get_test_files_set(); - int fd = -1; TEST(backing_dir = create_backing_dir(mount_dir), backing_dir); TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false), 0); - TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1); for (i = 0; i < test.files_count; i++) { struct test_file *file = &test.files[i]; + TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1); TESTEQUAL(crypto_emit_file(cmd_fd, NULL, file->name, &file->id, file->size, file->root_hash, file->sig.add_data), 0); + close(cmd_fd); + cmd_fd = -1; - TESTEQUAL(emit_partial_test_file_hash(mount_dir, file), 0); - TESTEQUAL(validate_hash_block_count(mount_dir, &test.files[i]), + TESTEQUAL(validate_hash_block_count(mount_dir, backing_dir, + &test.files[i]), 0); } result = TEST_SUCCESS; out: - close(fd); close(cmd_fd); umount(mount_dir); free(backing_dir); @@ -3311,7 +3461,7 @@ int main(int argc, char *argv[]) MAKE_TEST(large_file_test), MAKE_TEST(mapped_file_test), MAKE_TEST(compatibility_test), - MAKE_TEST(block_count_test), + MAKE_TEST(data_block_count_test), MAKE_TEST(hash_block_count_test), }; #undef MAKE_TEST