summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Lawrence <paullawrence@google.com>2021-04-19 14:09:01 -0700
committerPaul Lawrence <paullawrence@google.com>2021-04-22 16:33:00 +0000
commitc9a0b73d256d97a2f459d41ab66e66b91c72d99b (patch)
treedbc905b81c96ba8826a8e0d8bb8cf5fb041dba34
parent8f58eda4deac48c1156b75773aed700710b7dc82 (diff)
ANDROID: Incremental fs: Add INCFS_IOC_GET_LAST_READ_ERROR
Bug: 184291759 Test: incfs_test passes Signed-off-by: Paul Lawrence <paullawrence@google.com> Change-Id: If46e91f9c992337d53970573c238be965187761e
-rw-r--r--fs/incfs/data_mgmt.c24
-rw-r--r--fs/incfs/data_mgmt.h7
-rw-r--r--fs/incfs/pseudo_files.c24
-rw-r--r--include/uapi/linux/incrementalfs.h26
-rw-r--r--tools/testing/selftests/filesystems/incfs/incfs_test.c20
5 files changed, 101 insertions, 0 deletions
diff --git a/fs/incfs/data_mgmt.c b/fs/incfs/data_mgmt.c
index 8486b1624337..a330a9ec2cb4 100644
--- a/fs/incfs/data_mgmt.c
+++ b/fs/incfs/data_mgmt.c
@@ -73,6 +73,7 @@ struct mount_info *incfs_alloc_mount_info(struct super_block *sb,
spin_lock_init(&mi->mi_per_uid_read_timeouts_lock);
mutex_init(&mi->mi_zstd_workspace_mutex);
INIT_DELAYED_WORK(&mi->mi_zstd_cleanup_work, zstd_free_workspace);
+ mutex_init(&mi->mi_le_mutex);
node = incfs_add_sysfs_node(options->sysfs_name);
if (IS_ERR(node)) {
@@ -1246,6 +1247,27 @@ out:
return 0;
}
+static int incfs_update_sysfs_error(struct file *file, int index, int result,
+ struct mount_info *mi, struct data_file *df)
+{
+ int error;
+
+ if (result >= 0)
+ return 0;
+
+ error = mutex_lock_interruptible(&mi->mi_le_mutex);
+ if (error)
+ return error;
+
+ mi->mi_le_file_id = df->df_id;
+ mi->mi_le_time_us = ktime_to_us(ktime_get());
+ mi->mi_le_page = index;
+ mi->mi_le_errno = result;
+ mutex_unlock(&mi->mi_le_mutex);
+
+ return 0;
+}
+
ssize_t incfs_read_data_file_block(struct mem_range dst, struct file *f,
int index, struct mem_range tmp,
struct incfs_read_data_file_timeouts *timeouts)
@@ -1317,6 +1339,8 @@ out:
mi->mi_sysfs_node->isn_reads_failed_hash_verification++;
else if (result < 0)
mi->mi_sysfs_node->isn_reads_failed_other++;
+
+ incfs_update_sysfs_error(f, index, result, mi, df);
}
return result;
diff --git a/fs/incfs/data_mgmt.h b/fs/incfs/data_mgmt.h
index 7e80833ab42a..21458f2609c7 100644
--- a/fs/incfs/data_mgmt.h
+++ b/fs/incfs/data_mgmt.h
@@ -192,6 +192,13 @@ struct mount_info {
/* sysfs node */
struct incfs_sysfs_node *mi_sysfs_node;
+
+ /* Last error information */
+ struct mutex mi_le_mutex;
+ incfs_uuid_t mi_le_file_id;
+ u64 mi_le_time_us;
+ u32 mi_le_page;
+ u32 mi_le_errno;
};
struct data_file_block {
diff --git a/fs/incfs/pseudo_files.c b/fs/incfs/pseudo_files.c
index be5e2b91fec6..8c3980f83703 100644
--- a/fs/incfs/pseudo_files.c
+++ b/fs/incfs/pseudo_files.c
@@ -993,6 +993,28 @@ out:
return error;
}
+static long ioctl_get_last_read_error(struct mount_info *mi, void __user *arg)
+{
+ struct incfs_get_last_read_error_args __user *args_usr_ptr = arg;
+ struct incfs_get_last_read_error_args args = {};
+ int error;
+
+ error = mutex_lock_interruptible(&mi->mi_le_mutex);
+ if (error)
+ return error;
+
+ args.file_id_out = mi->mi_le_file_id;
+ args.time_us_out = mi->mi_le_time_us;
+ args.page_out = mi->mi_le_page;
+ args.errno_out = mi->mi_le_errno;
+
+ mutex_unlock(&mi->mi_le_mutex);
+ if (copy_to_user(args_usr_ptr, &args, sizeof(args)) > 0)
+ error = -EFAULT;
+
+ return error;
+}
+
static long pending_reads_dispatch_ioctl(struct file *f, unsigned int req,
unsigned long arg)
{
@@ -1009,6 +1031,8 @@ static long pending_reads_dispatch_ioctl(struct file *f, unsigned int req,
return ioctl_get_read_timeouts(mi, (void __user *)arg);
case INCFS_IOC_SET_READ_TIMEOUTS:
return ioctl_set_read_timeouts(mi, (void __user *)arg);
+ case INCFS_IOC_GET_LAST_READ_ERROR:
+ return ioctl_get_last_read_error(mi, (void __user *)arg);
default:
return -EINVAL;
}
diff --git a/include/uapi/linux/incrementalfs.h b/include/uapi/linux/incrementalfs.h
index e22094b3ce85..f1a6199da850 100644
--- a/include/uapi/linux/incrementalfs.h
+++ b/include/uapi/linux/incrementalfs.h
@@ -134,6 +134,13 @@
#define INCFS_IOC_SET_READ_TIMEOUTS \
_IOW(INCFS_IOCTL_BASE_CODE, 38, struct incfs_set_read_timeouts_args)
+/*
+ * Get last read error
+ * May only be called on .pending_reads file
+ */
+#define INCFS_IOC_GET_LAST_READ_ERROR \
+ _IOW(INCFS_IOCTL_BASE_CODE, 39, struct incfs_get_last_read_error_args)
+
/* ===== sysfs feature flags ===== */
/*
* Each flag is represented by a file in /sys/fs/incremental-fs/features
@@ -556,5 +563,24 @@ struct incfs_set_read_timeouts_args {
__u32 timeouts_array_size;
};
+/*
+ * Get last read error struct
+ * Arguments for INCFS_IOC_GET_LAST_READ_ERROR
+ */
+struct incfs_get_last_read_error_args {
+ /* File id of last file that had a read error */
+ incfs_uuid_t file_id_out;
+
+ /* Time of last read error, in us, from CLOCK_MONOTONIC */
+ __u64 time_us_out;
+
+ /* Index of page that was being read at last read error */
+ __u32 page_out;
+
+ /* errno of last read error */
+ __u32 errno_out;
+
+ __u64 reserved;
+};
#endif /* _UAPI_LINUX_INCREMENTALFS_H */
diff --git a/tools/testing/selftests/filesystems/incfs/incfs_test.c b/tools/testing/selftests/filesystems/incfs/incfs_test.c
index 1c0506770705..468401a85710 100644
--- a/tools/testing/selftests/filesystems/incfs/incfs_test.c
+++ b/tools/testing/selftests/filesystems/incfs/incfs_test.c
@@ -4378,6 +4378,24 @@ out:
return result;
}
+static int ioctl_test_last_error(int cmd_fd, const incfs_uuid_t *file_id,
+ int page, int error)
+{
+ int result = TEST_FAILURE;
+ struct incfs_get_last_read_error_args glre;
+
+ TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_GET_LAST_READ_ERROR, &glre), 0);
+ if (file_id)
+ TESTEQUAL(memcmp(&glre.file_id_out, file_id, sizeof(*file_id)),
+ 0);
+
+ TESTEQUAL(glre.page_out, page);
+ TESTEQUAL(glre.errno_out, error);
+ result = TEST_SUCCESS;
+out:
+ return result;
+}
+
static int sysfs_test(const char *mount_dir)
{
int result = TEST_FAILURE;
@@ -4417,8 +4435,10 @@ static int sysfs_test(const char *mount_dir)
0);
TEST(filename = concat_file_name(mount_dir, file.name), filename);
TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
+ TESTEQUAL(ioctl_test_last_error(cmd_fd, NULL, 0, 0), 0);
TESTEQUAL(sysfs_test_value("reads_failed_timed_out", 0), 0);
TEST(read(fd, NULL, 1), -1);
+ TESTEQUAL(ioctl_test_last_error(cmd_fd, &file.id, 0, -ETIME), 0);
TESTEQUAL(sysfs_test_value("reads_failed_timed_out", 2), 0);
TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);