io_uring/rw: ensure kiocb_end_write() is always called
A previous commit moved the notifications and end-write handling, but it is now missing a few spots where we also want to call both of those. Without that, we can potentially be missing file notifications, and more importantly, have an imbalance in the super_block writers sem accounting. Fixes: b000145e9907 ("io_uring/rw: defer fsnotify calls to task context") Reported-by: Dave Chinner <david@fromorbit.com> Link: https://lore.kernel.org/all/20221010050319.GC2703033@dread.disaster.area/ Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
00927931cb
commit
2ec33a6c3c
@ -234,11 +234,34 @@ static void kiocb_end_write(struct io_kiocb *req)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trigger the notifications after having done some IO, and finish the write
|
||||||
|
* accounting, if any.
|
||||||
|
*/
|
||||||
|
static void io_req_io_end(struct io_kiocb *req)
|
||||||
|
{
|
||||||
|
struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
|
||||||
|
|
||||||
|
WARN_ON(!in_task());
|
||||||
|
|
||||||
|
if (rw->kiocb.ki_flags & IOCB_WRITE) {
|
||||||
|
kiocb_end_write(req);
|
||||||
|
fsnotify_modify(req->file);
|
||||||
|
} else {
|
||||||
|
fsnotify_access(req->file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool __io_complete_rw_common(struct io_kiocb *req, long res)
|
static bool __io_complete_rw_common(struct io_kiocb *req, long res)
|
||||||
{
|
{
|
||||||
if (unlikely(res != req->cqe.res)) {
|
if (unlikely(res != req->cqe.res)) {
|
||||||
if ((res == -EAGAIN || res == -EOPNOTSUPP) &&
|
if ((res == -EAGAIN || res == -EOPNOTSUPP) &&
|
||||||
io_rw_should_reissue(req)) {
|
io_rw_should_reissue(req)) {
|
||||||
|
/*
|
||||||
|
* Reissue will start accounting again, finish the
|
||||||
|
* current cycle.
|
||||||
|
*/
|
||||||
|
io_req_io_end(req);
|
||||||
req->flags |= REQ_F_REISSUE | REQ_F_PARTIAL_IO;
|
req->flags |= REQ_F_REISSUE | REQ_F_PARTIAL_IO;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -264,15 +287,7 @@ static inline int io_fixup_rw_res(struct io_kiocb *req, long res)
|
|||||||
|
|
||||||
static void io_req_rw_complete(struct io_kiocb *req, bool *locked)
|
static void io_req_rw_complete(struct io_kiocb *req, bool *locked)
|
||||||
{
|
{
|
||||||
struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
|
io_req_io_end(req);
|
||||||
|
|
||||||
if (rw->kiocb.ki_flags & IOCB_WRITE) {
|
|
||||||
kiocb_end_write(req);
|
|
||||||
fsnotify_modify(req->file);
|
|
||||||
} else {
|
|
||||||
fsnotify_access(req->file);
|
|
||||||
}
|
|
||||||
|
|
||||||
io_req_task_complete(req, locked);
|
io_req_task_complete(req, locked);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,6 +332,11 @@ static int kiocb_done(struct io_kiocb *req, ssize_t ret,
|
|||||||
req->file->f_pos = rw->kiocb.ki_pos;
|
req->file->f_pos = rw->kiocb.ki_pos;
|
||||||
if (ret >= 0 && (rw->kiocb.ki_complete == io_complete_rw)) {
|
if (ret >= 0 && (rw->kiocb.ki_complete == io_complete_rw)) {
|
||||||
if (!__io_complete_rw_common(req, ret)) {
|
if (!__io_complete_rw_common(req, ret)) {
|
||||||
|
/*
|
||||||
|
* Safe to call io_end from here as we're inline
|
||||||
|
* from the submission path.
|
||||||
|
*/
|
||||||
|
io_req_io_end(req);
|
||||||
io_req_set_res(req, final_ret,
|
io_req_set_res(req, final_ret,
|
||||||
io_put_kbuf(req, issue_flags));
|
io_put_kbuf(req, issue_flags));
|
||||||
return IOU_OK;
|
return IOU_OK;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user