gfs2-utils: RHEL7 - libgfs2: Write file metadata sequentially

Andrew Price andyp at fedoraproject.org
Mon Sep 8 17:34:36 UTC 2014


Gitweb:        http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=443d8ee6df480d08db3e998a180b682ad0ed4210
Commit:        443d8ee6df480d08db3e998a180b682ad0ed4210
Parent:        75495994a710d09a8a9a7b6f4a09b73e01a2a772
Author:        Andrew Price <anprice at redhat.com>
AuthorDate:    Tue Aug 26 23:40:56 2014 +0100
Committer:     Andrew Price <anprice at redhat.com>
CommitterDate: Fri Sep 5 14:57:46 2014 +0100

libgfs2: Write file metadata sequentially

Until now the journal creation functions built up the height of the
journal metadata using incremental allocation and the build_height
function which grows a file naively. Two things are about to change:

1. We will guarantee that a journal will occupy a single extent.
2. Journals will be written out sequentially and will only required one
   write of the resource group header, before the journal is written.

Since we know the size of the extent and can predict the layout of the
journal's metadata tree, it is possible to generate and write the
metadata blocks in sequence. This patch adds an lgfs2_write_filemeta()
function which does just that.

Signed-off-by: Andrew Price <anprice at redhat.com>
---
 gfs2/libgfs2/fs_ops.c  |   69 ++++++++++++++++++++++++++++++++++++++++++++++++
 gfs2/libgfs2/libgfs2.h |    1 +
 2 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c
index 98db34d..9c9cc82 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -1412,6 +1412,75 @@ int init_dinode(struct gfs2_sbd *sdp, struct gfs2_buffer_head **bhp, struct gfs2
 	return __init_dinode(sdp, bhp, inum, mode, flags, parent, 0);
 }
 
+static void lgfs2_fill_indir(char *start, char *end, uint64_t ptr0, unsigned n, unsigned *p)
+{
+	char *bp;
+	memset(start, 0, end - start);
+	for (bp = start; bp < end && *p < n; bp += sizeof(uint64_t)) {
+		uint64_t pn = ptr0 + *p;
+		*(uint64_t *)bp = cpu_to_be64(pn);
+		(*p)++;
+	}
+}
+
+/**
+ * Calculate and write the indirect blocks for a single-extent file of a given
+ * size.
+ * ip: The inode for which to write indirect blocks, with fields already set
+ *     appropriately (see lgfs2_file_alloc).
+ * Returns 0 on success or non-zero with errno set on failure.
+ */
+int lgfs2_write_filemeta(struct gfs2_inode *ip)
+{
+	unsigned height = 0;
+	struct metapath mp;
+	struct gfs2_sbd *sdp = ip->i_sbd;
+	uint64_t dblocks = (ip->i_di.di_size + sdp->bsize - 1) / sdp->bsize;
+	uint64_t ptr0 = ip->i_di.di_num.no_addr + 1;
+	unsigned ptrs = 1;
+	struct gfs2_meta_header mh = {
+		.mh_magic = GFS2_MAGIC,
+		.mh_type = GFS2_METATYPE_IN,
+		.mh_format = GFS2_FORMAT_IN,
+	};
+	struct gfs2_buffer_head *bh = bget(sdp, ip->i_di.di_num.no_addr);
+	if (bh == NULL)
+		return 1;
+
+	/* Using find_metapath() to find the last data block in the file will
+	   effectively give a remainder for the number of pointers at each
+	   height. Just need to add 1 to convert ptr index to quantity later. */
+	find_metapath(ip, dblocks - 1, &mp);
+
+	for (height = 0; height < ip->i_di.di_height; height++) {
+		unsigned p;
+		/* The number of pointers in this height will be the number of
+		   full indirect blocks pointed to by the previous height
+		   multiplied by the pointer capacity of an indirect block,
+		   plus the remainder which find_metapath() gave us. */
+		ptrs = ((ptrs - 1) * sdp->sd_inptrs) + mp.mp_list[height] + 1;
+
+		for (p = 0; p < ptrs; bh->b_blocknr++) {
+			char *start = bh->b_data;
+			if (height == 0) {
+				start += sizeof(struct gfs2_dinode);
+				gfs2_dinode_out(&ip->i_di, bh);
+			} else {
+				start += sizeof(struct gfs2_meta_header);
+				gfs2_meta_header_out(&mh, bh->b_data);
+			}
+			lgfs2_fill_indir(start, bh->b_data + sdp->bsize, ptr0, ptrs, &p);
+			if(bwrite(bh)) {
+				free(bh);
+				return 1;
+			}
+		}
+		ptr0 += ptrs;
+	}
+	free(bh);
+	return 0;
+}
+
 static struct gfs2_inode *__createi(struct gfs2_inode *dip,
 				    const char *filename, unsigned int mode,
 				    uint32_t flags, int if_gfs1)
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index d683dc7..c7adbc1 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_filemeta(struct gfs2_inode *ip);
 
 /* gfs1.c - GFS1 backward compatibility structures and functions */
 


More information about the cluster-commits mailing list