ANDROID: Incremental fs: Change per UID timeouts to microseconds

Bug: 174495152
Test: incfs_test passes
Signed-off-by: Paul Lawrence <paullawrence@google.com>
Change-Id: Id76d2fec83a0eb7b70ad85f1fac81bf319563a66
This commit is contained in:
Paul Lawrence 2020-11-30 11:36:28 -08:00 committed by Alistair Delva
parent 6fb25c4252
commit 5ef8ab7172
6 changed files with 71 additions and 48 deletions

View File

@ -1005,9 +1005,25 @@ static void notify_pending_reads(struct mount_info *mi,
wake_up_all(&mi->mi_blocks_written_notif_wq); 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, static int wait_for_data_block(struct data_file *df, int block_index,
int min_time_ms, int min_pending_time_ms, u32 min_time_us, u32 min_pending_time_us,
int max_pending_time_ms, u32 max_pending_time_us,
struct data_file_block *res_block) struct data_file_block *res_block)
{ {
struct data_file_block block = {}; struct data_file_block block = {};
@ -1044,13 +1060,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 the block was found, just return it. No need to wait. */
if (is_data_block_present(&block)) { if (is_data_block_present(&block)) {
if (min_time_ms) if (min_time_us)
error = msleep_interruptible(min_time_ms); error = usleep_interruptible(min_time_us);
*res_block = block; *res_block = block;
return error; return error;
} else { } else {
/* If it's not found, create a pending read */ /* 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); read = add_pending_read(df, block_index);
if (!read) if (!read)
return -ENOMEM; return -ENOMEM;
@ -1060,14 +1076,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(); time = ktime_get_ns();
/* Wait for notifications about block's arrival */ /* Wait for notifications about block's arrival */
wait_res = wait_res =
wait_event_interruptible_timeout(segment->new_data_arrival_wq, wait_event_interruptible_timeout(segment->new_data_arrival_wq,
(is_read_done(read)), (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. */ /* Woke up, the pending read is no longer needed. */
remove_pending_read(df, read); remove_pending_read(df, read);
@ -1085,11 +1101,11 @@ static int wait_for_data_block(struct data_file *df, int block_index,
return wait_res; return wait_res;
} }
if (min_pending_time_ms) { if (min_pending_time_us) {
time = div_u64(ktime_get_ns() - time, 1000000); time = div_u64(ktime_get_ns() - time, 1000);
if (min_pending_time_ms > time) { if (min_pending_time_us > time) {
error = msleep_interruptible( error = usleep_interruptible(
min_pending_time_ms - time); min_pending_time_us - time);
if (error) if (error)
return error; return error;
} }
@ -1122,8 +1138,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, ssize_t incfs_read_data_file_block(struct mem_range dst, struct file *f,
int index, int min_time_ms, int index, u32 min_time_us,
int min_pending_time_ms, int max_pending_time_ms, u32 min_pending_time_us, u32 max_pending_time_us,
struct mem_range tmp) struct mem_range tmp)
{ {
loff_t pos; loff_t pos;
@ -1143,8 +1159,8 @@ ssize_t incfs_read_data_file_block(struct mem_range dst, struct file *f,
mi = df->df_mount_info; mi = df->df_mount_info;
bf = df->df_backing_file_context->bc_file; bf = df->df_backing_file_context->bc_file;
result = wait_for_data_block(df, index, min_time_ms, result = wait_for_data_block(df, index, min_time_us,
min_pending_time_ms, max_pending_time_ms, &block); min_pending_time_us, max_pending_time_us, &block);
if (result < 0) if (result < 0)
goto out; goto out;

View File

@ -335,8 +335,8 @@ struct dir_file *incfs_open_dir_file(struct mount_info *mi, struct file *bf);
void incfs_free_dir_file(struct dir_file *dir); void incfs_free_dir_file(struct dir_file *dir);
ssize_t incfs_read_data_file_block(struct mem_range dst, struct file *f, ssize_t incfs_read_data_file_block(struct mem_range dst, struct file *f,
int index, int min_time_ms, int index, u32 min_time_us,
int min_pending_time_ms, int max_pending_time_ms, u32 min_pending_time_us, u32 max_pending_time_us,
struct mem_range tmp); struct mem_range tmp);
int incfs_get_filled_blocks(struct data_file *df, int incfs_get_filled_blocks(struct data_file *df,

View File

@ -1018,7 +1018,7 @@ static long ioctl_set_read_timeouts(struct mount_info *mi, void __user *arg)
for (i = 0; i < size / sizeof(*buffer); ++i) { for (i = 0; i < size / sizeof(*buffer); ++i) {
struct incfs_per_uid_read_timeouts *t = &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; error = -EINVAL;
goto out; goto out;
} }

View File

@ -199,6 +199,8 @@ static int parse_options(struct mount_options *opts, char *str)
case Opt_read_timeout: case Opt_read_timeout:
if (match_int(&args[0], &value)) if (match_int(&args[0], &value))
return -EINVAL; return -EINVAL;
if (value > 3600000)
return -EINVAL;
opts->read_timeout_ms = value; opts->read_timeout_ms = value;
break; break;
case Opt_readahead_pages: case Opt_readahead_pages:
@ -408,9 +410,9 @@ static int read_single_page_timeouts(struct data_file *df, struct file *f,
struct mem_range tmp) struct mem_range tmp)
{ {
struct mount_info *mi = df->df_mount_info; struct mount_info *mi = df->df_mount_info;
u32 min_time_ms = 0; u32 min_time_us = 0;
u32 min_pending_time_ms = 0; u32 min_pending_time_us = 0;
u32 max_pending_time_ms = U32_MAX; u32 max_pending_time_us = U32_MAX;
int uid = current_uid().val; int uid = current_uid().val;
int i; int i;
@ -421,18 +423,23 @@ static int read_single_page_timeouts(struct data_file *df, struct file *f,
&mi->mi_per_uid_read_timeouts[i]; &mi->mi_per_uid_read_timeouts[i];
if(t->uid == uid) { if(t->uid == uid) {
min_time_ms = t->min_time_ms; min_time_us = t->min_time_us;
min_pending_time_ms = t->min_pending_time_ms; min_pending_time_us = t->min_pending_time_us;
max_pending_time_ms = t->max_pending_time_ms; max_pending_time_us = t->max_pending_time_us;
break; break;
} }
} }
spin_unlock(&mi->mi_per_uid_read_timeouts_lock); spin_unlock(&mi->mi_per_uid_read_timeouts_lock);
if (max_pending_time_ms == U32_MAX) if (max_pending_time_us == U32_MAX) {
max_pending_time_ms = mi->mi_options.read_timeout_ms; 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, 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); tmp);
} }

View File

@ -490,24 +490,24 @@ struct incfs_per_uid_read_timeouts {
__u32 uid; __u32 uid;
/* /*
* Min time to read any block. Note that this doesn't apply to reads * Min time in microseconds to read any block. Note that this doesn't
* which are satisfied from the page cache. * 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 * Min time in microseconds to satisfy a pending read. Any pending read
* pending read which is filled before this time will be delayed so * which is filled before this time will be delayed so that the total
* that the total read time >= this value. * 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. * Max time in microseconds to satisfy a pending read before the read
* If set to U32_MAX, defaults to mount options read_timeout_ms= * times out. If set to U32_MAX, defaults to mount options
* Must be >= min_pending_time_ms * read_timeout_ms * 1000. Must be >= min_pending_time_us
*/ */
__u32 max_pending_time_ms; __u32 max_pending_time_us;
}; };
/* /*

View File

@ -3358,9 +3358,9 @@ static int per_uid_read_timeouts_test(const char *mount_dir)
struct incfs_per_uid_read_timeouts purt_set[] = { struct incfs_per_uid_read_timeouts purt_set[] = {
{ {
.uid = 0, .uid = 0,
.min_time_ms = 1000, .min_time_us = 1000000,
.min_pending_time_ms = 2000, .min_pending_time_us = 2000000,
.max_pending_time_ms = 3000, .max_pending_time_us = 3000000,
}, },
}; };
struct incfs_set_read_timeouts_args srt = { struct incfs_set_read_timeouts_args srt = {
@ -3402,11 +3402,11 @@ static int per_uid_read_timeouts_test(const char *mount_dir)
TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_GET_READ_TIMEOUTS, &grt), 0); TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_GET_READ_TIMEOUTS, &grt), 0);
TESTEQUAL(grt.timeouts_array_size_out, sizeof(purt_get)); TESTEQUAL(grt.timeouts_array_size_out, sizeof(purt_get));
TESTEQUAL(purt_get[0].uid, purt_set[0].uid); TESTEQUAL(purt_get[0].uid, purt_set[0].uid);
TESTEQUAL(purt_get[0].min_time_ms, purt_set[0].min_time_ms); TESTEQUAL(purt_get[0].min_time_us, purt_set[0].min_time_us);
TESTEQUAL(purt_get[0].min_pending_time_ms, TESTEQUAL(purt_get[0].min_pending_time_us,
purt_set[0].min_pending_time_ms); purt_set[0].min_pending_time_us);
TESTEQUAL(purt_get[0].max_pending_time_ms, TESTEQUAL(purt_get[0].max_pending_time_us,
purt_set[0].max_pending_time_ms); purt_set[0].max_pending_time_us);
/* Still 1000 in UID 2 */ /* Still 1000 in UID 2 */
TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0); TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
@ -3421,7 +3421,7 @@ static int per_uid_read_timeouts_test(const char *mount_dir)
TESTEQUAL(is_close(&start, 1000), 0); TESTEQUAL(is_close(&start, 1000), 0);
/* Set it to default */ /* Set it to default */
purt_set[0].max_pending_time_ms = UINT32_MAX; purt_set[0].max_pending_time_us = UINT32_MAX;
TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_SET_READ_TIMEOUTS, &srt), 0); TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_SET_READ_TIMEOUTS, &srt), 0);
TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0); TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), -1); TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), -1);