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:
Paul Lawrence
2020-09-03 13:40:25 -07:00
committed by Alistair Delva
parent ceed5e0251
commit 9cbdd375f6
8 changed files with 281 additions and 108 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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.

View File

@@ -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);

View File

@@ -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:

View File

@@ -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);

View 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;

View File

@@ -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