diff options
author | Andreas Gruenbacher <agruenba@redhat.com> | 2016-09-07 15:28:30 +0200 |
---|---|---|
committer | Andreas Gruenbacher <agruenba@redhat.com> | 2016-09-09 13:25:03 +0200 |
commit | 65b9157979f4444840367bc7003a4ea54e26d915 (patch) | |
tree | d35cd91714aebe8f972ae714d70a53c36ae37880 | |
parent | 3b0979c2c5cf8ec57e20e1d1912f9d3a93172ea6 (diff) | |
download | linux-gfs2-log.tar.gz |
gfs2 log recovery: Full-log readaheadgfs2-log
Read the entire log into the page cache immediately instead of reading
it in chunk by chunk as required.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
-rw-r--r-- | fs/gfs2/meta_io.c | 61 | ||||
-rw-r--r-- | fs/gfs2/meta_io.h | 1 | ||||
-rw-r--r-- | fs/gfs2/recovery.c | 15 |
3 files changed, 77 insertions, 0 deletions
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index ffa6fea4a68ee3..10177650269ef4 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -27,6 +27,7 @@ #include "inode.h" #include "log.h" #include "lops.h" +#include "bmap.h" #include "meta_io.h" #include "rgrp.h" #include "trans.h" @@ -327,6 +328,66 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh) return 0; } +int gfs2_readahead_extent(struct gfs2_inode *ip, unsigned int *blk) +{ + struct gfs2_glock *gl = ip->i_gl; + struct bio *bio = NULL; + struct buffer_head *bh = NULL; + int new = 0; + u64 dblock; + u32 extlen; + int error; + + error = gfs2_extent_map(&ip->i_inode, *blk, &new, &dblock, &extlen); + if (error) + return error; + if (!dblock) { + gfs2_consist_inode(ip); + return -EIO; + } + + while (extlen) { + if (!bh) { + bh = gfs2_getbuf(gl, dblock, CREATE); + if (buffer_uptodate(bh) || !trylock_buffer(bh)) { + brelse(bh); + if (bio) { + submit_bio(bio); + bio = NULL; + } + goto next_bh; + } + bh->b_end_io = end_buffer_read_sync; + } + + if (!bio) { + bio = bio_alloc(GFP_NOIO, min((int)extlen, BIO_MAX_PAGES)); + bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); + bio->bi_bdev = bh->b_bdev; + bio->bi_end_io = gfs2_meta_read_endio; + bio_set_op_attrs(bio, REQ_OP_READ, REQ_RAHEAD | REQ_META); + } + + if (bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh))) + goto next_bh; + + submit_bio(bio); + bio = NULL; + continue; + +next_bh: + bh = NULL; + (*blk)++; + dblock++; + extlen--; + } + + if (bio) + submit_bio(bio); + + return 0; +} + void gfs2_remove_from_journal(struct buffer_head *bh, int meta) { struct address_space *mapping = bh->b_page->mapping; diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 259b650e859722..d347847b38d613 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -56,6 +56,7 @@ extern void gfs2_meta_read_endio(struct bio *bio); extern int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, int rahead, struct buffer_head **bhp); extern int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh); +extern int gfs2_readahead_extent(struct gfs2_inode *ip, unsigned int *blk); extern struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno, int create); enum { diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index e7186828643c51..0f2e88d90f171b 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -83,6 +83,19 @@ submit: return 0; } +static int gfs2_readahead_journal(struct gfs2_jdesc *jd) +{ + struct gfs2_inode *ip = GFS2_I(jd->jd_inode); + unsigned int blk = 0; + + while (blk < jd->jd_blocks) { + int error = gfs2_readahead_extent(ip, &blk); + if (error) + return error; + } + return 0; +} + int gfs2_revoke_add(struct gfs2_jdesc *jd, u64 blkno, unsigned int where) { struct list_head *head = &jd->jd_revoke_list; @@ -248,6 +261,8 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head) u32 blk = 0; int error; + gfs2_readahead_journal(jd); + error = gfs2_map_journal_extents(sdp, jd); if (error) return error; |