On Mon, Jul 3, 2023 at 5:42 PM Ahelenia Ziemiańska <nabijaczleweli@xxxxxxxxxxxxxxxxxx> wrote: > > The current behaviour caused an asymmetry where some write APIs > (write, sendfile) would notify the written-to/read-from objects, > but splice wouldn't. > > This affected userspace which uses inotify, most notably coreutils > tail -f, to monitor pipes. > If the pipe buffer had been filled by a splice-family function: > * tail wouldn't know and thus wouldn't service the pipe, and > * all writes to the pipe would block because it's full, > thus service was denied. > (For the particular case of tail -f this could be worked around > with ---disable-inotify.) > > Fixes: 983652c69199 ("splice: report related fsnotify events") > Link: https://lore.kernel.org/linux-fsdevel/jbyihkyk5dtaohdwjyivambb2gffyjs3dodpofafnkkunxq7bu@jngkdxx65pux/t/#u > Link: https://bugs.debian.org/1039488 > Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@xxxxxxxxxxxxxxxxxx> > Reviewed-by: Amir Goldstein <amir73il@xxxxxxxxx> > Acked-by: Jan Kara <jack@xxxxxxx> > --- > fs/splice.c | 31 ++++++++++++++----------------- > 1 file changed, 14 insertions(+), 17 deletions(-) > > diff --git a/fs/splice.c b/fs/splice.c > index 3e06611d19ae..6ae6da52eba9 100644 > --- a/fs/splice.c > +++ b/fs/splice.c > @@ -1154,10 +1154,8 @@ long do_splice(struct file *in, loff_t *off_in, struct file *out, > if ((in->f_flags | out->f_flags) & O_NONBLOCK) > flags |= SPLICE_F_NONBLOCK; > > - return splice_pipe_to_pipe(ipipe, opipe, len, flags); > - } > - > - if (ipipe) { > + ret = splice_pipe_to_pipe(ipipe, opipe, len, flags); > + } else if (ipipe) { > if (off_in) > return -ESPIPE; > if (off_out) { > @@ -1182,18 +1180,11 @@ long do_splice(struct file *in, loff_t *off_in, struct file *out, > ret = do_splice_from(ipipe, out, &offset, len, flags); > file_end_write(out); > > - if (ret > 0) > - fsnotify_modify(out); > - > if (!off_out) > out->f_pos = offset; > else > *off_out = offset; > - > - return ret; > - } > - > - if (opipe) { > + } else if (opipe) { > if (off_out) > return -ESPIPE; > if (off_in) { > @@ -1209,18 +1200,24 @@ long do_splice(struct file *in, loff_t *off_in, struct file *out, > > ret = splice_file_to_pipe(in, opipe, &offset, len, flags); > > - if (ret > 0) > - fsnotify_access(in); > - > if (!off_in) > in->f_pos = offset; > else > *off_in = offset; > + } else > + return -EINVAL; I must have missed this in previous reviews - mixing if {} else (without {}) is an anti pattern that causes bugs. No need to send v6 just for this - it can be fixed up on commit. > > - return ret; > + if (ret > 0) { > + /* > + * Generate modify out before access in: > + * do_splice_from() may've already sent modify out, > + * and this ensures the events get merged. > + */ > + fsnotify_modify(out); > + fsnotify_access(in); > } > > - return -EINVAL; > + return ret; > } > > static long __do_splice(struct file *in, loff_t __user *off_in, > -- > 2.39.2 >