Skip to content

Commit 7644c82

Browse files
committed
Merge tag 'pipe-nonblock-2023-05-06' of git://git.kernel.dk/linux
Pull nonblocking pipe io_uring support from Jens Axboe: "Here's the revised edition of the FMODE_NOWAIT support for pipes, in which we just flag it as such supporting FMODE_NOWAIT unconditionally, but clear it if we ever end up using splice/vmsplice on the pipe. The pipe read/write side is perfectly fine for nonblocking IO, however splice and vmsplice can potentially wait for IO with the pipe lock held" * tag 'pipe-nonblock-2023-05-06' of git://git.kernel.dk/linux: pipe: set FMODE_NOWAIT on pipes splice: clear FMODE_NOWAIT on file if splice/vmsplice is used
2 parents 0021b53 + afed627 commit 7644c82

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed

fs/pipe.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,9 @@ static int __do_pipe_flags(int *fd, struct file **files, int flags)
976976
audit_fd_pair(fdr, fdw);
977977
fd[0] = fdr;
978978
fd[1] = fdw;
979+
/* pipe groks IOCB_NOWAIT */
980+
files[0]->f_mode |= FMODE_NOWAIT;
981+
files[1]->f_mode |= FMODE_NOWAIT;
979982
return 0;
980983

981984
err_fdr:

fs/splice.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@
3838

3939
#include "internal.h"
4040

41+
/*
42+
* Splice doesn't support FMODE_NOWAIT. Since pipes may set this flag to
43+
* indicate they support non-blocking reads or writes, we must clear it
44+
* here if set to avoid blocking other users of this pipe if splice is
45+
* being done on it.
46+
*/
47+
static noinline void noinline pipe_clear_nowait(struct file *file)
48+
{
49+
fmode_t fmode = READ_ONCE(file->f_mode);
50+
51+
do {
52+
if (!(fmode & FMODE_NOWAIT))
53+
break;
54+
} while (!try_cmpxchg(&file->f_mode, &fmode, fmode & ~FMODE_NOWAIT));
55+
}
56+
4157
/*
4258
* Attempt to steal a page from a pipe buffer. This should perhaps go into
4359
* a vm helper function, it's already simplified quite a bit by the
@@ -1219,10 +1235,16 @@ static long __do_splice(struct file *in, loff_t __user *off_in,
12191235
ipipe = get_pipe_info(in, true);
12201236
opipe = get_pipe_info(out, true);
12211237

1222-
if (ipipe && off_in)
1223-
return -ESPIPE;
1224-
if (opipe && off_out)
1225-
return -ESPIPE;
1238+
if (ipipe) {
1239+
if (off_in)
1240+
return -ESPIPE;
1241+
pipe_clear_nowait(in);
1242+
}
1243+
if (opipe) {
1244+
if (off_out)
1245+
return -ESPIPE;
1246+
pipe_clear_nowait(out);
1247+
}
12261248

12271249
if (off_out) {
12281250
if (copy_from_user(&offset, off_out, sizeof(loff_t)))
@@ -1319,6 +1341,8 @@ static long vmsplice_to_user(struct file *file, struct iov_iter *iter,
13191341
if (!pipe)
13201342
return -EBADF;
13211343

1344+
pipe_clear_nowait(file);
1345+
13221346
if (sd.total_len) {
13231347
pipe_lock(pipe);
13241348
ret = __splice_from_pipe(pipe, &sd, pipe_to_user);
@@ -1347,6 +1371,8 @@ static long vmsplice_to_pipe(struct file *file, struct iov_iter *iter,
13471371
if (!pipe)
13481372
return -EBADF;
13491373

1374+
pipe_clear_nowait(file);
1375+
13501376
pipe_lock(pipe);
13511377
ret = wait_for_space(pipe, flags);
13521378
if (!ret)

0 commit comments

Comments
 (0)