This is the mail archive of the cluster-cvs@sourceware.org mailing list for the cluster.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

cluster: RHEL5 - Fix gfs2_fsck segfault


Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=ff07f9f1f267a66de0b7428a5f3c5fee0c5e4d6f
Commit:        ff07f9f1f267a66de0b7428a5f3c5fee0c5e4d6f
Parent:        b08a992e52144b2f6fa6424dd4c69ab705f5d4e1
Author:        Bob Peterson <rpeterso@redhat.com>
AuthorDate:    Mon Apr 20 12:33:00 2009 -0500
Committer:     Bob Peterson <rpeterso@redhat.com>
CommitterDate: Mon Apr 20 12:33:00 2009 -0500

Fix gfs2_fsck segfault

bz 496330

The gfs2_fsck tool was segfaulting if gfs2 had any blocks
assigned to two different purposes.  There were two problems.
First, struct blocks was not big enough to handle the data
that pass1b needed for duplicate processing.  Second,
function pass1b() was improperly referencing the duplicate
blocks list.
---
 gfs2/fsck/pass1b.c        |   25 +++++++----------
 gfs2/libgfs2/block_list.c |   63 ++++++++++++++++++++++++++++++++++++++++++---
 gfs2/libgfs2/libgfs2.h    |    8 +++++-
 3 files changed, 76 insertions(+), 20 deletions(-)

diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 1e4968a..0ca9191 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -33,12 +33,6 @@ struct inode_with_dups {
 	char *name;
 };
 
-struct blocks {
-	osi_list_t list;
-	uint64_t block_no;
-	osi_list_t ref_inode_list;
-};
-
 struct fxn_info {
 	uint64_t block;
 	int found;
@@ -46,7 +40,7 @@ struct fxn_info {
 };
 
 struct dup_handler {
-	struct blocks *b;
+	struct dup_blocks *b;
 	struct inode_with_dups *id;
 	int ref_inode_count;
 	int ref_count;
@@ -135,12 +129,12 @@ static int find_dentry(struct gfs2_inode *ip, struct gfs2_dirent *de,
 		       enum update_flags *update, uint16_t *count, void *priv)
 {
 	osi_list_t *tmp1, *tmp2;
-	struct blocks *b;
+	struct dup_blocks *b;
 	struct inode_with_dups *id;
 	struct gfs2_leaf leaf;
 
 	osi_list_foreach(tmp1, &ip->i_sbd->dup_blocks.list) {
-		b = osi_list_entry(tmp1, struct blocks, list);
+		b = osi_list_entry(tmp1, struct dup_blocks, list);
 		osi_list_foreach(tmp2, &b->ref_inode_list) {
 			id = osi_list_entry(tmp2, struct inode_with_dups,
 					    list);
@@ -348,7 +342,7 @@ static int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
 }
 
 /* Finds all references to duplicate blocks in the metadata */
-int find_block_ref(struct gfs2_sbd *sbp, uint64_t inode, struct blocks *b)
+int find_block_ref(struct gfs2_sbd *sbp, uint64_t inode, struct dup_blocks *b)
 {
 	struct gfs2_inode *ip;
 	struct fxn_info myfi = {b->block_no, 0, 1};
@@ -403,7 +397,7 @@ int find_block_ref(struct gfs2_sbd *sbp, uint64_t inode, struct blocks *b)
 	return 0;
 }
 
-int handle_dup_blk(struct gfs2_sbd *sbp, struct blocks *b)
+int handle_dup_blk(struct gfs2_sbd *sbp, struct dup_blocks *b)
 {
 	osi_list_t *tmp;
 	struct inode_with_dups *id;
@@ -467,7 +461,7 @@ int handle_dup_blk(struct gfs2_sbd *sbp, struct blocks *b)
  * use in pass2 */
 int pass1b(struct gfs2_sbd *sbp)
 {
-	struct blocks *b;
+	struct dup_blocks *b;
 	uint64_t i;
 	struct gfs2_block_query q;
 	osi_list_t *tmp = NULL, *x;
@@ -507,7 +501,8 @@ int pass1b(struct gfs2_sbd *sbp)
 		   (q.block_type == gfs2_inode_fifo) ||
 		   (q.block_type == gfs2_inode_sock)) {
 			osi_list_foreach_safe(tmp, &sbp->dup_blocks.list, x) {
-				b = osi_list_entry(tmp, struct blocks, list);
+				b = osi_list_entry(tmp, struct dup_blocks,
+						   list);
 				if(find_block_ref(sbp, i, b)) {
 					stack;
 					rc = FSCK_ERROR;
@@ -525,8 +520,8 @@ int pass1b(struct gfs2_sbd *sbp)
 	log_info("Handling duplicate blocks\n");
 out:
 	while (!osi_list_empty(&sbp->dup_blocks.list)) {
-		b = osi_list_entry(&sbp->dup_blocks.list.next, struct blocks,
-				   list);
+		b = osi_list_entry(sbp->dup_blocks.list.next,
+				   struct dup_blocks, list);
 		if (!skip_this_pass && !rc) /* no error & not asked to skip the rest */
 			handle_dup_blk(sbp, b);
 		osi_list_del(&b->list);
diff --git a/gfs2/libgfs2/block_list.c b/gfs2/libgfs2/block_list.c
index 054a5e4..67de5e1 100644
--- a/gfs2/libgfs2/block_list.c
+++ b/gfs2/libgfs2/block_list.c
@@ -63,6 +63,19 @@ void gfs2_special_free(struct special_blocks *blist)
 	}
 }
 
+void gfs2_dup_free(struct dup_blocks *blist)
+{
+	struct dup_blocks *f;
+
+	while(!osi_list_empty(&blist->list)) {
+		f = osi_list_entry(blist->list.next, struct dup_blocks, list);
+		while (!osi_list_empty(&f->ref_inode_list))
+			osi_list_del(&f->ref_inode_list);
+		osi_list_del(&f->list);
+		free(f);
+	}
+}
+
 struct special_blocks *blockfind(struct special_blocks *blist, uint64_t num)
 {
 	osi_list_t *head = &blist->list;
@@ -77,6 +90,20 @@ struct special_blocks *blockfind(struct special_blocks *blist, uint64_t num)
 	return NULL;
 }
 
+struct dup_blocks *dupfind(struct dup_blocks *blist, uint64_t num)
+{
+	osi_list_t *head = &blist->list;
+	osi_list_t *tmp;
+	struct dup_blocks *b;
+
+	for (tmp = head->next; tmp != head; tmp = tmp->next) {
+		b = osi_list_entry(tmp, struct dup_blocks, list);
+		if (b->block_no == num)
+			return b;
+	}
+	return NULL;
+}
+
 void gfs2_special_set(struct special_blocks *blocklist, uint64_t block)
 {
 	struct special_blocks *b;
@@ -85,12 +112,29 @@ void gfs2_special_set(struct special_blocks *blocklist, uint64_t block)
 		return;
 	b = malloc(sizeof(struct special_blocks));
 	if (b) {
+		memset(b, 0, sizeof(*b));
 		b->block = block;
 		osi_list_add(&b->list, &blocklist->list);
 	}
 	return;
 }
 
+void gfs2_dup_set(struct dup_blocks *blocklist, uint64_t block)
+{
+	struct dup_blocks *b;
+
+	if (dupfind(blocklist, block))
+		return;
+	b = malloc(sizeof(struct dup_blocks));
+	if (b) {
+		memset(b, 0, sizeof(*b));
+		b->block_no = block;
+		osi_list_init(&b->ref_inode_list);
+		osi_list_add(&b->list, &blocklist->list);
+	}
+	return;
+}
+
 void gfs2_special_clear(struct special_blocks *blocklist, uint64_t block)
 {
 	struct special_blocks *b;
@@ -102,6 +146,17 @@ void gfs2_special_clear(struct special_blocks *blocklist, uint64_t block)
 	}
 }
 
+void gfs2_dup_clear(struct dup_blocks *blocklist, uint64_t block)
+{
+	struct dup_blocks *b;
+
+	b = dupfind(blocklist, block);
+	if (b) {
+		osi_list_del(&b->list);
+		free(b);
+	}
+}
+
 int gfs2_block_mark(struct gfs2_sbd *sdp, struct gfs2_block_list *il,
 		    uint64_t block, enum gfs2_mark_block mark)
 {
@@ -110,7 +165,7 @@ int gfs2_block_mark(struct gfs2_sbd *sdp, struct gfs2_block_list *il,
 	if(mark == gfs2_bad_block)
 		gfs2_special_set(&sdp->bad_blocks, block);
 	else if(mark == gfs2_dup_block)
-		gfs2_special_set(&sdp->dup_blocks, block);
+		gfs2_dup_set(&sdp->dup_blocks, block);
 	else if(mark == gfs2_eattr_block)
 		gfs2_special_set(&sdp->eattr_blocks, block);
 	else
@@ -126,7 +181,7 @@ int gfs2_block_clear(struct gfs2_sbd *sdp, struct gfs2_block_list *il,
 
 	switch (m) {
 	case gfs2_dup_block:
-		gfs2_special_clear(&sdp->dup_blocks, block);
+		gfs2_dup_clear(&sdp->dup_blocks, block);
 		break;
 	case gfs2_bad_block:
 		gfs2_special_clear(&sdp->bad_blocks, block);
@@ -166,7 +221,7 @@ int gfs2_block_check(struct gfs2_sbd *sdp, struct gfs2_block_list *il,
 		return err;
 	if (blockfind(&sdp->bad_blocks, block))
 		val->bad_block = 1;
-	if (blockfind(&sdp->dup_blocks, block))
+	if (dupfind(&sdp->dup_blocks, block))
 		val->dup_block = 1;
 	if (blockfind(&sdp->eattr_blocks, block))
 		val->eattr_block = 1;
@@ -181,7 +236,7 @@ void *gfs2_block_list_destroy(struct gfs2_sbd *sdp, struct gfs2_block_list *il)
 		il = NULL;
 	}
 	gfs2_special_free(&sdp->bad_blocks);
-	gfs2_special_free(&sdp->dup_blocks);
+	gfs2_dup_free(&sdp->dup_blocks);
 	gfs2_special_free(&sdp->eattr_blocks);
 	return il;
 }
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 110c2c7..57c8fd6 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -123,6 +123,12 @@ struct gfs2_buffer_head {
 	int b_changed;
 };
 
+struct dup_blocks {
+	osi_list_t list;
+	uint64_t block_no;
+	osi_list_t ref_inode_list;
+};
+
 struct special_blocks {
 	osi_list_t list;
 	uint64_t block;
@@ -254,7 +260,7 @@ struct gfs2_sbd {
 	int metafs_mounted; /* If metafs was already mounted */
 	char metafs_path[PATH_MAX]; /* where metafs is mounted */
 	struct special_blocks bad_blocks;
-	struct special_blocks dup_blocks;
+	struct dup_blocks dup_blocks;
 	struct special_blocks eattr_blocks;
 };
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]