ANDROID: Incremental fs: Add INCFS_IOC_GET_FILLED_BLOCKS

Test: incfs_test passes
Bug: 151240628
Signed-off-by: Paul Lawrence <paullawrence@google.com>
Change-Id: I66d0ba1911adc5d68ed404585222e6a81a7eb94f
(cherry picked from commit 8d963bb24076b60cb2de0f2d49deaff1d52e8270)
Git-commit: 05cf04f60a
Git-repo: https://android.googlesource.com/kernel/common/
Signed-off-by: Sayali Lokhande <sayalil@codeaurora.org>
This commit is contained in:
Paul Lawrence
2020-03-18 09:28:29 -07:00
committed by Blagovest Kolenichev
parent 27681b2b59
commit c38495f0d8
7 changed files with 614 additions and 40 deletions

View File

@@ -118,8 +118,8 @@ struct data_file *incfs_open_data_file(struct mount_info *mi, struct file *bf)
error = mutex_lock_interruptible(&bfc->bc_mutex);
if (error)
goto out;
error = incfs_read_file_header(bfc, &df->df_metadata_off,
&df->df_id, &size);
error = incfs_read_file_header(bfc, &df->df_metadata_off, &df->df_id,
&size, &df->df_header_flags);
mutex_unlock(&bfc->bc_mutex);
if (error)
@@ -127,7 +127,7 @@ struct data_file *incfs_open_data_file(struct mount_info *mi, struct file *bf)
df->df_size = size;
if (size > 0)
df->df_block_count = get_blocks_count_for_size(size);
df->df_data_block_count = get_blocks_count_for_size(size);
md_records = incfs_scan_metadata_chain(df);
if (md_records < 0)
@@ -351,7 +351,7 @@ static int get_data_file_block(struct data_file *df, int index,
blockmap_off = df->df_blockmap_off;
bfc = df->df_backing_file_context;
if (index < 0 || index >= df->df_block_count || blockmap_off == 0)
if (index < 0 || blockmap_off == 0)
return -EINVAL;
error = incfs_read_blockmap_entry(bfc, index, blockmap_off, &bme);
@@ -371,6 +371,96 @@ static int get_data_file_block(struct data_file *df, int index,
return 0;
}
static int copy_one_range(struct incfs_filled_range *range, void __user *buffer,
u32 size, u32 *size_out)
{
if (*size_out + sizeof(*range) > size)
return -ERANGE;
if (copy_to_user(((char *)buffer) + *size_out, range, sizeof(*range)))
return -EFAULT;
*size_out += sizeof(*range);
return 0;
}
int incfs_get_filled_blocks(struct data_file *df,
struct incfs_get_filled_blocks_args *arg)
{
int error = 0;
bool in_range = false;
struct incfs_filled_range range;
void *buffer = u64_to_user_ptr(arg->range_buffer);
u32 size = arg->range_buffer_size;
u32 end_index =
arg->end_index ? arg->end_index : df->df_total_block_count;
u32 *size_out = &arg->range_buffer_size_out;
*size_out = 0;
if (end_index > df->df_total_block_count)
end_index = df->df_total_block_count;
arg->total_blocks_out = df->df_total_block_count;
if (df->df_header_flags & INCFS_FILE_COMPLETE) {
pr_debug("File marked full, fast get_filled_blocks");
if (arg->start_index > end_index) {
arg->index_out = arg->start_index;
return 0;
}
range = (struct incfs_filled_range){
.begin = arg->start_index,
.end = end_index,
};
arg->index_out = end_index;
return copy_one_range(&range, buffer, size, size_out);
}
for (arg->index_out = arg->start_index; arg->index_out < end_index;
++arg->index_out) {
struct data_file_block dfb;
error = get_data_file_block(df, arg->index_out, &dfb);
if (error)
break;
if (is_data_block_present(&dfb) == in_range)
continue;
if (!in_range) {
in_range = true;
range.begin = arg->index_out;
} else {
range.end = arg->index_out;
error = copy_one_range(&range, buffer, size, size_out);
if (error)
break;
in_range = false;
}
}
if (in_range) {
range.end = arg->index_out;
error = copy_one_range(&range, buffer, size, size_out);
}
if (!error && in_range && arg->start_index == 0 &&
end_index == df->df_total_block_count &&
*size_out == sizeof(struct incfs_filled_range)) {
int result;
df->df_header_flags |= INCFS_FILE_COMPLETE;
result = incfs_update_file_header_flags(
df->df_backing_file_context, df->df_header_flags);
/* Log failure only, since it's just a failed optimization */
pr_debug("Marked file full with result %d", result);
}
return error;
}
static bool is_read_done(struct pending_read *read)
{
return atomic_read_acquire(&read->done) != 0;
@@ -470,7 +560,7 @@ static int wait_for_data_block(struct data_file *df, int block_index,
if (!df || !res_block)
return -EFAULT;
if (block_index < 0 || block_index >= df->df_block_count)
if (block_index < 0 || block_index >= df->df_data_block_count)
return -EINVAL;
if (df->df_blockmap_off <= 0)
@@ -640,7 +730,7 @@ int incfs_process_new_data_block(struct data_file *df,
bfc = df->df_backing_file_context;
mi = df->df_mount_info;
if (block->block_index >= df->df_block_count)
if (block->block_index >= df->df_data_block_count)
return -ERANGE;
segment = get_file_segment(df, block->block_index);
@@ -746,7 +836,7 @@ int incfs_process_new_hash_block(struct data_file *df,
if (!error)
error = incfs_write_hash_block_to_backing_file(
bfc, range(data, block->data_len), block->block_index,
hash_area_base);
hash_area_base, df->df_blockmap_off, df->df_size);
mutex_unlock(&bfc->bc_mutex);
return error;
}
@@ -762,9 +852,10 @@ static int process_blockmap_md(struct incfs_blockmap *bm,
if (!df)
return -EFAULT;
if (df->df_block_count != block_count)
if (df->df_data_block_count > block_count)
return -EBADMSG;
df->df_total_block_count = block_count;
df->df_blockmap_off = base_off;
return error;
}
@@ -829,7 +920,7 @@ static int process_file_signature_md(struct incfs_file_signature *sg,
}
hash_tree = incfs_alloc_mtree(range(buf, signature->sig_size),
df->df_block_count);
df->df_data_block_count);
if (IS_ERR(hash_tree)) {
error = PTR_ERR(hash_tree);
hash_tree = NULL;
@@ -911,6 +1002,17 @@ int incfs_scan_metadata_chain(struct data_file *df)
result = records_count;
}
mutex_unlock(&bfc->bc_mutex);
if (df->df_hash_tree) {
int hash_block_count = get_blocks_count_for_size(
df->df_hash_tree->hash_tree_area_size);
if (df->df_data_block_count + hash_block_count !=
df->df_total_block_count)
result = -EINVAL;
} else if (df->df_data_block_count != df->df_total_block_count)
result = -EINVAL;
out:
kfree(handler);
return result;