From 80f43471ceb913040175b9d3d9a7e5ae04f3b59c Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Mon, 30 Nov 2020 11:36:28 -0800 Subject: [PATCH 21/31] ANDROID: Incremental fs: Change per UID timeouts to microseconds Bug: 174495152 Test: incfs_test passes Signed-off-by: Paul Lawrence Change-Id: I41c23d5f38adab35ee6fab25a6926a8a6aebe2e8 --- fs/incfs/data_mgmt.c | 48 ++++++++++++++++++++---------- fs/incfs/data_mgmt.h | 4 +-- fs/incfs/pseudo_files.c | 2 +- fs/incfs/vfs.c | 25 ++++++++++------ include/uapi/linux/incrementalfs.h | 22 +++++++------- 5 files changed, 62 insertions(+), 39 deletions(-) diff --git a/fs/incfs/data_mgmt.c b/fs/incfs/data_mgmt.c index 703cad49724e..52165f08f3a7 100644 --- a/fs/incfs/data_mgmt.c +++ b/fs/incfs/data_mgmt.c @@ -1071,9 +1071,25 @@ static void notify_pending_reads(struct mount_info *mi, wake_up_all(&mi->mi_blocks_written_notif_wq); } +static int usleep_interruptible(u32 us) +{ + /* See: + * https://www.kernel.org/doc/Documentation/timers/timers-howto.txt + * for explanation + */ + if (us < 10) { + udelay(us); + return 0; + } else if (us < 20000) { + usleep_range(us, us + us / 10); + return 0; + } else + return msleep_interruptible(us / 1000); +} + static int wait_for_data_block(struct data_file *df, int block_index, - int min_time_ms, int min_pending_time_ms, - int max_pending_time_ms, + u32 min_time_us, u32 min_pending_time_us, + u32 max_pending_time_us, struct data_file_block *res_block) { struct data_file_block block = {}; @@ -1110,13 +1126,13 @@ static int wait_for_data_block(struct data_file *df, int block_index, /* If the block was found, just return it. No need to wait. */ if (is_data_block_present(&block)) { - if (min_time_ms) - error = msleep_interruptible(min_time_ms); + if (min_time_us) + error = usleep_interruptible(min_time_us); *res_block = block; return error; } else { /* If it's not found, create a pending read */ - if (max_pending_time_ms != 0) { + if (max_pending_time_us != 0) { read = add_pending_read(df, block_index); if (!read) return -ENOMEM; @@ -1126,14 +1142,14 @@ static int wait_for_data_block(struct data_file *df, int block_index, } } - if (min_pending_time_ms) + if (min_pending_time_us) time = ktime_get_ns(); /* Wait for notifications about block's arrival */ wait_res = wait_event_interruptible_timeout(segment->new_data_arrival_wq, (is_read_done(read)), - msecs_to_jiffies(max_pending_time_ms)); + usecs_to_jiffies(max_pending_time_us)); /* Woke up, the pending read is no longer needed. */ remove_pending_read(df, read); @@ -1151,11 +1167,11 @@ static int wait_for_data_block(struct data_file *df, int block_index, return wait_res; } - if (min_pending_time_ms) { - time = div_u64(ktime_get_ns() - time, 1000000); - if (min_pending_time_ms > time) { - error = msleep_interruptible( - min_pending_time_ms - time); + if (min_pending_time_us) { + time = div_u64(ktime_get_ns() - time, 1000); + if (min_pending_time_us > time) { + error = usleep_interruptible( + min_pending_time_us - time); if (error) return error; } @@ -1188,8 +1204,8 @@ static int wait_for_data_block(struct data_file *df, int block_index, } ssize_t incfs_read_data_file_block(struct mem_range dst, struct file *f, - int index, int min_time_ms, - int min_pending_time_ms, int max_pending_time_ms, + int index, u32 min_time_us, + u32 min_pending_time_us, u32 max_pending_time_us, struct mem_range tmp) { loff_t pos; @@ -1209,8 +1225,8 @@ ssize_t incfs_read_data_file_block(struct mem_range dst, struct file *f, mi = df->df_mount_info; bf = df->df_backing_file_context->bc_file; - result = wait_for_data_block(df, index, min_time_ms, - min_pending_time_ms, max_pending_time_ms, &block); + result = wait_for_data_block(df, index, min_time_us, + min_pending_time_us, max_pending_time_us, &block); if (result < 0) goto out; diff --git a/fs/incfs/data_mgmt.h b/fs/incfs/data_mgmt.h index 4ed06dbb05aa..516e2e0dd5da 100644 --- a/fs/incfs/data_mgmt.h +++ b/fs/incfs/data_mgmt.h @@ -373,8 +373,8 @@ struct dir_file *incfs_open_dir_file(struct mount_info *mi, struct file *bf); void incfs_free_dir_file(struct dir_file *dir); ssize_t incfs_read_data_file_block(struct mem_range dst, struct file *f, - int index, int min_time_ms, - int min_pending_time_ms, int max_pending_time_ms, + int index, u32 min_time_us, + u32 min_pending_time_us, u32 max_pending_time_us, struct mem_range tmp); int incfs_get_filled_blocks(struct data_file *df, diff --git a/fs/incfs/pseudo_files.c b/fs/incfs/pseudo_files.c index 8d2e4a26792e..fd9e0581fe39 100644 --- a/fs/incfs/pseudo_files.c +++ b/fs/incfs/pseudo_files.c @@ -972,7 +972,7 @@ static long ioctl_set_read_timeouts(struct mount_info *mi, void __user *arg) for (i = 0; i < size / sizeof(*buffer); ++i) { struct incfs_per_uid_read_timeouts *t = &buffer[i]; - if (t->min_pending_time_ms > t->max_pending_time_ms) { + if (t->min_pending_time_us > t->max_pending_time_us) { error = -EINVAL; goto out; } diff --git a/fs/incfs/vfs.c b/fs/incfs/vfs.c index 00279ae04878..46dfabfebd52 100644 --- a/fs/incfs/vfs.c +++ b/fs/incfs/vfs.c @@ -239,6 +239,8 @@ static int parse_options(struct mount_options *opts, char *str) case Opt_read_timeout: if (match_int(&args[0], &value)) return -EINVAL; + if (value > 3600000) + return -EINVAL; opts->read_timeout_ms = value; break; case Opt_readahead_pages: @@ -458,9 +460,9 @@ static int read_single_page_timeouts(struct data_file *df, struct file *f, struct mem_range tmp) { struct mount_info *mi = df->df_mount_info; - u32 min_time_ms = 0; - u32 min_pending_time_ms = 0; - u32 max_pending_time_ms = U32_MAX; + u32 min_time_us = 0; + u32 min_pending_time_us = 0; + u32 max_pending_time_us = U32_MAX; int uid = current_uid().val; int i; @@ -471,18 +473,23 @@ static int read_single_page_timeouts(struct data_file *df, struct file *f, &mi->mi_per_uid_read_timeouts[i]; if(t->uid == uid) { - min_time_ms = t->min_time_ms; - min_pending_time_ms = t->min_pending_time_ms; - max_pending_time_ms = t->max_pending_time_ms; + min_time_us = t->min_time_us; + min_pending_time_us = t->min_pending_time_us; + max_pending_time_us = t->max_pending_time_us; break; } } spin_unlock(&mi->mi_per_uid_read_timeouts_lock); - if (max_pending_time_ms == U32_MAX) - max_pending_time_ms = mi->mi_options.read_timeout_ms; + if (max_pending_time_us == U32_MAX) { + u64 read_timeout_us = (u64)mi->mi_options.read_timeout_ms * + 1000; + + max_pending_time_us = read_timeout_us <= U32_MAX ? + read_timeout_us : U32_MAX; + } return incfs_read_data_file_block(range, f, block_index, - min_time_ms, min_pending_time_ms, max_pending_time_ms, + min_time_us, min_pending_time_us, max_pending_time_us, tmp); } diff --git a/include/uapi/linux/incrementalfs.h b/include/uapi/linux/incrementalfs.h index dae528d9d0c0..32fa517cd635 100644 --- a/include/uapi/linux/incrementalfs.h +++ b/include/uapi/linux/incrementalfs.h @@ -482,24 +482,24 @@ struct incfs_per_uid_read_timeouts { __u32 uid; /* - * Min time to read any block. Note that this doesn't apply to reads - * which are satisfied from the page cache. + * Min time in microseconds to read any block. Note that this doesn't + * apply to reads which are satisfied from the page cache. */ - __u32 min_time_ms; + __u32 min_time_us; /* - * Min time to satisfy a pending read. Must be >= min_time_ms. Any - * pending read which is filled before this time will be delayed so - * that the total read time >= this value. + * Min time in microseconds to satisfy a pending read. Any pending read + * which is filled before this time will be delayed so that the total + * read time >= this value. */ - __u32 min_pending_time_ms; + __u32 min_pending_time_us; /* - * Max time to satisfy a pending read before the read times out. - * If set to U32_MAX, defaults to mount options read_timeout_ms= - * Must be >= min_pending_time_ms + * Max time in microseconds to satisfy a pending read before the read + * times out. If set to U32_MAX, defaults to mount options + * read_timeout_ms * 1000. Must be >= min_pending_time_us */ - __u32 max_pending_time_ms; + __u32 max_pending_time_us; }; /* -- 2.17.1