aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2016-09-07 15:28:30 +0200
committerAndreas Gruenbacher <agruenba@redhat.com>2016-09-09 13:25:03 +0200
commit65b9157979f4444840367bc7003a4ea54e26d915 (patch)
treed35cd91714aebe8f972ae714d70a53c36ae37880
parent3b0979c2c5cf8ec57e20e1d1912f9d3a93172ea6 (diff)
downloadlinux-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.c61
-rw-r--r--fs/gfs2/meta_io.h1
-rw-r--r--fs/gfs2/recovery.c15
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;