On 2/21/22 7:16 AM, Dylan Yudaken wrote: > Update kiocb->ki_pos at execution time rather than in io_prep_rw(). > io_prep_rw() happens before the job is enqueued to a worker and so the > offset might be read multiple times before being executed once. > > Ensures that the file position in a set of _linked_ SQEs will be only > obtained after earlier SQEs have completed, and so will include their > incremented file position. > > Signed-off-by: Dylan Yudaken <dylany@xxxxxx> > --- > fs/io_uring.c | 25 +++++++++++++++++-------- > 1 file changed, 17 insertions(+), 8 deletions(-) > > diff --git a/fs/io_uring.c b/fs/io_uring.c > index 1f9b4466c269..50b93ff2ee12 100644 > --- a/fs/io_uring.c > +++ b/fs/io_uring.c > @@ -3000,14 +3000,6 @@ static int io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe) > req->flags |= io_file_get_flags(file) << REQ_F_SUPPORT_NOWAIT_BIT; > > kiocb->ki_pos = READ_ONCE(sqe->off); > - if (kiocb->ki_pos == -1) { > - if (!(file->f_mode & FMODE_STREAM)) { > - req->flags |= REQ_F_CUR_POS; > - kiocb->ki_pos = file->f_pos; > - } else { > - kiocb->ki_pos = 0; > - } > - } > kiocb->ki_flags = iocb_flags(file); > ret = kiocb_set_rw_flags(kiocb, READ_ONCE(sqe->rw_flags)); > if (unlikely(ret)) > @@ -3074,6 +3066,19 @@ static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret) > } > } > > +static inline void > +io_kiocb_update_pos(struct io_kiocb *req, struct kiocb *kiocb) > +{ > + if (kiocb->ki_pos == -1) { > + if (!(req->file->f_mode & FMODE_STREAM)) { > + req->flags |= REQ_F_CUR_POS; > + kiocb->ki_pos = req->file->f_pos; > + } else { > + kiocb->ki_pos = 0; > + } > + } > +} static inline void io_kiocb_update_pos(struct io_kiocb *req, struct kiocb *kiocb) { } Can we just drop the kiocb argument? It'll always be req->rw.kiocb. Should generate the same code if you do: static inline void io_kiocb_update_pos(struct io_kiocb *req) { struct kiocb *kiocb = &req->rw.kiocb; ... } Apart from that minor thing, looks good to me. -- Jens Axboe