[Cluster-devel] [PATCH 17/19] libgfs2: Add a speedier journal data block writing function

Andrew Price anprice at redhat.com
Tue Sep 2 12:07:34 UTC 2014


Now that we guarantee journals to be allocated contiguously, and the
block allocation has been separated out, we can speed up the journal
data writing process by simply generating the blocks and writing them
sequentially without consulting the resource group bitmaps each time a
new block is required.

lgfs2_write_journal_data() is added and the old write_journal() function
is left in place for now, until other journal creation scenarios (e.g.
potentially fragmented journals in gfs2_jadd and fsck.gfs2) have been
catered for, and those tools migrated to the new functions.

A further speed-up may be possible by using async i/o but we already
have a significant performance improvement with this strategy alone so
the added complexity of async i/o may not be worth it.

Signed-off-by: Andrew Price <anprice at redhat.com>
---
 gfs2/libgfs2/libgfs2.h    |  1 +
 gfs2/libgfs2/structures.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+)

diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index c7adbc1..406fbbe 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -500,6 +500,7 @@ extern void build_height(struct gfs2_inode *ip, int height);
 extern void unstuff_dinode(struct gfs2_inode *ip);
 extern unsigned int calc_tree_height(struct gfs2_inode *ip, uint64_t size);
 extern int write_journal(struct gfs2_inode *jnl, unsigned bsize, unsigned blocks);
+extern int lgfs2_write_journal_data(struct gfs2_inode *ip);
 extern int lgfs2_write_filemeta(struct gfs2_inode *ip);
 
 /* gfs1.c - GFS1 backward compatibility structures and functions */
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index 1836255..c4b9ebc 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -143,6 +143,54 @@ out_buf:
 	return err;
 }
 
+/**
+ * Intialise and write the data blocks for a new journal as a contiguous
+ * extent. The indirect blocks pointing to these data blocks should have been
+ * written separately using lgfs2_write_filemeta() and the extent should have
+ * been allocated using lgfs2_file_alloc().
+ * ip: The journal's inode
+ * Returns 0 on success or -1 with errno set on error.
+ */
+int lgfs2_write_journal_data(struct gfs2_inode *ip)
+{
+	uint32_t hash;
+	struct gfs2_log_header lh = {
+		.lh_header.mh_magic = GFS2_MAGIC,
+		.lh_header.mh_type = GFS2_METATYPE_LH,
+		.lh_header.mh_format = GFS2_FORMAT_LH,
+		.lh_flags = GFS2_LOG_HEAD_UNMOUNT,
+	};
+	struct gfs2_buffer_head *bh;
+	struct gfs2_sbd *sdp = ip->i_sbd;
+	unsigned blocks = (ip->i_di.di_size + sdp->bsize - 1) / sdp->bsize;
+	uint64_t jext0 = ip->i_di.di_num.no_addr + ip->i_di.di_blocks - blocks;
+	uint64_t seq = ((blocks) * (random() / (RAND_MAX + 1.0)));
+
+	bh = bget(sdp, jext0);
+	if (bh == NULL)
+		return -1;
+
+	do {
+		lh.lh_sequence = seq;
+		lh.lh_blkno = bh->b_blocknr - jext0;
+		gfs2_log_header_out(&lh, bh);
+		hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header));
+		((struct gfs2_log_header *)bh->b_data)->lh_hash = cpu_to_be32(hash);
+
+		if (bwrite(bh)) {
+			free(bh);
+			return -1;
+		}
+
+		if (++seq == blocks)
+			seq = 0;
+
+	} while (++bh->b_blocknr < jext0 + blocks);
+
+	free(bh);
+	return 0;
+}
+
 int write_journal(struct gfs2_inode *jnl, unsigned bsize, unsigned int blocks)
 {
 	struct gfs2_log_header lh;
-- 
1.9.3




More information about the Cluster-devel mailing list