This is an automated email from the git hooks/post-receive script.
andyp pushed a commit to branch andyp-fsckperf
in repository gfs2-utils.
commit d93a20ad3c8b273b1f8740a6ebc121fed87ae325
Author: Andrew Price <anprice(a)redhat.com>
Date: Fri Mar 9 18:32:32 2018 +0000
fsck.gfs2: Scan log headers in multi-block chunks
check_journal_seq_no() scans log headers issuing block-by-block reads.
block_map() gives us the length of an extent we can read in one go but
block_map() is called deep in the call path that operates on a single
block. Instead, do the block_map() and read the extent in
check_journal_seq_no(), then scan the multi-block buffers for log
headers. This requires a new lgfs2_get_log_header() function that
accepts a buffer instead of reading one.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/fsck/fs_recovery.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++---
gfs2/libgfs2/libgfs2.h | 1 +
gfs2/libgfs2/recovery.c | 51 ++++++++++++++++++++++++++++---------------------
3 files changed, 78 insertions(+), 25 deletions(-)
diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c
index 677abd7..3eaf576 100644
--- a/gfs2/fsck/fs_recovery.c
+++ b/gfs2/fsck/fs_recovery.c
@@ -391,6 +391,39 @@ static int foreach_descriptor(struct gfs2_inode *ip, unsigned int start,
}
/**
+ * Read an extent from a gfs2 inode.
+ * lblk: The logical data block to read
+ * extlen: The length of the extent (in fs blocks) that is read
+ * Returns a buffer (*extlen * bsize) in size containing the inode data
+ * or NULL on error.
+ */
+static char *readi_extent(struct gfs2_inode *ip, uint64_t lblk, uint32_t *extlen)
+{
+ struct gfs2_sbd *sdp = ip->i_sbd;
+ uint64_t dblock;
+ int notnew = 0;
+ ssize_t bytes;
+ ssize_t bufsz;
+ char *buf;
+
+ block_map(ip, lblk, ¬new, &dblock, extlen, FALSE);
+ if (dblock == 0)
+ return NULL;
+
+ bufsz = *extlen * sdp->bsize;
+ buf = malloc(bufsz);
+ if (buf == NULL)
+ return NULL;
+
+ bytes = pread(sdp->device_fd, buf, bufsz, dblock * sdp->bsize);
+ if (bytes != bufsz) {
+ free(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+/**
* check_journal_seq_no - Check and Fix log header sequencing problems
* @ip: the journal incore inode
* @fix: if 1, fix the sequence numbers, otherwise just report the problem
@@ -399,6 +432,7 @@ static int foreach_descriptor(struct gfs2_inode *ip, unsigned int start,
*/
static int check_journal_seq_no(struct gfs2_inode *ip, int fix)
{
+ struct gfs2_sbd *sdp = ip->i_sbd;
int error = 0, wrapped = 0;
uint32_t jd_blocks = ip->i_di.di_size / ip->i_sbd->sd_sb.sb_bsize;
uint32_t blk;
@@ -407,12 +441,22 @@ static int check_journal_seq_no(struct gfs2_inode *ip, int fix)
int new = 0;
uint64_t dblock;
struct gfs2_buffer_head *bh;
+ uint32_t extlen = 0;
int seq_errors = 0;
+ char *buf = NULL;
+ int b;
memset(&lh, 0, sizeof(lh));
- for (blk = 0; blk < jd_blocks; blk++) {
- error = get_log_header(ip, blk, &lh);
- if (error == 1) /* if not a log header */
+ for (blk = 0, b = 0; blk < jd_blocks; blk++, b++) {
+ if (extlen - b == 0) {
+ free(buf);
+ buf = readi_extent(ip, blk, &extlen);
+ if (buf == NULL)
+ return -1;
+ b = 0;
+ }
+ error = lgfs2_get_log_header(buf + (b * sdp->bsize), sdp->bsize, &lh);
+ if (error == 1 || lh.lh_blkno != blk) /* if not a log header */
continue; /* just journal data--ignore it */
if (!lowest_seq || lh.lh_sequence < lowest_seq)
lowest_seq = lh.lh_sequence;
@@ -448,6 +492,7 @@ static int check_journal_seq_no(struct gfs2_inode *ip, int fix)
bmodified(bh);
brelse(bh);
}
+ free(buf);
if (seq_errors && fix) {
log_err(_("%d sequence errors fixed.\n"), seq_errors);
seq_errors = 0;
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 3a54195..215907a 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -660,6 +660,7 @@ extern int gfs2_revoke_add(struct gfs2_sbd *sdp, uint64_t blkno, unsigned int wh
extern int gfs2_revoke_check(struct gfs2_sbd *sdp, uint64_t blkno,
unsigned int where);
extern void gfs2_revoke_clean(struct gfs2_sbd *sdp);
+extern int lgfs2_get_log_header(char *buf, unsigned bsize, struct gfs2_log_header *lh);
extern int get_log_header(struct gfs2_inode *ip, unsigned int blk,
struct gfs2_log_header *head);
extern int gfs2_find_jhead(struct gfs2_inode *ip, struct gfs2_log_header *head);
diff --git a/gfs2/libgfs2/recovery.c b/gfs2/libgfs2/recovery.c
index 6b14bf9..1321b57 100644
--- a/gfs2/libgfs2/recovery.c
+++ b/gfs2/libgfs2/recovery.c
@@ -36,6 +36,31 @@ int gfs2_replay_read_block(struct gfs2_inode *ip, unsigned int blk,
return 0;
}
+int lgfs2_get_log_header(char *buf, unsigned bsize, struct gfs2_log_header *lh)
+{
+ struct gfs2_log_header *dlh = (struct gfs2_log_header *)buf;
+ uint32_t saved_hash;
+ uint32_t lh_crc = 0;
+ uint32_t hash;
+ uint32_t crc;
+
+ saved_hash = dlh->lh_hash;
+ dlh->lh_hash = 0;
+ hash = lgfs2_log_header_hash(buf);
+ dlh->lh_hash = saved_hash;
+ crc = lgfs2_log_header_crc(buf, bsize);
+ gfs2_log_header_in(lh, buf);
+#ifdef GFS2_HAS_LH_V2
+ lh_crc = lh->lh_crc;
+#endif
+ if (lh->lh_hash != hash)
+ return 1;
+ /* Don't check the crc if it's zero, as it is in pre-v2 log headers */
+ if (lh_crc != 0 && lh_crc != crc)
+ return 1;
+ return 0;
+}
+
/**
* get_log_header - read the log header for a given segment
* @ip: the journal incore inode
@@ -54,35 +79,17 @@ int get_log_header(struct gfs2_inode *ip, unsigned int blk,
struct gfs2_log_header *head)
{
struct gfs2_buffer_head *bh;
- struct gfs2_log_header lh, *tmp;
- uint32_t hash, saved_hash;
- uint32_t lh_crc = 0;
- uint32_t crc;
int error;
error = gfs2_replay_read_block(ip, blk, &bh);
if (error)
return error;
- tmp = (struct gfs2_log_header *)bh->b_data;
- saved_hash = tmp->lh_hash;
- tmp->lh_hash = 0;
- hash = lgfs2_log_header_hash(bh->b_data);
- tmp->lh_hash = saved_hash;
- crc = lgfs2_log_header_crc(bh->b_data, ip->i_sbd->bsize);
- gfs2_log_header_in(&lh, bh->b_data);
- brelse(bh);
-#ifdef GFS2_HAS_LH_V2
- lh_crc = lh.lh_crc;
-#endif
- if (error || lh.lh_blkno != blk || lh.lh_hash != hash)
- return 1;
- /* Don't check the crc if it's zero, as it is in pre-v2 log headers */
- if (lh_crc != 0 && lh_crc != crc)
+ error = lgfs2_get_log_header(bh->b_data, ip->i_sbd->bsize, head);
+ if (error)
+ return error;
+ if (head->lh_blkno != blk)
return 1;
-
- *head = lh;
-
return 0;
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.