summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2024-02-07 11:43:32 -0800
committerKent Overstreet <kent.overstreet@linux.dev>2024-02-15 19:45:41 -0500
commitd741c84848a7c2d81b8f60b592622723b2d2b8c1 (patch)
tree00c1efdb1a02511341803c3a31f315f21da395a8
parent873da86d4817022921a01e2d483bd0fed9183cac (diff)
thread_with_file: allow creation of readonly files
Create a new run_thread_with_stdout function that opens a file in O_RDONLY mode so that the kernel can write things to userspace but userspace cannot write to the kernel. This will be used to convey xfs health event information to userspace. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--include/linux/thread_with_file.h3
-rw-r--r--lib/thread_with_file.c36
2 files changed, 39 insertions, 0 deletions
diff --git a/include/linux/thread_with_file.h b/include/linux/thread_with_file.h
index 54091f7ff338..5f7e85bc8322 100644
--- a/include/linux/thread_with_file.h
+++ b/include/linux/thread_with_file.h
@@ -62,6 +62,9 @@ struct thread_with_stdio {
int run_thread_with_stdio(struct thread_with_stdio *,
void (*exit)(struct thread_with_stdio *),
void (*fn)(struct thread_with_stdio *));
+int run_thread_with_stdout(struct thread_with_stdio *,
+ void (*exit)(struct thread_with_stdio *),
+ void (*fn)(struct thread_with_stdio *));
int stdio_redirect_read(struct stdio_redirect *, char *, size_t);
int stdio_redirect_readline(struct stdio_redirect *, char *, size_t);
diff --git a/lib/thread_with_file.c b/lib/thread_with_file.c
index b09dc60ba628..71028611b8d5 100644
--- a/lib/thread_with_file.c
+++ b/lib/thread_with_file.c
@@ -344,6 +344,22 @@ static int thread_with_stdio_release(struct inode *inode, struct file *file)
return 0;
}
+static __poll_t thread_with_stdout_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct thread_with_stdio *thr =
+ container_of(file->private_data, struct thread_with_stdio, thr);
+
+ poll_wait(file, &thr->stdio.output.wait, wait);
+
+ __poll_t mask = 0;
+
+ if (stdio_redirect_has_output(&thr->stdio))
+ mask |= EPOLLIN;
+ if (thr->thr.done)
+ mask |= EPOLLHUP|EPOLLERR;
+ return mask;
+}
+
static const struct file_operations thread_with_stdio_fops = {
.llseek = no_llseek,
.read = thread_with_stdio_read,
@@ -352,6 +368,13 @@ static const struct file_operations thread_with_stdio_fops = {
.release = thread_with_stdio_release,
};
+static const struct file_operations thread_with_stdout_fops = {
+ .llseek = no_llseek,
+ .read = thread_with_stdio_read,
+ .poll = thread_with_stdout_poll,
+ .release = thread_with_stdio_release,
+};
+
static int thread_with_stdio_fn(void *arg)
{
struct thread_with_stdio *thr = arg;
@@ -375,5 +398,18 @@ int run_thread_with_stdio(struct thread_with_stdio *thr,
}
EXPORT_SYMBOL_GPL(run_thread_with_stdio);
+int run_thread_with_stdout(struct thread_with_stdio *thr,
+ void (*exit)(struct thread_with_stdio *),
+ void (*fn)(struct thread_with_stdio *))
+{
+ stdio_buf_init(&thr->stdio.input);
+ stdio_buf_init(&thr->stdio.output);
+ thr->exit = exit;
+ thr->fn = fn;
+
+ return run_thread_with_file(&thr->thr, &thread_with_stdout_fops, thread_with_stdio_fn);
+}
+EXPORT_SYMBOL_GPL(run_thread_with_stdout);
+
MODULE_AUTHOR("Kent Overstreet");
MODULE_LICENSE("GPL");