From 29624453676b96b7b11de55cd16cf3fbb69f6f3c Mon Sep 17 00:00:00 2001 From: Yurii Zubrytskyi Date: Wed, 13 May 2020 17:04:44 -0700 Subject: [PATCH] ANDROID: Incremental fs: wake up log pollers less often Waking up the waiters accounts for 80+% of the total logging time, and about 40% of overall read_single_page() with no signature verification. By throttling it to once every 16ms we get back all read performance, reduce the waiter's CPU usage and still leave it enough time to pull the logs out. Bug: 155996534 Test: adb install megacity.apk & dd from the installed apk Signed-off-by: Yurii Zubrytskyi Signed-off-by: Paul Lawrence Change-Id: I4a118dc226d7ca318cf099ba3e239f0120bb23c2 --- fs/incfs/data_mgmt.c | 27 ++++++++++++++++++++++++--- fs/incfs/data_mgmt.h | 3 +++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/fs/incfs/data_mgmt.c b/fs/incfs/data_mgmt.c index 7e3205880010..bf34f57e27a2 100644 --- a/fs/incfs/data_mgmt.c +++ b/fs/incfs/data_mgmt.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,13 @@ #include "format.h" #include "integrity.h" +static void log_wake_up_all(struct work_struct *work) +{ + struct delayed_work *dw = container_of(work, struct delayed_work, work); + struct read_log *rl = container_of(dw, struct read_log, ml_wakeup_work); + wake_up_all(&rl->ml_notif_wq); +} + struct mount_info *incfs_alloc_mount_info(struct super_block *sb, struct mount_options *options, struct path *backing_dir_path) @@ -35,6 +43,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); + INIT_DELAYED_WORK(&mi->mi_log.ml_wakeup_work, log_wake_up_all); spin_lock_init(&mi->mi_log.rl_lock); INIT_LIST_HEAD(&mi->mi_reads_list_head); @@ -95,6 +104,8 @@ void incfs_free_mount_info(struct mount_info *mi) if (!mi) return; + flush_delayed_work(&mi->mi_log.ml_wakeup_work); + dput(mi->mi_index_dir); path_put(&mi->mi_backing_dir_path); mutex_destroy(&mi->mi_dir_struct_mutex); @@ -297,11 +308,20 @@ static void log_block_read(struct mount_info *mi, incfs_uuid_t *id, { struct read_log *log = &mi->mi_log; struct read_log_state *head, *tail; - s64 now_us = ktime_to_us(ktime_get()); + s64 now_us; s64 relative_us; union log_record record; size_t record_size; + /* + * This may read the old value, but it's OK to delay the logging start + * right after the configuration update. + */ + if (READ_ONCE(log->rl_size) == 0) + return; + + now_us = ktime_to_us(ktime_get()); + spin_lock(&log->rl_lock); if (log->rl_size == 0) { spin_unlock(&log->rl_lock); @@ -320,6 +340,7 @@ static void log_block_read(struct mount_info *mi, incfs_uuid_t *id, .file_id = *id, .absolute_ts_us = now_us, }; + head->base_record.file_id = *id; record_size = sizeof(struct full_record); } else if (block_index != head->base_record.block_index + 1 || relative_us >= 1 << 30) { @@ -344,7 +365,6 @@ static void log_block_read(struct mount_info *mi, incfs_uuid_t *id, 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; @@ -363,7 +383,8 @@ static void log_block_read(struct mount_info *mi, incfs_uuid_t *id, ++head->current_record_no; spin_unlock(&log->rl_lock); - wake_up_all(&log->ml_notif_wq); + if (schedule_delayed_work(&log->ml_wakeup_work, msecs_to_jiffies(16))) + pr_debug("incfs: scheduled a log pollers wakeup"); } static int validate_hash_tree(struct file *bf, struct data_file *df, diff --git a/fs/incfs/data_mgmt.h b/fs/incfs/data_mgmt.h index b7aecdd5bf4a..d9d9966b838a 100644 --- a/fs/incfs/data_mgmt.h +++ b/fs/incfs/data_mgmt.h @@ -89,6 +89,9 @@ struct read_log { /* A queue of waiters who want to be notified about reads */ wait_queue_head_t ml_notif_wq; + + /* A work item to wake up those waiters without slowing down readers */ + struct delayed_work ml_wakeup_work; }; struct mount_options {