xref: /linux/fs/bcachefs/thread_with_file.c (revision 4b132aacb0768ac1e652cf517097ea6f237214b9)
1 // SPDX-License-Identifier: GPL-2.0
2 #ifndef NO_BCACHEFS_FS
3 
4 #include "bcachefs.h"
5 #include "thread_with_file.h"
6 
7 #include <linux/anon_inodes.h>
8 #include <linux/file.h>
9 #include <linux/kthread.h>
10 #include <linux/pagemap.h>
11 #include <linux/poll.h>
12 #include <linux/sched/sysctl.h>
13 
14 void bch2_thread_with_file_exit(struct thread_with_file *thr)
15 {
16 	if (thr->task) {
17 		kthread_stop(thr->task);
18 		put_task_struct(thr->task);
19 	}
20 }
21 
22 int bch2_run_thread_with_file(struct thread_with_file *thr,
23 			      const struct file_operations *fops,
24 			      int (*fn)(void *))
25 {
26 	struct file *file = NULL;
27 	int ret, fd = -1;
28 	unsigned fd_flags = O_CLOEXEC;
29 
30 	if (fops->read && fops->write)
31 		fd_flags |= O_RDWR;
32 	else if (fops->read)
33 		fd_flags |= O_RDONLY;
34 	else if (fops->write)
35 		fd_flags |= O_WRONLY;
36 
37 	char name[TASK_COMM_LEN];
38 	get_task_comm(name, current);
39 
40 	thr->ret = 0;
41 	thr->task = kthread_create(fn, thr, "%s", name);
42 	ret = PTR_ERR_OR_ZERO(thr->task);
43 	if (ret)
44 		return ret;
45 
46 	ret = get_unused_fd_flags(fd_flags);
47 	if (ret < 0)
48 		goto err;
49 	fd = ret;
50 
51 	file = anon_inode_getfile(name, fops, thr, fd_flags);
52 	ret = PTR_ERR_OR_ZERO(file);
53 	if (ret)
54 		goto err;
55 
56 	get_task_struct(thr->task);
57 	wake_up_process(thr->task);
58 	fd_install(fd, file);
59 	return fd;
60 err:
61 	if (fd >= 0)
62 		put_unused_fd(fd);
63 	if (thr->task)
64 		kthread_stop(thr->task);
65 	return ret;
66 }
67 
68 /* stdio_redirect */
69 
70 static bool stdio_redirect_has_more_input(struct stdio_redirect *stdio, size_t seen)
71 {
72 	return stdio->input.buf.nr > seen || stdio->done;
73 }
74 
75 static bool stdio_redirect_has_input(struct stdio_redirect *stdio)
76 {
77 	return stdio_redirect_has_more_input(stdio, 0);
78 }
79 
80 static bool stdio_redirect_has_output(struct stdio_redirect *stdio)
81 {
82 	return stdio->output.buf.nr || stdio->done;
83 }
84 
85 #define STDIO_REDIRECT_BUFSIZE		4096
86 
87 static bool stdio_redirect_has_input_space(struct stdio_redirect *stdio)
88 {
89 	return stdio->input.buf.nr < STDIO_REDIRECT_BUFSIZE || stdio->done;
90 }
91 
92 static bool stdio_redirect_has_output_space(struct stdio_redirect *stdio)
93 {
94 	return stdio->output.buf.nr < STDIO_REDIRECT_BUFSIZE || stdio->done;
95 }
96 
97 static void stdio_buf_init(struct stdio_buf *buf)
98 {
99 	spin_lock_init(&buf->lock);
100 	init_waitqueue_head(&buf->wait);
101 	darray_init(&buf->buf);
102 }
103 
104 /* thread_with_stdio */
105 
106 static void thread_with_stdio_done(struct thread_with_stdio *thr)
107 {
108 	thr->thr.done = true;
109 	thr->stdio.done = true;
110 	wake_up(&thr->stdio.input.wait);
111 	wake_up(&thr->stdio.output.wait);
112 }
113 
114 static ssize_t thread_with_stdio_read(struct file *file, char __user *ubuf,
115 				      size_t len, loff_t *ppos)
116 {
117 	struct thread_with_stdio *thr =
118 		container_of(file->private_data, struct thread_with_stdio, thr);
119 	struct stdio_buf *buf = &thr->stdio.output;
120 	size_t copied = 0, b;
121 	int ret = 0;
122 
123 	if (!(file->f_flags & O_NONBLOCK)) {
124 		ret = wait_event_interruptible(buf->wait, stdio_redirect_has_output(&thr->stdio));
125 		if (ret)
126 			return ret;
127 	} else if (!stdio_redirect_has_output(&thr->stdio))
128 		return -EAGAIN;
129 
130 	while (len && buf->buf.nr) {
131 		if (fault_in_writeable(ubuf, len) == len) {
132 			ret = -EFAULT;
133 			break;
134 		}
135 
136 		spin_lock_irq(&buf->lock);
137 		b = min_t(size_t, len, buf->buf.nr);
138 
139 		if (b && !copy_to_user_nofault(ubuf, buf->buf.data, b)) {
140 			ubuf	+= b;
141 			len	-= b;
142 			copied	+= b;
143 			buf->buf.nr -= b;
144 			memmove(buf->buf.data,
145 				buf->buf.data + b,
146 				buf->buf.nr);
147 		}
148 		spin_unlock_irq(&buf->lock);
149 	}
150 
151 	return copied ?: ret;
152 }
153 
154 static int thread_with_stdio_release(struct inode *inode, struct file *file)
155 {
156 	struct thread_with_stdio *thr =
157 		container_of(file->private_data, struct thread_with_stdio, thr);
158 
159 	thread_with_stdio_done(thr);
160 	bch2_thread_with_file_exit(&thr->thr);
161 	darray_exit(&thr->stdio.input.buf);
162 	darray_exit(&thr->stdio.output.buf);
163 	thr->ops->exit(thr);
164 	return 0;
165 }
166 
167 static ssize_t thread_with_stdio_write(struct file *file, const char __user *ubuf,
168 				       size_t len, loff_t *ppos)
169 {
170 	struct thread_with_stdio *thr =
171 		container_of(file->private_data, struct thread_with_stdio, thr);
172 	struct stdio_buf *buf = &thr->stdio.input;
173 	size_t copied = 0;
174 	ssize_t ret = 0;
175 
176 	while (len) {
177 		if (thr->thr.done) {
178 			ret = -EPIPE;
179 			break;
180 		}
181 
182 		size_t b = len - fault_in_readable(ubuf, len);
183 		if (!b) {
184 			ret = -EFAULT;
185 			break;
186 		}
187 
188 		spin_lock(&buf->lock);
189 		size_t makeroom = b;
190 		if (!buf->waiting_for_line || memchr(buf->buf.data, '\n', buf->buf.nr))
191 			makeroom = min_t(ssize_t, makeroom,
192 				   max_t(ssize_t, STDIO_REDIRECT_BUFSIZE - buf->buf.nr,
193 						  0));
194 		darray_make_room_gfp(&buf->buf, makeroom, GFP_NOWAIT);
195 
196 		b = min(len, darray_room(buf->buf));
197 
198 		if (b && !copy_from_user_nofault(&darray_top(buf->buf), ubuf, b)) {
199 			buf->buf.nr += b;
200 			ubuf	+= b;
201 			len	-= b;
202 			copied	+= b;
203 		}
204 		spin_unlock(&buf->lock);
205 
206 		if (b) {
207 			wake_up(&buf->wait);
208 		} else {
209 			if ((file->f_flags & O_NONBLOCK)) {
210 				ret = -EAGAIN;
211 				break;
212 			}
213 
214 			ret = wait_event_interruptible(buf->wait,
215 					stdio_redirect_has_input_space(&thr->stdio));
216 			if (ret)
217 				break;
218 		}
219 	}
220 
221 	return copied ?: ret;
222 }
223 
224 static __poll_t thread_with_stdio_poll(struct file *file, struct poll_table_struct *wait)
225 {
226 	struct thread_with_stdio *thr =
227 		container_of(file->private_data, struct thread_with_stdio, thr);
228 
229 	poll_wait(file, &thr->stdio.output.wait, wait);
230 	poll_wait(file, &thr->stdio.input.wait, wait);
231 
232 	__poll_t mask = 0;
233 
234 	if (stdio_redirect_has_output(&thr->stdio))
235 		mask |= EPOLLIN;
236 	if (stdio_redirect_has_input_space(&thr->stdio))
237 		mask |= EPOLLOUT;
238 	if (thr->thr.done)
239 		mask |= EPOLLHUP|EPOLLERR;
240 	return mask;
241 }
242 
243 static __poll_t thread_with_stdout_poll(struct file *file, struct poll_table_struct *wait)
244 {
245 	struct thread_with_stdio *thr =
246 		container_of(file->private_data, struct thread_with_stdio, thr);
247 
248 	poll_wait(file, &thr->stdio.output.wait, wait);
249 
250 	__poll_t mask = 0;
251 
252 	if (stdio_redirect_has_output(&thr->stdio))
253 		mask |= EPOLLIN;
254 	if (thr->thr.done)
255 		mask |= EPOLLHUP|EPOLLERR;
256 	return mask;
257 }
258 
259 static int thread_with_stdio_flush(struct file *file, fl_owner_t id)
260 {
261 	struct thread_with_stdio *thr =
262 		container_of(file->private_data, struct thread_with_stdio, thr);
263 
264 	return thr->thr.ret;
265 }
266 
267 static long thread_with_stdio_ioctl(struct file *file, unsigned int cmd, unsigned long p)
268 {
269 	struct thread_with_stdio *thr =
270 		container_of(file->private_data, struct thread_with_stdio, thr);
271 
272 	if (thr->ops->unlocked_ioctl)
273 		return thr->ops->unlocked_ioctl(thr, cmd, p);
274 	return -ENOTTY;
275 }
276 
277 static const struct file_operations thread_with_stdio_fops = {
278 	.llseek		= no_llseek,
279 	.read		= thread_with_stdio_read,
280 	.write		= thread_with_stdio_write,
281 	.poll		= thread_with_stdio_poll,
282 	.flush		= thread_with_stdio_flush,
283 	.release	= thread_with_stdio_release,
284 	.unlocked_ioctl	= thread_with_stdio_ioctl,
285 };
286 
287 static const struct file_operations thread_with_stdout_fops = {
288 	.llseek		= no_llseek,
289 	.read		= thread_with_stdio_read,
290 	.poll		= thread_with_stdout_poll,
291 	.flush		= thread_with_stdio_flush,
292 	.release	= thread_with_stdio_release,
293 	.unlocked_ioctl	= thread_with_stdio_ioctl,
294 };
295 
296 static int thread_with_stdio_fn(void *arg)
297 {
298 	struct thread_with_stdio *thr = arg;
299 
300 	thr->thr.ret = thr->ops->fn(thr);
301 
302 	thread_with_stdio_done(thr);
303 	return 0;
304 }
305 
306 void bch2_thread_with_stdio_init(struct thread_with_stdio *thr,
307 				 const struct thread_with_stdio_ops *ops)
308 {
309 	stdio_buf_init(&thr->stdio.input);
310 	stdio_buf_init(&thr->stdio.output);
311 	thr->ops = ops;
312 }
313 
314 int __bch2_run_thread_with_stdio(struct thread_with_stdio *thr)
315 {
316 	return bch2_run_thread_with_file(&thr->thr, &thread_with_stdio_fops, thread_with_stdio_fn);
317 }
318 
319 int bch2_run_thread_with_stdio(struct thread_with_stdio *thr,
320 			       const struct thread_with_stdio_ops *ops)
321 {
322 	bch2_thread_with_stdio_init(thr, ops);
323 
324 	return __bch2_run_thread_with_stdio(thr);
325 }
326 
327 int bch2_run_thread_with_stdout(struct thread_with_stdio *thr,
328 				const struct thread_with_stdio_ops *ops)
329 {
330 	stdio_buf_init(&thr->stdio.input);
331 	stdio_buf_init(&thr->stdio.output);
332 	thr->ops = ops;
333 
334 	return bch2_run_thread_with_file(&thr->thr, &thread_with_stdout_fops, thread_with_stdio_fn);
335 }
336 EXPORT_SYMBOL_GPL(bch2_run_thread_with_stdout);
337 
338 int bch2_stdio_redirect_read(struct stdio_redirect *stdio, char *ubuf, size_t len)
339 {
340 	struct stdio_buf *buf = &stdio->input;
341 
342 	/*
343 	 * we're waiting on user input (or for the file descriptor to be
344 	 * closed), don't want a hung task warning:
345 	 */
346 	do {
347 		wait_event_timeout(buf->wait, stdio_redirect_has_input(stdio),
348 				   sysctl_hung_task_timeout_secs * HZ / 2);
349 	} while (!stdio_redirect_has_input(stdio));
350 
351 	if (stdio->done)
352 		return -1;
353 
354 	spin_lock(&buf->lock);
355 	int ret = min(len, buf->buf.nr);
356 	buf->buf.nr -= ret;
357 	memcpy(ubuf, buf->buf.data, ret);
358 	memmove(buf->buf.data,
359 		buf->buf.data + ret,
360 		buf->buf.nr);
361 	spin_unlock(&buf->lock);
362 
363 	wake_up(&buf->wait);
364 	return ret;
365 }
366 
367 int bch2_stdio_redirect_readline_timeout(struct stdio_redirect *stdio,
368 					 darray_char *line,
369 					 unsigned long timeout)
370 {
371 	unsigned long until = jiffies + timeout, t;
372 	struct stdio_buf *buf = &stdio->input;
373 	size_t seen = 0;
374 again:
375 	t = timeout != MAX_SCHEDULE_TIMEOUT
376 		? max_t(long, until - jiffies, 0)
377 		: timeout;
378 
379 	t = min(t, sysctl_hung_task_timeout_secs * HZ / 2);
380 
381 	wait_event_timeout(buf->wait, stdio_redirect_has_more_input(stdio, seen), t);
382 
383 	if (stdio->done)
384 		return -1;
385 
386 	spin_lock(&buf->lock);
387 	seen = buf->buf.nr;
388 	char *n = memchr(buf->buf.data, '\n', seen);
389 
390 	if (!n && timeout != MAX_SCHEDULE_TIMEOUT && jiffies >= until) {
391 		spin_unlock(&buf->lock);
392 		return -ETIME;
393 	}
394 
395 	if (!n) {
396 		buf->waiting_for_line = true;
397 		spin_unlock(&buf->lock);
398 		goto again;
399 	}
400 
401 	size_t b = n + 1 - buf->buf.data;
402 	if (b > line->size) {
403 		spin_unlock(&buf->lock);
404 		int ret = darray_resize(line, b);
405 		if (ret)
406 			return ret;
407 		seen = 0;
408 		goto again;
409 	}
410 
411 	buf->buf.nr -= b;
412 	memcpy(line->data, buf->buf.data, b);
413 	memmove(buf->buf.data,
414 		buf->buf.data + b,
415 		buf->buf.nr);
416 	line->nr = b;
417 
418 	buf->waiting_for_line = false;
419 	spin_unlock(&buf->lock);
420 
421 	wake_up(&buf->wait);
422 	return 0;
423 }
424 
425 int bch2_stdio_redirect_readline(struct stdio_redirect *stdio, darray_char *line)
426 {
427 	return bch2_stdio_redirect_readline_timeout(stdio, line, MAX_SCHEDULE_TIMEOUT);
428 }
429 
430 __printf(3, 0)
431 static ssize_t bch2_darray_vprintf(darray_char *out, gfp_t gfp, const char *fmt, va_list args)
432 {
433 	ssize_t ret;
434 
435 	do {
436 		va_list args2;
437 		size_t len;
438 
439 		va_copy(args2, args);
440 		len = vsnprintf(out->data + out->nr, darray_room(*out), fmt, args2);
441 		va_end(args2);
442 
443 		if (len + 1 <= darray_room(*out)) {
444 			out->nr += len;
445 			return len;
446 		}
447 
448 		ret = darray_make_room_gfp(out, len + 1, gfp);
449 	} while (ret == 0);
450 
451 	return ret;
452 }
453 
454 ssize_t bch2_stdio_redirect_vprintf(struct stdio_redirect *stdio, bool nonblocking,
455 				    const char *fmt, va_list args)
456 {
457 	struct stdio_buf *buf = &stdio->output;
458 	unsigned long flags;
459 	ssize_t ret;
460 
461 again:
462 	spin_lock_irqsave(&buf->lock, flags);
463 	ret = bch2_darray_vprintf(&buf->buf, GFP_NOWAIT, fmt, args);
464 	spin_unlock_irqrestore(&buf->lock, flags);
465 
466 	if (ret < 0) {
467 		if (nonblocking)
468 			return -EAGAIN;
469 
470 		ret = wait_event_interruptible(buf->wait,
471 				stdio_redirect_has_output_space(stdio));
472 		if (ret)
473 			return ret;
474 		goto again;
475 	}
476 
477 	wake_up(&buf->wait);
478 	return ret;
479 }
480 
481 ssize_t bch2_stdio_redirect_printf(struct stdio_redirect *stdio, bool nonblocking,
482 				const char *fmt, ...)
483 {
484 	va_list args;
485 	ssize_t ret;
486 
487 	va_start(args, fmt);
488 	ret = bch2_stdio_redirect_vprintf(stdio, nonblocking, fmt, args);
489 	va_end(args);
490 
491 	return ret;
492 }
493 
494 #endif /* NO_BCACHEFS_FS */
495