Commit 14a56ec6 authored by Gao Xiang's avatar Gao Xiang Committed by Greg Kroah-Hartman
Browse files

staging: erofs: support IO read error injection



Used to simulate disk IO read error for testing fatal
error tolerance.

Here are the details,
1) use bio->bi_private to indicate super_block
   for non-compressed bios since some (mainly meta)
   pages can be of the corresponding bdev inode;
2) get super_block dynamically for compressed bios,
   therefore it could not inject bios full of staging
   pages, yet it doesn't affect the normal usage.

Signed-off-by: default avatarGao Xiang <gaoxiang25@huawei.com>
Reviewed-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d61fbb6b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ fault_injection=%d Enable fault injection in all supported types with
                       specified injection rate. Supported injection type:
                       Type_Name                Type_Value
                       FAULT_KMALLOC            0x000000001
                       FAULT_READ_IO            0x000000002
(no)user_xattr         Setup Extended User Attributes. Note: xattr is enabled
                       by default if CONFIG_EROFS_FS_XATTR is selected.
(no)acl                Setup POSIX Access Control List. Note: acl is enabled
+12 −6
Original line number Diff line number Diff line
@@ -17,11 +17,17 @@

static inline void read_endio(struct bio *bio)
{
	struct super_block *const sb = bio->bi_private;
	int i;
	struct bio_vec *bvec;
	const blk_status_t err = bio->bi_status;
	blk_status_t err = bio->bi_status;
	struct bvec_iter_all iter_all;

	if (time_to_inject(EROFS_SB(sb), FAULT_READ_IO)) {
		erofs_show_injection_info(FAULT_READ_IO);
		err = BLK_STS_IOERR;
	}

	bio_for_each_segment_all(bvec, bio, i, iter_all) {
		struct page *page = bvec->bv_page;

@@ -63,7 +69,7 @@ repeat:
	if (!PageUptodate(page)) {
		struct bio *bio;

		bio = erofs_grab_bio(sb, blkaddr, 1, read_endio, nofail);
		bio = erofs_grab_bio(sb, blkaddr, 1, sb, read_endio, nofail);
		if (IS_ERR(bio)) {
			DBG_BUGON(nofail);
			err = PTR_ERR(bio);
@@ -188,7 +194,8 @@ static inline struct bio *erofs_read_raw_page(struct bio *bio,
					      unsigned int nblocks,
					      bool ra)
{
	struct inode *inode = mapping->host;
	struct inode *const inode = mapping->host;
	struct super_block *const sb = inode->i_sb;
	erofs_off_t current_block = (erofs_off_t)page->index;
	int err;

@@ -280,9 +287,8 @@ submit_bio_retry:
		if (nblocks > BIO_MAX_PAGES)
			nblocks = BIO_MAX_PAGES;

		bio = erofs_grab_bio(inode->i_sb,
				     blknr, nblocks, read_endio, false);

		bio = erofs_grab_bio(sb, blknr, nblocks, sb,
				     read_endio, false);
		if (IS_ERR(bio)) {
			err = PTR_ERR(bio);
			bio = NULL;
+4 −2
Original line number Diff line number Diff line
@@ -44,11 +44,12 @@

enum {
	FAULT_KMALLOC,
	FAULT_READ_IO,
	FAULT_MAX,
};

#ifdef CONFIG_EROFS_FAULT_INJECTION
extern char *erofs_fault_name[FAULT_MAX];
extern const char *erofs_fault_name[FAULT_MAX];
#define IS_FAULT_SET(fi, type) ((fi)->inject_type & (1 << (type)))

struct erofs_fault_info {
@@ -467,7 +468,7 @@ static inline int z_erofs_map_blocks_iter(struct inode *inode,
/* data.c */
static inline struct bio *
erofs_grab_bio(struct super_block *sb,
	       erofs_blk_t blkaddr, unsigned int nr_pages,
	       erofs_blk_t blkaddr, unsigned int nr_pages, void *bi_private,
	       bio_end_io_t endio, bool nofail)
{
	const gfp_t gfp = GFP_NOIO;
@@ -489,6 +490,7 @@ erofs_grab_bio(struct super_block *sb,
	bio->bi_end_io = endio;
	bio_set_dev(bio, sb->s_bdev);
	bio->bi_iter.bi_sector = (sector_t)blkaddr << LOG_SECTORS_PER_BLOCK;
	bio->bi_private = bi_private;
	return bio;
}

+2 −1
Original line number Diff line number Diff line
@@ -142,8 +142,9 @@ out:
}

#ifdef CONFIG_EROFS_FAULT_INJECTION
char *erofs_fault_name[FAULT_MAX] = {
const char *erofs_fault_name[FAULT_MAX] = {
	[FAULT_KMALLOC]		= "kmalloc",
	[FAULT_READ_IO]		= "read IO error",
};

static void __erofs_build_fault_attr(struct erofs_sb_info *sbi,
+9 −5
Original line number Diff line number Diff line
@@ -844,8 +844,8 @@ static void z_erofs_vle_unzip_kickoff(void *ptr, int bios)

static inline void z_erofs_vle_read_endio(struct bio *bio)
{
	const blk_status_t err = bio->bi_status;
	struct erofs_sb_info *sbi = NULL;
	blk_status_t err = bio->bi_status;
	unsigned int i;
	struct bio_vec *bvec;
	struct bvec_iter_all iter_all;
@@ -857,9 +857,15 @@ static inline void z_erofs_vle_read_endio(struct bio *bio)
		DBG_BUGON(PageUptodate(page));
		DBG_BUGON(!page->mapping);

		if (unlikely(!sbi && !z_erofs_is_stagingpage(page)))
		if (unlikely(!sbi && !z_erofs_is_stagingpage(page))) {
			sbi = EROFS_SB(page->mapping->host->i_sb);

			if (time_to_inject(sbi, FAULT_READ_IO)) {
				erofs_show_injection_info(FAULT_READ_IO);
				err = BLK_STS_IOERR;
			}
		}

		/* sbi should already be gotten if the page is managed */
		if (sbi)
			cachemngd = erofs_page_is_managed(sbi, page);
@@ -1430,10 +1436,8 @@ submit_bio_retry:

		if (!bio) {
			bio = erofs_grab_bio(sb, first_index + i,
					     BIO_MAX_PAGES,
					     BIO_MAX_PAGES, bi_private,
					     z_erofs_vle_read_endio, true);
			bio->bi_private = bi_private;

			++nr_bios;
		}