Test EROFS to inject faults such as ENOMEM, EIO, and so on.
If unsure, say N.
+config EROFS_FS_IO_MAX_RETRIES
+ int "EROFS IO Maximum Retries"
+ depends on EROFS_FS
+ default "5"
+ help
+ Maximum retry count of IO Errors.
+
+ If unsure, leave the default value (5 retries, 6 IOs at most).
+
config EROFS_FS_ZIP
bool "EROFS Data Compresssion Support"
depends on EROFS_FS
}
/* prio -- true is used for dir */
-struct page *erofs_get_meta_page(struct super_block *sb,
- erofs_blk_t blkaddr, bool prio)
+struct page *__erofs_get_meta_page(struct super_block *sb,
+ erofs_blk_t blkaddr, bool prio, bool nofail)
{
- struct inode *bd_inode = sb->s_bdev->bd_inode;
- struct address_space *mapping = bd_inode->i_mapping;
+ struct inode *const bd_inode = sb->s_bdev->bd_inode;
+ struct address_space *const mapping = bd_inode->i_mapping;
+ /* prefer retrying in the allocator to blindly looping below */
+ const gfp_t gfp = mapping_gfp_constraint(mapping, ~__GFP_FS) |
+ (nofail ? __GFP_NOFAIL : 0);
+ unsigned int io_retries = nofail ? EROFS_IO_MAX_RETRIES_NOFAIL : 0;
struct page *page;
+ int err;
repeat:
- page = find_or_create_page(mapping, blkaddr,
- /*
- * Prefer looping in the allocator rather than here,
- * at least that code knows what it's doing.
- */
- mapping_gfp_constraint(mapping, ~__GFP_FS) | __GFP_NOFAIL);
-
- BUG_ON(!page || !PageLocked(page));
+ page = find_or_create_page(mapping, blkaddr, gfp);
+ if (unlikely(page == NULL)) {
+ DBG_BUGON(nofail);
+ return ERR_PTR(-ENOMEM);
+ }
+ DBG_BUGON(!PageLocked(page));
if (!PageUptodate(page)) {
struct bio *bio;
- int err;
- bio = erofs_grab_bio(sb, blkaddr, 1, read_endio, true);
+ bio = erofs_grab_bio(sb, blkaddr, 1, read_endio, nofail);
+ if (IS_ERR(bio)) {
+ DBG_BUGON(nofail);
+ err = PTR_ERR(bio);
+ goto err_out;
+ }
err = bio_add_page(bio, page, PAGE_SIZE, 0);
- BUG_ON(err != PAGE_SIZE);
+ if (unlikely(err != PAGE_SIZE)) {
+ err = -EFAULT;
+ goto err_out;
+ }
__submit_bio(bio, REQ_OP_READ,
REQ_META | (prio ? REQ_PRIO : 0));
lock_page(page);
- /* the page has been truncated by others? */
+ /* this page has been truncated by others */
if (unlikely(page->mapping != mapping)) {
+unlock_repeat:
unlock_page(page);
put_page(page);
goto repeat;
/* more likely a read error */
if (unlikely(!PageUptodate(page))) {
- unlock_page(page);
- put_page(page);
-
- page = ERR_PTR(-EIO);
+ if (io_retries) {
+ --io_retries;
+ goto unlock_repeat;
+ }
+ err = -EIO;
+ goto err_out;
}
}
return page;
+
+err_out:
+ unlock_page(page);
+ put_page(page);
+ return ERR_PTR(err);
}
static int erofs_map_blocks_flatmode(struct inode *inode,
submit_bio(bio);
}
-extern struct page *erofs_get_meta_page(struct super_block *sb,
- erofs_blk_t blkaddr, bool prio);
+#ifndef CONFIG_EROFS_FS_IO_MAX_RETRIES
+#define EROFS_IO_MAX_RETRIES_NOFAIL 0
+#else
+#define EROFS_IO_MAX_RETRIES_NOFAIL CONFIG_EROFS_FS_IO_MAX_RETRIES
+#endif
+
+extern struct page *__erofs_get_meta_page(struct super_block *sb,
+ erofs_blk_t blkaddr, bool prio, bool nofail);
+
+static inline struct page *erofs_get_meta_page(struct super_block *sb,
+ erofs_blk_t blkaddr, bool prio)
+{
+ return __erofs_get_meta_page(sb, blkaddr, prio, false);
+}
+
+static inline struct page *erofs_get_meta_page_nofail(struct super_block *sb,
+ erofs_blk_t blkaddr, bool prio)
+{
+ return __erofs_get_meta_page(sb, blkaddr, prio, true);
+}
+
extern int erofs_map_blocks(struct inode *, struct erofs_map_blocks *, int);
extern int erofs_map_blocks_iter(struct inode *, struct erofs_map_blocks *,
struct page **, int);
};
-static inline struct page *erofs_get_inline_page(struct inode *inode,
- erofs_blk_t blkaddr)
+static inline struct page *
+erofs_get_inline_page_nofail(struct inode *inode,
+ erofs_blk_t blkaddr)
{
- return erofs_get_meta_page(inode->i_sb,
+ return erofs_get_meta_page_nofail(inode->i_sb,
blkaddr, S_ISDIR(inode->i_mode));
}
erofs_blk_t blkaddr = vle_extent_blkaddr(inode, lcn);
struct z_erofs_vle_decompressed_index *di;
unsigned long long ofs;
- const unsigned int clusterbits = EROFS_SB(inode->i_sb)->clusterbits;
+ struct super_block *const sb = inode->i_sb;
+ const unsigned int clusterbits = EROFS_SB(sb)->clusterbits;
const unsigned int clustersize = 1 << clusterbits;
if (page->index != blkaddr) {
unlock_page(page);
put_page(page);
- *page_iter = page = erofs_get_meta_page(inode->i_sb,
- blkaddr, false);
+ page = erofs_get_meta_page_nofail(sb, blkaddr, false);
+ *page_iter = page;
*kaddr_iter = kmap_atomic(page);
}
struct page *mpage = *mpage_ret;
void *kaddr;
bool initial;
- const unsigned int clusterbits = EROFS_SB(inode->i_sb)->clusterbits;
+ struct super_block *const sb = inode->i_sb;
+ const unsigned int clusterbits = EROFS_SB(sb)->clusterbits;
const unsigned int clustersize = 1 << clusterbits;
int err = 0;
if (mpage != NULL)
put_page(mpage);
- mpage = erofs_get_meta_page(inode->i_sb, e_blkaddr, false);
+ mpage = erofs_get_meta_page_nofail(sb, e_blkaddr, false);
*mpage_ret = mpage;
} else {
lock_page(mpage);
struct xattr_iter it;
unsigned i;
struct erofs_xattr_ibody_header *ih;
+ struct super_block *sb;
struct erofs_sb_info *sbi;
struct erofs_vnode *vi;
bool atomic_map;
vi = EROFS_V(inode);
BUG_ON(!vi->xattr_isize);
- sbi = EROFS_I_SB(inode);
+ sb = inode->i_sb;
+ sbi = EROFS_SB(sb);
it.blkaddr = erofs_blknr(iloc(sbi, vi->nid) + vi->inode_isize);
it.ofs = erofs_blkoff(iloc(sbi, vi->nid) + vi->inode_isize);
- it.page = erofs_get_inline_page(inode, it.blkaddr);
+ it.page = erofs_get_inline_page_nofail(inode, it.blkaddr);
BUG_ON(IS_ERR(it.page));
/* read in shared xattr array (non-atomic, see kmalloc below) */
BUG_ON(it.ofs != EROFS_BLKSIZ);
xattr_iter_end(&it, atomic_map);
- it.page = erofs_get_meta_page(inode->i_sb,
+ it.page = erofs_get_meta_page_nofail(sb,
++it.blkaddr, S_ISDIR(inode->i_mode));
BUG_ON(IS_ERR(it.page));
xattr_iter_end(it, true);
it->blkaddr += erofs_blknr(it->ofs);
- it->page = erofs_get_meta_page(it->sb, it->blkaddr, false);
+ it->page = erofs_get_meta_page_nofail(it->sb,
+ it->blkaddr, false);
BUG_ON(IS_ERR(it->page));
it->kaddr = kmap_atomic(it->page);
it->blkaddr = erofs_blknr(iloc(sbi, vi->nid) + inline_xattr_ofs);
it->ofs = erofs_blkoff(iloc(sbi, vi->nid) + inline_xattr_ofs);
- it->page = erofs_get_inline_page(inode, it->blkaddr);
+ it->page = erofs_get_inline_page_nofail(inode, it->blkaddr);
BUG_ON(IS_ERR(it->page));
it->kaddr = kmap_atomic(it->page);
static int shared_getxattr(struct inode *inode, struct getxattr_iter *it)
{
struct erofs_vnode *const vi = EROFS_V(inode);
- struct erofs_sb_info *const sbi = EROFS_SB(inode->i_sb);
+ struct super_block *const sb = inode->i_sb;
+ struct erofs_sb_info *const sbi = EROFS_SB(sb);
unsigned i;
int ret = -ENOATTR;
if (i)
xattr_iter_end(&it->it, true);
- it->it.page = erofs_get_meta_page(inode->i_sb,
+ it->it.page = erofs_get_meta_page_nofail(sb,
blkaddr, false);
BUG_ON(IS_ERR(it->it.page));
it->it.kaddr = kmap_atomic(it->it.page);
{
struct inode *const inode = d_inode(it->dentry);
struct erofs_vnode *const vi = EROFS_V(inode);
- struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
+ struct super_block *const sb = inode->i_sb;
+ struct erofs_sb_info *const sbi = EROFS_SB(sb);
unsigned i;
int ret = 0;
if (i)
xattr_iter_end(&it->it, true);
- it->it.page = erofs_get_meta_page(inode->i_sb,
+ it->it.page = erofs_get_meta_page_nofail(sb,
blkaddr, false);
BUG_ON(IS_ERR(it->it.page));
it->it.kaddr = kmap_atomic(it->it.page);