Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+33 -4
+3
fs/pipe.c
··· 976 976 audit_fd_pair(fdr, fdw); 977 977 fd[0] = fdr; 978 978 fd[1] = fdw; 979 + /* pipe groks IOCB_NOWAIT */ 980 + files[0]->f_mode |= FMODE_NOWAIT; 981 + files[1]->f_mode |= FMODE_NOWAIT; 979 982 return 0; 980 983 981 984 err_fdr:
+30 -4
fs/splice.c
··· 39 39 #include "internal.h" 40 40 41 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 + 57 + /* 42 58 * Attempt to steal a page from a pipe buffer. This should perhaps go into 43 59 * a vm helper function, it's already simplified quite a bit by the 44 60 * addition of remove_mapping(). If success is returned, the caller may ··· 1235 1219 ipipe = get_pipe_info(in, true); 1236 1220 opipe = get_pipe_info(out, true); 1237 1221 1238 - if (ipipe && off_in) 1239 - return -ESPIPE; 1240 - if (opipe && off_out) 1241 - return -ESPIPE; 1222 + if (ipipe) { 1223 + if (off_in) 1224 + return -ESPIPE; 1225 + pipe_clear_nowait(in); 1226 + } 1227 + if (opipe) { 1228 + if (off_out) 1229 + return -ESPIPE; 1230 + pipe_clear_nowait(out); 1231 + } 1242 1232 1243 1233 if (off_out) { 1244 1234 if (copy_from_user(&offset, off_out, sizeof(loff_t))) ··· 1341 1319 if (!pipe) 1342 1320 return -EBADF; 1343 1321 1322 + pipe_clear_nowait(file); 1323 + 1344 1324 if (sd.total_len) { 1345 1325 pipe_lock(pipe); 1346 1326 ret = __splice_from_pipe(pipe, &sd, pipe_to_user); ··· 1370 1346 pipe = get_pipe_info(file, true); 1371 1347 if (!pipe) 1372 1348 return -EBADF; 1349 + 1350 + pipe_clear_nowait(file); 1373 1351 1374 1352 pipe_lock(pipe); 1375 1353 ret = wait_for_space(pipe, flags);