mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 00:44:31 +01:00
iomap: report file I/O errors to the VFS
Wire up iomap so that it reports all file read and write errors to the VFS (and hence fsnotify) via the new fserror mechanism. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Link: https://patch.msgid.link/176826402631.3490369.729008983502742314.stgit@frogsfrogsfrogs Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
21945e6cb5
commit
a9d573ee88
3 changed files with 40 additions and 1 deletions
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/writeback.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/migrate.h>
|
||||
#include <linux/fserror.h>
|
||||
#include "internal.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
|
@ -371,8 +372,11 @@ static int iomap_read_inline_data(const struct iomap_iter *iter,
|
|||
if (folio_test_uptodate(folio))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON_ONCE(size > iomap->length))
|
||||
if (WARN_ON_ONCE(size > iomap->length)) {
|
||||
fserror_report_io(iter->inode, FSERR_BUFFERED_READ,
|
||||
iomap->offset, size, -EIO, GFP_NOFS);
|
||||
return -EIO;
|
||||
}
|
||||
if (offset > 0)
|
||||
ifs_alloc(iter->inode, folio, iter->flags);
|
||||
|
||||
|
|
@ -399,6 +403,11 @@ void iomap_finish_folio_read(struct folio *folio, size_t off, size_t len,
|
|||
spin_unlock_irqrestore(&ifs->state_lock, flags);
|
||||
}
|
||||
|
||||
if (error)
|
||||
fserror_report_io(folio->mapping->host, FSERR_BUFFERED_READ,
|
||||
folio_pos(folio) + off, len, error,
|
||||
GFP_ATOMIC);
|
||||
|
||||
if (finished)
|
||||
folio_end_read(folio, uptodate);
|
||||
}
|
||||
|
|
@ -540,6 +549,10 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
|
|||
if (!*bytes_submitted)
|
||||
iomap_read_init(folio);
|
||||
ret = ctx->ops->read_folio_range(iter, ctx, plen);
|
||||
if (ret < 0)
|
||||
fserror_report_io(iter->inode,
|
||||
FSERR_BUFFERED_READ, pos,
|
||||
plen, ret, GFP_NOFS);
|
||||
if (ret)
|
||||
return ret;
|
||||
*bytes_submitted += plen;
|
||||
|
|
@ -815,6 +828,10 @@ static int __iomap_write_begin(const struct iomap_iter *iter,
|
|||
else
|
||||
status = iomap_bio_read_folio_range_sync(iter,
|
||||
folio, block_start, plen);
|
||||
if (status < 0)
|
||||
fserror_report_io(iter->inode,
|
||||
FSERR_BUFFERED_READ, pos,
|
||||
len, status, GFP_NOFS);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
|
@ -1805,6 +1822,7 @@ int iomap_writeback_folio(struct iomap_writepage_ctx *wpc, struct folio *folio)
|
|||
u64 pos = folio_pos(folio);
|
||||
u64 end_pos = pos + folio_size(folio);
|
||||
u64 end_aligned = 0;
|
||||
loff_t orig_pos = pos;
|
||||
size_t bytes_submitted = 0;
|
||||
int error = 0;
|
||||
u32 rlen;
|
||||
|
|
@ -1848,6 +1866,9 @@ int iomap_writeback_folio(struct iomap_writepage_ctx *wpc, struct folio *folio)
|
|||
|
||||
if (bytes_submitted)
|
||||
wpc->nr_folios++;
|
||||
if (error && pos > orig_pos)
|
||||
fserror_report_io(inode, FSERR_BUFFERED_WRITE, orig_pos, 0,
|
||||
error, GFP_NOFS);
|
||||
|
||||
/*
|
||||
* We can have dirty bits set past end of file in page_mkwrite path
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/pagemap.h>
|
||||
#include <linux/iomap.h>
|
||||
#include <linux/task_io_accounting_ops.h>
|
||||
#include <linux/fserror.h>
|
||||
#include "internal.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
|
@ -78,6 +79,13 @@ static void iomap_dio_submit_bio(const struct iomap_iter *iter,
|
|||
}
|
||||
}
|
||||
|
||||
static inline enum fserror_type iomap_dio_err_type(const struct iomap_dio *dio)
|
||||
{
|
||||
if (dio->flags & IOMAP_DIO_WRITE)
|
||||
return FSERR_DIRECTIO_WRITE;
|
||||
return FSERR_DIRECTIO_READ;
|
||||
}
|
||||
|
||||
ssize_t iomap_dio_complete(struct iomap_dio *dio)
|
||||
{
|
||||
const struct iomap_dio_ops *dops = dio->dops;
|
||||
|
|
@ -87,6 +95,10 @@ ssize_t iomap_dio_complete(struct iomap_dio *dio)
|
|||
|
||||
if (dops && dops->end_io)
|
||||
ret = dops->end_io(iocb, dio->size, ret, dio->flags);
|
||||
if (dio->error)
|
||||
fserror_report_io(file_inode(iocb->ki_filp),
|
||||
iomap_dio_err_type(dio), offset, dio->size,
|
||||
dio->error, GFP_NOFS);
|
||||
|
||||
if (likely(!ret)) {
|
||||
ret = dio->size;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <linux/list_sort.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/writeback.h>
|
||||
#include <linux/fserror.h>
|
||||
#include "internal.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
|
@ -55,6 +56,11 @@ static u32 iomap_finish_ioend_buffered(struct iomap_ioend *ioend)
|
|||
|
||||
/* walk all folios in bio, ending page IO on them */
|
||||
bio_for_each_folio_all(fi, bio) {
|
||||
if (ioend->io_error)
|
||||
fserror_report_io(inode, FSERR_BUFFERED_WRITE,
|
||||
folio_pos(fi.folio) + fi.offset,
|
||||
fi.length, ioend->io_error,
|
||||
GFP_ATOMIC);
|
||||
iomap_finish_folio_write(inode, fi.folio, fi.length);
|
||||
folio_count++;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue