On Fri, Feb 8, 2019 at 6:34 PM Jens Axboe <axboe@xxxxxxxxx> wrote: > From: Christoph Hellwig <hch@xxxxxx> > > Add a new fsync opcode, which either syncs a range if one is passed, > or the whole file if the offset and length fields are both cleared > to zero. A flag is provided to use fdatasync semantics, that is only > force out metadata which is required to retrieve the file data, but > not others like metadata. > > Signed-off-by: Christoph Hellwig <hch@xxxxxx> > Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> > --- [...] > +static int io_fsync(struct io_kiocb *req, const struct io_uring_sqe *sqe, > + bool force_nonblock) > +{ > + struct io_ring_ctx *ctx = req->ctx; > + loff_t sqe_off = READ_ONCE(sqe->off); > + loff_t sqe_len = READ_ONCE(sqe->len); > + loff_t end = sqe_off + sqe_len; > + unsigned fsync_flags; > + struct file *file; > + int ret, fd; > + > + /* fsync always requires a blocking context */ > + if (force_nonblock) > + return -EAGAIN; > + > + if (unlikely(sqe->addr || sqe->ioprio)) > + return -EINVAL; > + > + fsync_flags = READ_ONCE(sqe->fsync_flags); > + if (unlikely(fsync_flags & ~IORING_FSYNC_DATASYNC)) > + return -EINVAL; > + > + fd = READ_ONCE(sqe->fd); > + file = fget(fd); This always runs on the workqueue, right? Is it possible to call fget() on a workqueue? > + if (unlikely(!file)) > + return -EBADF; > + > + ret = vfs_fsync_range(file, sqe_off, end > 0 ? end : LLONG_MAX, > + fsync_flags & IORING_FSYNC_DATASYNC); > + > + fput(file); > + io_cqring_add_event(ctx, sqe->user_data, ret, 0); > + io_free_req(req); > + return 0; > +}