From: Abhi Das <adas@redhat.com>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] [GFS2 v2 PATCH 4/4] gfs2: read journal in large chunks to locate the head
Date: Mon, 10 Sep 2018 09:56:28 -0500 [thread overview]
Message-ID: <1536591388-19553-5-git-send-email-adas@redhat.com> (raw)
In-Reply-To: <1536591388-19553-1-git-send-email-adas@redhat.com>
Use bio(s) to read in the journal sequentially in large chunks and
locate the head of the journal.
This is faster in most cases when compared to the existing bisect
method which operates one block at a time.
Signed-off-by: Abhi Das <adas@redhat.com>
---
fs/gfs2/incore.h | 8 +++-
fs/gfs2/lops.c | 96 +++++++++++++++++++++++++++++++++++++++++-
fs/gfs2/lops.h | 1 +
fs/gfs2/ops_fstype.c | 1 +
fs/gfs2/recovery.c | 115 +++++----------------------------------------------
5 files changed, 114 insertions(+), 107 deletions(-)
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index b96d39c..b24c105 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -529,6 +529,11 @@ struct gfs2_journal_extent {
u64 blocks;
};
+enum {
+ JDF_RECOVERY = 1,
+ JDF_JHEAD = 2,
+};
+
struct gfs2_jdesc {
struct list_head jd_list;
struct list_head extent_list;
@@ -536,12 +541,13 @@ struct gfs2_jdesc {
struct work_struct jd_work;
struct inode *jd_inode;
unsigned long jd_flags;
-#define JDF_RECOVERY 1
unsigned int jd_jid;
unsigned int jd_blocks;
int jd_recover_error;
/* Replay stuff */
+ struct gfs2_log_header_host jd_jhead;
+ struct bio *jd_rd_bio; /* bio used for reading this journal */
unsigned int jd_found_blocks;
unsigned int jd_found_revokes;
unsigned int jd_replayed_blocks;
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index f5f31a6..24d5dba 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -18,6 +18,7 @@
#include <linux/fs.h>
#include <linux/list_sort.h>
+#include "bmap.h"
#include "dir.h"
#include "gfs2.h"
#include "incore.h"
@@ -227,6 +228,50 @@ static void gfs2_end_log_write(struct bio *bio)
wake_up(&sdp->sd_log_flush_wait);
}
+static void gfs2_end_log_read(struct bio *bio)
+{
+ struct gfs2_jdesc *jd = bio->bi_private;
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+ struct page *page;
+ struct bio_vec *bvec;
+ int i, last;
+
+ if (bio->bi_status) {
+ fs_err(sdp, "Error %d reading from journal, jid=%u\n",
+ bio->bi_status, jd->jd_jid);
+ }
+
+ bio_for_each_segment_all(bvec, bio, i) {
+ struct gfs2_log_header_host uninitialized_var(lh);
+ void *ptr;
+
+ page = bvec->bv_page;
+ ptr = page_address(page);
+ last = page_private(page);
+
+ if (!test_bit(JDF_JHEAD, &jd->jd_flags)) {
+ mempool_free(page, gfs2_page_pool);
+ continue;
+ }
+
+ if (!__get_log_header(sdp, ptr, 0, &lh)) {
+ if (lh.lh_sequence > jd->jd_jhead.lh_sequence)
+ jd->jd_jhead = lh;
+ else
+ goto found;
+ }
+
+ if (last) {
+ found:
+ clear_bit(JDF_JHEAD, &jd->jd_flags);
+ wake_up_bit(&jd->jd_flags, JDF_JHEAD);
+ }
+ mempool_free(page, gfs2_page_pool);
+ }
+
+ bio_put(bio);
+}
+
/**
* gfs2_log_flush_bio - Submit any pending log bio
* @biop: Address of the bio pointer
@@ -241,8 +286,10 @@ void gfs2_log_flush_bio(struct bio **biop, int op, int op_flags)
{
struct bio *bio = *biop;
if (bio) {
- struct gfs2_sbd *sdp = bio->bi_private;
- atomic_inc(&sdp->sd_log_in_flight);
+ if (op != REQ_OP_READ) {
+ struct gfs2_sbd *sdp = bio->bi_private;
+ atomic_inc(&sdp->sd_log_in_flight);
+ }
bio_set_op_attrs(bio, op, op_flags);
submit_bio(bio);
*biop = NULL;
@@ -360,6 +407,51 @@ void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page)
gfs2_log_bmap(sdp));
}
+static void gfs2_log_read_extent(struct gfs2_jdesc *jd, u64 dblock,
+ unsigned int blocks, int last)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+ struct super_block *sb = sdp->sd_vfs;
+ struct page *page;
+ int i, ret;
+ struct bio *bio;
+
+ for (i = 0; i < blocks; i++) {
+ page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
+ /* flag the last page of the journal we plan to read in */
+ page_private(page) = (last && i == (blocks - 1));
+
+ bio = gfs2_log_get_bio(sdp, dblock + i, &jd->jd_rd_bio,
+ REQ_OP_READ, gfs2_end_log_read,
+ jd, false);
+ ret = bio_add_page(bio, page, sb->s_blocksize, 0);
+ if (ret == 0) {
+ bio = gfs2_log_get_bio(sdp, dblock + i, &jd->jd_rd_bio,
+ REQ_OP_READ, gfs2_end_log_read,
+ jd, true);
+ ret = bio_add_page(bio, page, sb->s_blocksize, 0);
+ WARN_ON(ret == 0);
+ }
+ bio->bi_private = jd;
+ }
+}
+
+void gfs2_log_read(struct gfs2_jdesc *jd)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+ int last = 0;
+ struct gfs2_journal_extent *je;
+
+ if (list_empty(&jd->extent_list))
+ gfs2_map_journal_extents(sdp, jd);
+
+ list_for_each_entry(je, &jd->extent_list, list) {
+ last = list_is_last(&je->list, &jd->extent_list);
+ gfs2_log_read_extent(jd, je->dblock, je->blocks, last);
+ gfs2_log_flush_bio(&jd->jd_rd_bio, REQ_OP_READ, 0);
+ }
+}
+
static struct page *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type,
u32 ld_length, u32 ld_data1)
{
diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h
index d709d99..23392c5d 100644
--- a/fs/gfs2/lops.h
+++ b/fs/gfs2/lops.h
@@ -32,6 +32,7 @@ extern void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page,
extern void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page);
extern void gfs2_log_flush_bio(struct bio **biop, int op, int op_flags);
extern void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh);
+extern void gfs2_log_read(struct gfs2_jdesc *jd);
static inline unsigned int buf_limit(struct gfs2_sbd *sdp)
{
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index c2469833b..dcc488b4 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -578,6 +578,7 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
kfree(jd);
break;
}
+ jd->jd_rd_bio = NULL;
spin_lock(&sdp->sd_jindex_spin);
jd->jd_jid = sdp->sd_journals++;
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
index 1b95294..0f80f25 100644
--- a/fs/gfs2/recovery.c
+++ b/fs/gfs2/recovery.c
@@ -182,85 +182,11 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk,
}
/**
- * find_good_lh - find a good log header
- * @jd: the journal
- * @blk: the segment to start searching from
- * @lh: the log header to fill in
- * @forward: if true search forward in the log, else search backward
- *
- * Call get_log_header() to get a log header for a segment, but if the
- * segment is bad, either scan forward or backward until we find a good one.
- *
- * Returns: errno
- */
-
-static int find_good_lh(struct gfs2_jdesc *jd, unsigned int *blk,
- struct gfs2_log_header_host *head)
-{
- unsigned int orig_blk = *blk;
- int error;
-
- for (;;) {
- error = get_log_header(jd, *blk, head);
- if (error <= 0)
- return error;
-
- if (++*blk == jd->jd_blocks)
- *blk = 0;
-
- if (*blk == orig_blk) {
- gfs2_consist_inode(GFS2_I(jd->jd_inode));
- return -EIO;
- }
- }
-}
-
-/**
- * jhead_scan - make sure we've found the head of the log
- * @jd: the journal
- * @head: this is filled in with the log descriptor of the head
- *
- * At this point, seg and lh should be either the head of the log or just
- * before. Scan forward until we find the head.
- *
- * Returns: errno
- */
-
-static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
-{
- unsigned int blk = head->lh_blkno;
- struct gfs2_log_header_host lh;
- int error;
-
- for (;;) {
- if (++blk == jd->jd_blocks)
- blk = 0;
-
- error = get_log_header(jd, blk, &lh);
- if (error < 0)
- return error;
- if (error == 1)
- continue;
-
- if (lh.lh_sequence == head->lh_sequence) {
- gfs2_consist_inode(GFS2_I(jd->jd_inode));
- return -EIO;
- }
- if (lh.lh_sequence < head->lh_sequence)
- break;
-
- *head = lh;
- }
-
- return 0;
-}
-
-/**
* gfs2_find_jhead - find the head of a log
* @jd: the journal
* @head: the log descriptor for the head of the log is returned here
*
- * Do a binary search of a journal and find the valid log entry with the
+ * Do a search of a journal and find the valid log entry with the
* highest sequence number. (i.e. the log head)
*
* Returns: errno
@@ -268,38 +194,19 @@ static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
{
- struct gfs2_log_header_host lh_1, lh_m;
- u32 blk_1, blk_2, blk_m;
- int error;
-
- blk_1 = 0;
- blk_2 = jd->jd_blocks - 1;
-
- for (;;) {
- blk_m = (blk_1 + blk_2) / 2;
-
- error = find_good_lh(jd, &blk_1, &lh_1);
- if (error)
- return error;
-
- error = find_good_lh(jd, &blk_m, &lh_m);
- if (error)
- return error;
-
- if (blk_1 == blk_m || blk_m == blk_2)
- break;
+ int error = 0;
- if (lh_1.lh_sequence <= lh_m.lh_sequence)
- blk_1 = blk_m;
- else
- blk_2 = blk_m;
- }
+ memset(&jd->jd_jhead, 0, sizeof(struct gfs2_log_header_host));
+ set_bit(JDF_JHEAD, &jd->jd_flags);
+ gfs2_log_read(jd);
- error = jhead_scan(jd, &lh_1);
- if (error)
- return error;
+ if (test_bit(JDF_JHEAD, &jd->jd_flags))
+ wait_on_bit(&jd->jd_flags, JDF_JHEAD, TASK_INTERRUPTIBLE);
- *head = lh_1;
+ if (jd->jd_jhead.lh_sequence == 0)
+ error = -EIO;
+ else
+ *head = jd->jd_jhead;
return error;
}
--
2.4.11
next prev parent reply other threads:[~2018-09-10 14:56 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-09-10 14:56 [Cluster-devel] [GFS2 v2 PATCH 0/4] Speed up journal head lookup Abhi Das
2018-09-10 14:56 ` [Cluster-devel] [GFS2 v2 PATCH 1/4] gfs2: add timing info to map_journal_extents Abhi Das
2018-09-10 14:56 ` [Cluster-devel] [GFS2 v2 PATCH 2/4] gfs2: changes to gfs2_log_XXX_bio Abhi Das
2018-09-10 14:56 ` [Cluster-devel] [GFS2 v2 PATCH 3/4] gfs2: add a helper function to get_log_header that can be used elsewhere Abhi Das
2018-09-10 14:56 ` Abhi Das [this message]
2018-09-10 15:35 ` [Cluster-devel] [GFS2 v2 PATCH 0/4] Speed up journal head lookup Andreas Gruenbacher
2018-09-10 15:46 ` Bob Peterson
2018-09-10 16:28 ` Abhijith Das
2018-09-10 18:46 ` Abhijith Das
-- strict thread matches above, loose matches on Subject: below --
2018-10-19 4:29 [Cluster-devel] [GFS2 v2 PATCH 4/4] gfs2: read journal in large chunks to locate the head Abhi Das
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1536591388-19553-5-git-send-email-adas@redhat.com \
--to=adas@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).