Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=e23... Commit: e23761e752f496399c51d74c557f302378eb1427 Parent: 11f4970cfaa3f7448a0f1c78f1e9ce4bd2fb43df Author: Bob Peterson rpeterso@redhat.com AuthorDate: Wed Mar 17 09:46:09 2010 -0500 Committer: Bob Peterson rpeterso@redhat.com CommitterDate: Wed Mar 17 09:46:09 2010 -0500
GFS2: fsck.gfs2 segfault - osi_tree "each_safe" patch
There are a few places in fsck.gfs2 where each element of the new rbtrees are processed. Some of those places delete items from the rbtree, which means I need to use the equivalent of osi_list_foreach_safe. In other words, I needed to prevent rbtree deletes from interfering with the next() function. The result was a segfault in fsck.gfs2 in a few places. This patch implements the "safe" rbtree traversal and fixes the problem.
rhbz#574215 --- gfs2/fsck/link.c | 2 -- gfs2/fsck/pass1b.c | 10 ++++++---- gfs2/fsck/pass3.c | 5 +++-- gfs2/fsck/pass4.c | 5 +++-- 4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/gfs2/fsck/link.c b/gfs2/fsck/link.c index 0314074..5bb3ae2 100644 --- a/gfs2/fsck/link.c +++ b/gfs2/fsck/link.c @@ -67,8 +67,6 @@ int decrement_link(uint64_t inode_no, uint64_t referenced_from, ii = inodetree_find(inode_no); /* If the list has entries, look for one that matches * inode_no */ - log_err( _("Decrementing %"PRIu64" (0x%" PRIx64 ") to %d\n"), - inode_no, inode_no, ii->counted_links); if(ii) { ii->counted_links--; log_debug( _("Directory %lld (0x%llx) decremented counted " diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c index 5554325..680eb38 100644 --- a/gfs2/fsck/pass1b.c +++ b/gfs2/fsck/pass1b.c @@ -168,12 +168,13 @@ static int find_dentry(struct gfs2_inode *ip, struct gfs2_dirent *de, struct gfs2_buffer_head *bh, char *filename, uint16_t *count, void *priv) { - struct osi_node *n; + struct osi_node *n, *next = NULL; osi_list_t *tmp2; struct duptree *b; int found;
- for (n = osi_first(&dup_blocks); n; n = osi_next(n)) { + for (n = osi_first(&dup_blocks); n; n = next) { + next = osi_next(n); b = (struct duptree *)n; found = 0; osi_list_foreach(tmp2, &b->ref_invinode_list) { @@ -600,7 +601,7 @@ int pass1b(struct gfs2_sbd *sbp) struct duptree *b; uint64_t i; uint8_t q; - struct osi_node *n; + struct osi_node *n, *next = NULL; int rc = FSCK_OK;
log_info( _("Looking for duplicate blocks...\n")); @@ -650,7 +651,8 @@ int pass1b(struct gfs2_sbd *sbp) * it later */ log_info( _("Handling duplicate blocks\n")); out: - for (n = osi_first(&dup_blocks); n; n = osi_next(n)) { + for (n = osi_first(&dup_blocks); n; n = next) { + next = osi_next(n); b = (struct duptree *)n; if (!skip_this_pass && !rc) /* no error & not asked to skip the rest */ handle_dup_blk(sbp, b); diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c index a15c63f..e1fe5a5 100644 --- a/gfs2/fsck/pass3.c +++ b/gfs2/fsck/pass3.c @@ -172,7 +172,7 @@ static struct dir_info *mark_and_return_parent(struct gfs2_sbd *sbp, */ int pass3(struct gfs2_sbd *sbp) { - struct osi_node *tmp; + struct osi_node *tmp, *next = NULL; struct dir_info *di, *tdi; struct gfs2_inode *ip; uint8_t q; @@ -193,7 +193,8 @@ int pass3(struct gfs2_sbd *sbp) * find a parent, put in lost+found. */ log_info( _("Checking directory linkage.\n")); - for (tmp = osi_first(&dirtree); tmp; tmp = osi_next(tmp)) { + for (tmp = osi_first(&dirtree); tmp; tmp = next) { + next = osi_next(tmp); di = (struct dir_info *)tmp; while(!di->checked) { /* FIXME: Change this so it returns success or diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c index d79f8e5..0fd0aac 100644 --- a/gfs2/fsck/pass4.c +++ b/gfs2/fsck/pass4.c @@ -40,7 +40,7 @@ static int fix_link_count(struct inode_info *ii, struct gfs2_inode *ip) }
static int scan_inode_list(struct gfs2_sbd *sbp) { - struct osi_node *tmp; + struct osi_node *tmp, *next = NULL; struct inode_info *ii; struct gfs2_inode *ip; int lf_addition = 0; @@ -48,9 +48,10 @@ static int scan_inode_list(struct gfs2_sbd *sbp) {
/* FIXME: should probably factor this out into a generic * scanning fxn */ - for (tmp = osi_first(&inodetree); tmp; tmp = osi_next(tmp)) { + for (tmp = osi_first(&inodetree); tmp; tmp = next) { if (skip_this_pass || fsck_abort) /* if asked to skip the rest */ return 0; + next = osi_next(tmp); if(!(ii = (struct inode_info *)tmp)) { log_crit( _("osi_tree broken in scan_info_list!!\n")); exit(FSCK_ERROR);