ANDROID: Incremental fs: Use simple compression in log buffer
Bug: 154342202
Test: incfs_test passes
Signed-off-by: Paul Lawrence <paullawrence@google.com>
Change-Id: Ibcc641dd92596018c9f10b5bc7bd0db2642a80c7
(cherry picked from commit b6b4a3a404ccd9c62347e27c4fc7883d776c2cbb)
Git-commit: 9d7386aae2
Git-repo: https://android.googlesource.com/kernel/common/
Signed-off-by: Sayali Lokhande <sayalil@codeaurora.org>
This commit is contained in:
committed by
Blagovest Kolenichev
parent
e6d7f587cc
commit
3f85b643be
@@ -34,8 +34,7 @@ struct mount_info *incfs_alloc_mount_info(struct super_block *sb,
|
||||
mutex_init(&mi->mi_pending_reads_mutex);
|
||||
init_waitqueue_head(&mi->mi_pending_reads_notif_wq);
|
||||
init_waitqueue_head(&mi->mi_log.ml_notif_wq);
|
||||
rwlock_init(&mi->mi_log.rl_access_lock);
|
||||
spin_lock_init(&mi->mi_log.rl_logging_lock);
|
||||
spin_lock_init(&mi->mi_log.rl_lock);
|
||||
INIT_LIST_HEAD(&mi->mi_reads_list_head);
|
||||
|
||||
error = incfs_realloc_mount_info(mi, options);
|
||||
@@ -53,6 +52,7 @@ int incfs_realloc_mount_info(struct mount_info *mi,
|
||||
struct mount_options *options)
|
||||
{
|
||||
void *new_buffer = NULL;
|
||||
void *old_buffer;
|
||||
size_t new_buffer_size = 0;
|
||||
|
||||
if (options->read_log_pages != mi->mi_options.read_log_pages) {
|
||||
@@ -71,16 +71,18 @@ int incfs_realloc_mount_info(struct mount_info *mi,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
write_lock(&mi->mi_log.rl_access_lock);
|
||||
kfree(mi->mi_log.rl_ring_buf);
|
||||
WRITE_ONCE(mi->mi_log.rl_ring_buf, new_buffer);
|
||||
WRITE_ONCE(mi->mi_log.rl_size,
|
||||
new_buffer_size / sizeof(*mi->mi_log.rl_ring_buf));
|
||||
log_state = READ_ONCE(mi->mi_log.rl_state);
|
||||
log_state.generation_id++;
|
||||
log_state.next_index = log_state.current_pass_no = 0;
|
||||
WRITE_ONCE(mi->mi_log.rl_state, log_state);
|
||||
write_unlock(&mi->mi_log.rl_access_lock);
|
||||
spin_lock(&mi->mi_log.rl_lock);
|
||||
old_buffer = mi->mi_log.rl_ring_buf;
|
||||
mi->mi_log.rl_ring_buf = new_buffer;
|
||||
mi->mi_log.rl_size = new_buffer_size;
|
||||
log_state = (struct read_log_state){
|
||||
.generation_id = mi->mi_log.rl_head.generation_id + 1,
|
||||
};
|
||||
mi->mi_log.rl_head = log_state;
|
||||
mi->mi_log.rl_tail = log_state;
|
||||
spin_unlock(&mi->mi_log.rl_lock);
|
||||
|
||||
kfree(old_buffer);
|
||||
}
|
||||
|
||||
mi->mi_options = *options;
|
||||
@@ -246,37 +248,121 @@ static ssize_t decompress(struct mem_range src, struct mem_range dst)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void log_read_one_record(struct read_log *rl, struct read_log_state *rs)
|
||||
{
|
||||
union log_record *record =
|
||||
(union log_record *)((u8 *)rl->rl_ring_buf + rs->next_offset);
|
||||
size_t record_size;
|
||||
|
||||
switch (record->full_record.type) {
|
||||
case FULL:
|
||||
rs->base_record = record->full_record;
|
||||
record_size = sizeof(record->full_record);
|
||||
break;
|
||||
|
||||
case SAME_FILE:
|
||||
rs->base_record.block_index =
|
||||
record->same_file_record.block_index;
|
||||
rs->base_record.absolute_ts_us +=
|
||||
record->same_file_record.relative_ts_us;
|
||||
record_size = sizeof(record->same_file_record);
|
||||
break;
|
||||
|
||||
case SAME_FILE_NEXT_BLOCK:
|
||||
++rs->base_record.block_index;
|
||||
rs->base_record.absolute_ts_us +=
|
||||
record->same_file_next_block.relative_ts_us;
|
||||
record_size = sizeof(record->same_file_next_block);
|
||||
break;
|
||||
|
||||
case SAME_FILE_NEXT_BLOCK_SHORT:
|
||||
++rs->base_record.block_index;
|
||||
rs->base_record.absolute_ts_us +=
|
||||
record->same_file_next_block_short.relative_ts_us;
|
||||
record_size = sizeof(record->same_file_next_block_short);
|
||||
break;
|
||||
}
|
||||
|
||||
rs->next_offset += record_size;
|
||||
if (rs->next_offset > rl->rl_size - sizeof(*record)) {
|
||||
rs->next_offset = 0;
|
||||
++rs->current_pass_no;
|
||||
}
|
||||
++rs->current_record_no;
|
||||
}
|
||||
|
||||
static void log_block_read(struct mount_info *mi, incfs_uuid_t *id,
|
||||
int block_index, bool timed_out)
|
||||
int block_index)
|
||||
{
|
||||
struct read_log *log = &mi->mi_log;
|
||||
struct read_log_state state;
|
||||
struct read_log_state *head, *tail;
|
||||
s64 now_us = ktime_to_us(ktime_get());
|
||||
int rl_size;
|
||||
struct read_log_record record = {
|
||||
.file_id = *id,
|
||||
.block_index = block_index,
|
||||
.timed_out = timed_out,
|
||||
.timestamp_us = now_us
|
||||
};
|
||||
s64 relative_us;
|
||||
union log_record record;
|
||||
size_t record_size;
|
||||
|
||||
read_lock(&log->rl_access_lock);
|
||||
rl_size = READ_ONCE(log->rl_size);
|
||||
if (rl_size != 0) {
|
||||
spin_lock(&log->rl_logging_lock);
|
||||
state = READ_ONCE(log->rl_state);
|
||||
log->rl_ring_buf[state.next_index] = record;
|
||||
if (++state.next_index == rl_size) {
|
||||
state.next_index = 0;
|
||||
++state.current_pass_no;
|
||||
}
|
||||
WRITE_ONCE(log->rl_state, state);
|
||||
spin_unlock(&log->rl_logging_lock);
|
||||
spin_lock(&log->rl_lock);
|
||||
if (log->rl_size == 0) {
|
||||
spin_unlock(&log->rl_lock);
|
||||
return;
|
||||
}
|
||||
read_unlock(&log->rl_access_lock);
|
||||
|
||||
if (rl_size != 0)
|
||||
wake_up_all(&log->ml_notif_wq);
|
||||
head = &log->rl_head;
|
||||
tail = &log->rl_tail;
|
||||
relative_us = now_us - head->base_record.absolute_ts_us;
|
||||
|
||||
if (memcmp(id, &head->base_record.file_id, sizeof(incfs_uuid_t)) ||
|
||||
relative_us >= 1ll << 32) {
|
||||
record.full_record = (struct full_record){
|
||||
.type = FULL,
|
||||
.block_index = block_index,
|
||||
.file_id = *id,
|
||||
.absolute_ts_us = now_us,
|
||||
};
|
||||
record_size = sizeof(struct full_record);
|
||||
} else if (block_index != head->base_record.block_index + 1 ||
|
||||
relative_us >= 1 << 30) {
|
||||
record.same_file_record = (struct same_file_record){
|
||||
.type = SAME_FILE,
|
||||
.block_index = block_index,
|
||||
.relative_ts_us = relative_us,
|
||||
};
|
||||
record_size = sizeof(struct same_file_record);
|
||||
} else if (relative_us >= 1 << 14) {
|
||||
record.same_file_next_block = (struct same_file_next_block){
|
||||
.type = SAME_FILE_NEXT_BLOCK,
|
||||
.relative_ts_us = relative_us,
|
||||
};
|
||||
record_size = sizeof(struct same_file_next_block);
|
||||
} else {
|
||||
record.same_file_next_block_short =
|
||||
(struct same_file_next_block_short){
|
||||
.type = SAME_FILE_NEXT_BLOCK_SHORT,
|
||||
.relative_ts_us = relative_us,
|
||||
};
|
||||
record_size = sizeof(struct same_file_next_block_short);
|
||||
}
|
||||
|
||||
head->base_record.file_id = *id;
|
||||
head->base_record.block_index = block_index;
|
||||
head->base_record.absolute_ts_us = now_us;
|
||||
|
||||
/* Advance tail beyond area we are going to overwrite */
|
||||
while (tail->current_pass_no < head->current_pass_no &&
|
||||
tail->next_offset < head->next_offset + record_size)
|
||||
log_read_one_record(log, tail);
|
||||
|
||||
memcpy(((u8 *)log->rl_ring_buf) + head->next_offset, &record,
|
||||
record_size);
|
||||
head->next_offset += record_size;
|
||||
if (head->next_offset > log->rl_size - sizeof(record)) {
|
||||
head->next_offset = 0;
|
||||
++head->current_pass_no;
|
||||
}
|
||||
++head->current_record_no;
|
||||
|
||||
spin_unlock(&log->rl_lock);
|
||||
wake_up_all(&log->ml_notif_wq);
|
||||
}
|
||||
|
||||
static int validate_hash_tree(struct file *bf, struct data_file *df,
|
||||
@@ -708,8 +794,7 @@ static int wait_for_data_block(struct data_file *df, int block_index,
|
||||
mi = df->df_mount_info;
|
||||
|
||||
if (timeout_ms == 0) {
|
||||
log_block_read(mi, &df->df_id, block_index,
|
||||
true /*timed out*/);
|
||||
log_block_read(mi, &df->df_id, block_index);
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
@@ -728,8 +813,7 @@ static int wait_for_data_block(struct data_file *df, int block_index,
|
||||
|
||||
if (wait_res == 0) {
|
||||
/* Wait has timed out */
|
||||
log_block_read(mi, &df->df_id, block_index,
|
||||
true /*timed out*/);
|
||||
log_block_read(mi, &df->df_id, block_index);
|
||||
return -ETIME;
|
||||
}
|
||||
if (wait_res < 0) {
|
||||
@@ -825,7 +909,7 @@ ssize_t incfs_read_data_file_block(struct mem_range dst, struct data_file *df,
|
||||
}
|
||||
|
||||
if (result >= 0)
|
||||
log_block_read(mi, &df->df_id, index, false /*timed out*/);
|
||||
log_block_read(mi, &df->df_id, index);
|
||||
|
||||
out:
|
||||
return result;
|
||||
@@ -1195,49 +1279,29 @@ struct read_log_state incfs_get_log_state(struct mount_info *mi)
|
||||
struct read_log *log = &mi->mi_log;
|
||||
struct read_log_state result;
|
||||
|
||||
read_lock(&log->rl_access_lock);
|
||||
spin_lock(&log->rl_logging_lock);
|
||||
result = READ_ONCE(log->rl_state);
|
||||
spin_unlock(&log->rl_logging_lock);
|
||||
read_unlock(&log->rl_access_lock);
|
||||
spin_lock(&log->rl_lock);
|
||||
result = log->rl_head;
|
||||
spin_unlock(&log->rl_lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
static u64 calc_record_count(const struct read_log_state *state, int rl_size)
|
||||
{
|
||||
return state->current_pass_no * (u64)rl_size + state->next_index;
|
||||
}
|
||||
|
||||
int incfs_get_uncollected_logs_count(struct mount_info *mi,
|
||||
struct read_log_state state)
|
||||
const struct read_log_state *state)
|
||||
{
|
||||
struct read_log *log = &mi->mi_log;
|
||||
struct read_log_state rl_state;
|
||||
int rl_size;
|
||||
u64 count;
|
||||
u32 generation;
|
||||
u64 head_no, tail_no;
|
||||
|
||||
read_lock(&log->rl_access_lock);
|
||||
rl_size = READ_ONCE(log->rl_size);
|
||||
spin_lock(&log->rl_logging_lock);
|
||||
rl_state = READ_ONCE(log->rl_state);
|
||||
spin_unlock(&log->rl_logging_lock);
|
||||
read_unlock(&log->rl_access_lock);
|
||||
spin_lock(&log->rl_lock);
|
||||
tail_no = log->rl_tail.current_record_no;
|
||||
head_no = log->rl_head.current_record_no;
|
||||
generation = log->rl_head.generation_id;
|
||||
spin_unlock(&log->rl_lock);
|
||||
|
||||
count = calc_record_count(&rl_state, rl_size);
|
||||
if (rl_state.generation_id == state.generation_id)
|
||||
count -= calc_record_count(&state, rl_size);
|
||||
return min_t(int, count, rl_size);
|
||||
}
|
||||
|
||||
static void fill_pending_read_from_log_record(
|
||||
struct incfs_pending_read_info *dest, const struct read_log_record *src,
|
||||
struct read_log_state *state, u64 log_size)
|
||||
{
|
||||
dest->file_id = src->file_id;
|
||||
dest->block_index = src->block_index;
|
||||
dest->serial_number =
|
||||
state->current_pass_no * log_size + state->next_index;
|
||||
dest->timestamp_us = src->timestamp_us;
|
||||
if (generation != state->generation_id)
|
||||
return head_no - tail_no;
|
||||
else
|
||||
return head_no - max_t(u64, tail_no, state->current_record_no);
|
||||
}
|
||||
|
||||
int incfs_collect_logged_reads(struct mount_info *mi,
|
||||
@@ -1245,82 +1309,48 @@ int incfs_collect_logged_reads(struct mount_info *mi,
|
||||
struct incfs_pending_read_info *reads,
|
||||
int reads_size)
|
||||
{
|
||||
struct read_log *log = &mi->mi_log;
|
||||
struct read_log_state live_state;
|
||||
int dst_idx;
|
||||
int rl_size;
|
||||
int result = 0;
|
||||
u64 read_count;
|
||||
u64 written_count;
|
||||
struct read_log *log = &mi->mi_log;
|
||||
struct read_log_state *head, *tail;
|
||||
|
||||
read_lock(&log->rl_access_lock);
|
||||
spin_lock(&log->rl_lock);
|
||||
head = &log->rl_head;
|
||||
tail = &log->rl_tail;
|
||||
|
||||
rl_size = READ_ONCE(log->rl_size);
|
||||
spin_lock(&log->rl_logging_lock);
|
||||
live_state = READ_ONCE(log->rl_state);
|
||||
spin_unlock(&log->rl_logging_lock);
|
||||
|
||||
if (reader_state->generation_id != live_state.generation_id) {
|
||||
reader_state->generation_id = live_state.generation_id;
|
||||
reader_state->current_pass_no = reader_state->next_index = 0;
|
||||
}
|
||||
|
||||
read_count = calc_record_count(reader_state, rl_size);
|
||||
written_count = calc_record_count(&live_state, rl_size);
|
||||
if (read_count == written_count) {
|
||||
result = 0;
|
||||
goto out;
|
||||
}
|
||||
if (reader_state->next_index >= rl_size) {
|
||||
result = -ERANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (read_count > written_count) {
|
||||
/* This reader is somehow ahead of the writer. */
|
||||
pr_debug("incfs: Log reader is ahead of writer\n");
|
||||
*reader_state = live_state;
|
||||
}
|
||||
|
||||
if (written_count - read_count > rl_size) {
|
||||
/*
|
||||
* Reading pointer is too far behind,
|
||||
* start from the record following the write pointer.
|
||||
*/
|
||||
pr_debug(
|
||||
"incfs: read pointer is behind, moving: %u/%u -> %u/%u / %u\n",
|
||||
(u32)reader_state->next_index,
|
||||
(u32)reader_state->current_pass_no,
|
||||
(u32)live_state.next_index,
|
||||
(u32)live_state.current_pass_no - 1, (u32)rl_size);
|
||||
if (reader_state->generation_id != head->generation_id) {
|
||||
pr_debug("read ptr is wrong generation: %u/%u",
|
||||
reader_state->generation_id, head->generation_id);
|
||||
|
||||
*reader_state = (struct read_log_state){
|
||||
.next_index = live_state.next_index,
|
||||
.current_pass_no = live_state.current_pass_no - 1,
|
||||
.generation_id = head->generation_id,
|
||||
};
|
||||
}
|
||||
|
||||
if (reader_state->current_record_no < tail->current_record_no) {
|
||||
pr_debug("read ptr is behind, moving: %u/%u -> %u/%u\n",
|
||||
(u32)reader_state->next_offset,
|
||||
(u32)reader_state->current_pass_no,
|
||||
(u32)tail->next_offset, (u32)tail->current_pass_no);
|
||||
|
||||
*reader_state = *tail;
|
||||
}
|
||||
|
||||
for (dst_idx = 0; dst_idx < reads_size; dst_idx++) {
|
||||
if (reader_state->next_index == live_state.next_index &&
|
||||
reader_state->current_pass_no == live_state.current_pass_no)
|
||||
if (reader_state->current_record_no == head->current_record_no)
|
||||
break;
|
||||
|
||||
fill_pending_read_from_log_record(
|
||||
&reads[dst_idx],
|
||||
&log->rl_ring_buf[reader_state->next_index],
|
||||
reader_state, rl_size);
|
||||
log_read_one_record(log, reader_state);
|
||||
|
||||
reader_state->next_index++;
|
||||
if (reader_state->next_index == rl_size) {
|
||||
reader_state->next_index = 0;
|
||||
reader_state->current_pass_no++;
|
||||
}
|
||||
reads[dst_idx] = (struct incfs_pending_read_info){
|
||||
.file_id = reader_state->base_record.file_id,
|
||||
.block_index = reader_state->base_record.block_index,
|
||||
.serial_number = reader_state->current_record_no,
|
||||
.timestamp_us = reader_state->base_record.absolute_ts_us
|
||||
};
|
||||
}
|
||||
result = dst_idx;
|
||||
|
||||
out:
|
||||
read_unlock(&log->rl_access_lock);
|
||||
return result;
|
||||
spin_unlock(&log->rl_lock);
|
||||
return dst_idx;
|
||||
}
|
||||
|
||||
bool incfs_equal_ranges(struct mem_range lhs, struct mem_range rhs)
|
||||
|
||||
Reference in New Issue
Block a user