Gitweb:
http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: b83b1ee7f3cf0cf04ed52932e5c1e75259b9ecd2
Parent: bbd213cf02b9f427342d75e4c05d4cf95d80d8ef
Author: Bob Peterson <bob(a)ganesha.peterson>
AuthorDate: Fri Apr 9 20:00:03 2010 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Apr 9 23:45:34 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#455300
---
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 a39db33..525836d 100644
--- a/gfs2/fsck/link.c
+++ b/gfs2/fsck/link.c
@@ -80,8 +80,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 e00294a..8b67573 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -184,12 +184,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) {
@@ -616,7 +617,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"));
@@ -666,7 +667,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 b200d42..65736f1 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -185,7 +185,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;
@@ -206,7 +206,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 43f12bc..a8d2533 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -53,7 +53,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;
@@ -61,9 +61,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);