ANDROID: Incremental fs: Fix filled block count from get filled blocks
Bug: 165929150 Test: incfs_test passes Signed-off-by: Paul Lawrence <paullawrence@google.com> Change-Id: I8845adcafcc3a3f01730e8b5534fb25ea3d551db
This commit is contained in:
committed by
Alistair Delva
parent
ceed5e0251
commit
9cbdd375f6
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user