From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 16946 invoked by alias); 20 Apr 2009 18:31:56 -0000 Received: (qmail 16898 invoked by alias); 20 Apr 2009 18:31:55 -0000 X-SWARE-Spam-Status: No, hits=-0.4 required=5.0 tests=AWL,BAYES_00,J_CHICKENPOX_24,J_CHICKENPOX_41,J_CHICKENPOX_61,SPF_HELO_PASS X-Spam-Status: No, hits=-0.4 required=5.0 tests=AWL,BAYES_00,J_CHICKENPOX_24,J_CHICKENPOX_41,J_CHICKENPOX_61,SPF_HELO_PASS X-Spam-Check-By: sourceware.org X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on bastion2.fedora.phx.redhat.com Subject: cluster: RHEL5 - Fix gfs2_fsck segfault To: cluster-cvs-relay@redhat.com X-Project: Cluster Project X-Git-Module: cluster.git X-Git-Refname: refs/heads/RHEL5 X-Git-Reftype: branch X-Git-Oldrev: b08a992e52144b2f6fa6424dd4c69ab705f5d4e1 X-Git-Newrev: ff07f9f1f267a66de0b7428a5f3c5fee0c5e4d6f From: Bob Peterson Message-Id: <20090420183131.5DC3512019B@lists.fedorahosted.org> Date: Mon, 20 Apr 2009 18:31:00 -0000 X-Scanned-By: MIMEDefang 2.58 on 172.16.52.254 Mailing-List: contact cluster-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: cluster-cvs-owner@sourceware.org X-SW-Source: 2009-q2/txt/msg00085.txt.bz2 Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=ff07f9f1f267a66de0b7428a5f3c5fee0c5e4d6f Commit: ff07f9f1f267a66de0b7428a5f3c5fee0c5e4d6f Parent: b08a992e52144b2f6fa6424dd4c69ab705f5d4e1 Author: Bob Peterson AuthorDate: Mon Apr 20 12:33:00 2009 -0500 Committer: Bob Peterson 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; };