summaryrefslogtreecommitdiffstats
path: root/drivers/staging/erofs/data.c
diff options
context:
space:
mode:
authorGao Xiang <gaoxiang25@huawei.com>2018-08-21 22:49:30 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-08-27 19:46:12 +0200
commit6e78901a9f233fb3581799a996b8ff6fadc97763 (patch)
tree43bb4eac11d6d378f8836ed09ce6febbcebc6d2c /drivers/staging/erofs/data.c
parent8be31270362b444a1f9d160aa5df9f147675b4a7 (diff)
staging: erofs: separate erofs_get_meta_page
This patch separates 'erofs_get_meta_page' into 'erofs_get_meta_page' and 'erofs_get_meta_page_nofail'. The second one ensures that it should not fail under memory pressure and should make best efforts if IO errors occur. It also adds auxiliary variables in order to fulfill 80 character limit. Signed-off-by: Gao Xiang <gaoxiang25@huawei.com> Reviewed-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/erofs/data.c')
-rw-r--r--drivers/staging/erofs/data.c58
1 files changed, 38 insertions, 20 deletions
diff --git a/drivers/staging/erofs/data.c b/drivers/staging/erofs/data.c
index e0c046df6665..9c85ccb24402 100644
--- a/drivers/staging/erofs/data.c
+++ b/drivers/staging/erofs/data.c
@@ -39,39 +39,50 @@ static inline void read_endio(struct bio *bio)
}
/* 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;
@@ -79,13 +90,20 @@ 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,