Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 9383e745e23602bc45f9c92184feea59 > files > 19

gfs2-utils-0.1.62-28.el5.src.rpm

commit cb66bfe79239309ace78c06f3548fb402be4e201
Author: Bob Peterson <bob@ganesha.peterson>
Date:   Thu Jan 21 14:01:44 2010 -0600

    fsck.gfs2: convert inode hash to rbtree
    
    This patch converts the inode hash table to an rbtree to speed
    things up.
    
    rhbz#455300

diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index 0e56a2f..44ab03b 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -37,7 +37,7 @@
 
 struct inode_info
 {
-        osi_list_t list;
+        struct osi_node node;
         uint64_t   inode;
         uint16_t   link_count;   /* the number of links the inode
                                   * thinks it has */
@@ -126,7 +126,6 @@ struct dir_info *dirtree_insert(uint64_t dblock);
 
 extern struct gfs2_options opts;
 extern struct gfs2_inode *lf_dip; /* Lost and found directory inode */
-extern osi_list_t inode_hash[FSCK_HASH_SIZE];
 extern struct gfs2_bmap *bl;
 extern uint64_t last_fs_block, last_reported_block;
 extern int64_t last_reported_fblock;
@@ -136,5 +135,6 @@ extern uint64_t last_data_block;
 extern uint64_t first_data_block;
 extern struct osi_root dup_blocks;
 extern struct osi_root dirtree;
+extern struct osi_root inodetree;
 
 #endif /* _FSCK_H */
diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c
index f9c3251..2687bdb 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -30,7 +30,8 @@
 #include "fsck.h"
 #include "util.h"
 #include "fs_recovery.h"
-#include "linux_endian.h"
+#include "metawalk.h"
+#include "inode_hash.h"
 
 #define CLEAR_POINTER(x) \
 	if(x) { \
@@ -94,6 +95,17 @@ static void gfs2_dirtree_free(void)
 	}
 }
 
+static void gfs2_inodetree_free(void)
+{
+	struct osi_node *n;
+	struct inode_info *dt;
+
+	while ((n = osi_first(&inodetree))) {
+		dt = (struct inode_info *)n;
+		inodetree_delete(dt);
+	}
+}
+
 /*
  * empty_super_block - free all structures in the super block
  * sdp: the in-core super block
@@ -105,22 +117,12 @@ static void gfs2_dirtree_free(void)
  */
 static void empty_super_block(struct gfs2_sbd *sdp)
 {
-	uint32_t i;
-
 	log_info( _("Freeing buffers.\n"));
 	gfs2_rgrp_free(&sdp->rglist);
 
-	for(i = 0; i < FSCK_HASH_SIZE; i++) {
-		while(!osi_list_empty(&inode_hash[i])) {
-			struct inode_info *ii;
-			ii = osi_list_entry(inode_hash[i].next, struct inode_info, list);
-			osi_list_del(&ii->list);
-			free(ii);
-		}
-	}
-
 	if (bl)
 		gfs2_bmap_destroy(sdp, bl);
+	gfs2_inodetree_free();
 	gfs2_dirtree_free();
 	gfs2_dup_free();
 }
@@ -428,8 +430,6 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
  */
 static int fill_super_block(struct gfs2_sbd *sdp)
 {
-	uint32_t i;
-
 	sync();
 
 	/********************************************************************
@@ -437,8 +437,6 @@ static int fill_super_block(struct gfs2_sbd *sdp)
 	 ********************************************************************/
 	log_info( _("Initializing lists...\n"));
 	osi_list_init(&sdp->rglist);
-	for(i = 0; i < FSCK_HASH_SIZE; i++)
-		osi_list_init(&inode_hash[i]);
 
 	/********************************************************************
 	 ************  next, read in on-disk SB and set constants  **********
diff --git a/gfs2/fsck/inode_hash.c b/gfs2/fsck/inode_hash.c
index 1c94b32..b23fe08 100644
--- a/gfs2/fsck/inode_hash.c
+++ b/gfs2/fsck/inode_hash.c
@@ -13,78 +13,69 @@
 
 #include <stdint.h>
 #include <unistd.h>
+#include <libintl.h>
 
 #include "libgfs2.h"
 #include "osi_list.h"
 #include "hash.h"
 #include "inode_hash.h"
 #include "fsck.h"
+#define _(String) gettext(String)
 
-static uint32_t gfs2_inode_hash(uint64_t block_no)
+struct inode_info *inodetree_find(uint64_t block)
 {
-	unsigned int h;
+	struct osi_node *node = inodetree.osi_node;
 
-	h = fsck_hash(&block_no, sizeof (uint64_t));
-	h &= FSCK_HASH_MASK;
+	while (node) {
+		struct inode_info *data = (struct inode_info *)node;
 
-	return h;
-}
-
-struct inode_info *inode_hash_search(osi_list_t *buckets, uint64_t key)
-{
-	struct inode_info *ii;
-	osi_list_t *tmp;
-	osi_list_t *bucket = &buckets[gfs2_inode_hash(key)];
-
-	osi_list_foreach(tmp, bucket) {
-		ii = osi_list_entry(tmp, struct inode_info, list);
-		if(ii->inode == key) {
-			return ii;
-		}
+		if (block < data->inode)
+			node = node->osi_left;
+		else if (block > data->inode)
+			node = node->osi_right;
+		else
+			return data;
 	}
 	return NULL;
 }
 
-int inode_hash_insert(osi_list_t *buckets, uint64_t key, struct inode_info *ii)
+struct inode_info *inodetree_insert(uint64_t dblock)
 {
-	osi_list_t *tmp;
-	osi_list_t *bucket = &buckets[gfs2_inode_hash(key)];
-	struct inode_info *itmp = NULL;
+	struct osi_node **newn = &inodetree.osi_node, *parent = NULL;
+	struct inode_info *data;
+
+	/* Figure out where to put new node */
+	while (*newn) {
+		struct inode_info *cur = (struct inode_info *)*newn;
 
-	if(osi_list_empty(bucket)) {
-		osi_list_add(&ii->list, bucket);
-		return 0;
+		parent = *newn;
+		if (dblock < cur->inode)
+			newn = &((*newn)->osi_left);
+		else if (dblock > cur->inode)
+			newn = &((*newn)->osi_right);
+		else
+			return cur;
 	}
 
-	osi_list_foreach(tmp, bucket) {
-		itmp = osi_list_entry(tmp, struct inode_info, list);
-		if(itmp->inode < key) {
-			continue;
-		} else {
-			osi_list_add_prev(&ii->list, tmp);
-			return 0;
-		}
+	data = malloc(sizeof(struct inode_info));
+	if (!data) {
+		log_crit( _("Unable to allocate inode_info structure\n"));
+		return NULL;
 	}
-	osi_list_add_prev(&ii->list, bucket);
-	return 0;
-}
+	if (!memset(data, 0, sizeof(struct inode_info))) {
+		log_crit( _("Error while zeroing inode_info structure\n"));
+		return NULL;
+	}
+	/* Add new node and rebalance tree. */
+	data->inode = dblock;
+	osi_link_node(&data->node, parent, newn);
+	osi_insert_color(&data->node, &inodetree);
 
+	return data;
+}
 
-int inode_hash_remove(osi_list_t *buckets, uint64_t key)
+void inodetree_delete(struct inode_info *b)
 {
-	osi_list_t *tmp;
-	osi_list_t *bucket = &buckets[gfs2_inode_hash(key)];
-	struct inode_info *itmp = NULL;
-
-	if(osi_list_empty(bucket)) {
-		return -1;
-	}
-	osi_list_foreach(tmp, bucket) {
-		itmp = osi_list_entry(tmp, struct inode_info, list);
-		if(itmp->inode == key) {
-			osi_list_del(tmp);
-			return 0;
-		}
-	}
-	return -1;
+	osi_erase(&b->node, &inodetree);
+	free(b);
 }
diff --git a/gfs2/fsck/inode_hash.h b/gfs2/fsck/inode_hash.h
index b2f0f26..3495ddc 100644
--- a/gfs2/fsck/inode_hash.h
+++ b/gfs2/fsck/inode_hash.h
@@ -14,9 +14,10 @@
 #ifndef _INODE_HASH_H
 #define _INODE_HASH_H
 
-struct inode_info *inode_hash_search(osi_list_t *buckets, uint64_t block_no);
-int inode_hash_insert(osi_list_t *buckets, uint64_t key,
-					  struct inode_info *ii);
-int inode_hash_remove(osi_list_t *buckets, uint64_t key);
+struct inode_info;
+
+extern struct inode_info *inodetree_find(uint64_t block);
+extern struct inode_info *inodetree_insert(uint64_t dblock);
+extern void inodetree_delete(struct inode_info *b);
 
 #endif /* _INODE_HASH_H */
diff --git a/gfs2/fsck/link.c b/gfs2/fsck/link.c
index 96dc261..b6870c8 100644
--- a/gfs2/fsck/link.c
+++ b/gfs2/fsck/link.c
@@ -24,37 +24,19 @@
 #include "inode_hash.h"
 #include "link.h"
 
-int set_link_count(struct gfs2_sbd *sbp, uint64_t inode_no, uint32_t count)
+int set_link_count(uint64_t inode_no, uint32_t count)
 {
-	struct inode_info *ii = NULL;
-	log_debug( _("Setting link count to %u for %" PRIu64 " (0x%" PRIx64 ")\n"),
-			  count, inode_no, inode_no);
-	/* If the list has entries, look for one that matches
-	 * inode_no */
-	ii = inode_hash_search(inode_hash, inode_no);
-	if(ii) {
-		if(ii->link_count) {
-			log_err( _("Link count already set for inode #%" PRIu64 " (0x%"
-					PRIx64 ")!\n"), inode_no, inode_no);
-			stack;
-			return -1;
-		}
-		else
-			ii->link_count = count;
-	}
-	else {
-		/* If not match was found, add a new entry and set it's
-		 * link count to count*/
-		if(!(ii = (struct inode_info *) malloc(sizeof(*ii)))) {
-			log_err( _("Unable to allocate inode_info structure\n"));
-			stack;
-			return -1;
-		}
-		memset(ii, 0, sizeof(*ii));
-		ii->inode = inode_no;
+	struct inode_info *ii;
+	/*log_debug( _("Setting link count to %u for %" PRIu64
+	  " (0x%" PRIx64 ")\n"), count, inode_no, inode_no);*/
+	/* If the list has entries, look for one that matches inode_no */
+	ii = inodetree_find(inode_no);
+	if (!ii)
+		ii = inodetree_insert(inode_no);
+	if (ii)
 		ii->link_count = count;
-		inode_hash_insert(inode_hash, inode_no, ii);
-	}
+	else
+		return -1;
 	return 0;
 }
 
@@ -62,7 +44,7 @@ int increment_link(struct gfs2_sbd *sbp, uint64_t inode_no)
 {
 	struct inode_info *ii = NULL;
 
-	ii = inode_hash_search(inode_hash, inode_no);
+	ii = inodetree_find(inode_no);
 	/* If the list has entries, look for one that matches
 	 * inode_no */
 	if(ii) {
@@ -75,20 +57,11 @@ int increment_link(struct gfs2_sbd *sbp, uint64_t inode_no)
 			  " (0x%" PRIx64 ")!\n"), inode_no, inode_no);
 	/* If no match was found, add a new entry and set its
 	 * counted links to 1 */
-	if(!(ii = (struct inode_info *) malloc(sizeof(*ii)))) {
-		log_err( _("Unable to allocate inode_info structure\n"));
-		stack;
-		return -1;
-	}
-	if(!memset(ii, 0, sizeof(*ii))) {
-		log_err( _("Unable to zero inode_info structure\n"));
-		stack;
+	ii = inodetree_insert(inode_no);
+	if (ii)
+		ii->counted_links = 1;
+	else
 		return -1;
-	}
-	ii->inode = inode_no;
-	ii->counted_links = 1;
-	inode_hash_insert(inode_hash, inode_no, ii);
-
 	return 0;
 }
 
@@ -96,7 +69,7 @@ int decrement_link(struct gfs2_sbd *sbp, uint64_t inode_no)
 {
 	struct inode_info *ii = NULL;
 
-	ii = inode_hash_search(inode_hash, inode_no);
+	ii = inodetree_find(inode_no);
 	/* If the list has entries, look for one that matches
 	 * inode_no */
 	log_err( _("Decrementing %"PRIu64" (0x%" PRIx64 ")\n"), inode_no, inode_no);
diff --git a/gfs2/fsck/link.h b/gfs2/fsck/link.h
index 96a3d87..0509255 100644
--- a/gfs2/fsck/link.h
+++ b/gfs2/fsck/link.h
@@ -15,7 +15,7 @@
 #ifndef _LINK_H
 #define _LINK_H
 
-int set_link_count(struct gfs2_sbd *sbp, uint64_t inode_no, uint32_t count);
+int set_link_count(uint64_t inode_no, uint32_t count);
 int increment_link(struct gfs2_sbd *sbp, uint64_t inode_no);
 int decrement_link(struct gfs2_sbd *sbp, uint64_t inode_no);
 
diff --git a/gfs2/fsck/main.c b/gfs2/fsck/main.c
index 52f6204..a4fefb5 100644
--- a/gfs2/fsck/main.c
+++ b/gfs2/fsck/main.c
@@ -31,8 +31,6 @@
 
 struct gfs2_options opts = {0};
 struct gfs2_inode *lf_dip; /* Lost and found directory inode */
-osi_list_t dir_hash[FSCK_HASH_SIZE];
-osi_list_t inode_hash[FSCK_HASH_SIZE];
 struct gfs2_bmap *bl = NULL;
 uint64_t last_fs_block, last_reported_block = -1;
 int64_t last_reported_fblock = -1000000;
@@ -45,6 +43,7 @@ const char *prog_name = "gfs2_fsck"; /* needed by libgfs2 */
 int preen = 0, force_check = 0;
 struct osi_root dup_blocks = (struct osi_root) { NULL, };
 struct osi_root dirtree = (struct osi_root) { NULL, };
+struct osi_root inodetree = (struct osi_root) { NULL, };
 
 /* This function is for libgfs2's sake.                                      */
 void print_it(const char *label, const char *fmt, const char *fmt2, ...)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index bd0230d..a3029d7 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -34,6 +34,7 @@
 
 #include "libgfs2.h"
 #include "fsck.h"
+#include "inode_hash.h"
 #include "util.h"
 #include "link.h"
 #include "linux_endian.h"
@@ -723,7 +724,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 		fsck_inode_put(&ip);
 		return 0;
 	}
-	if(set_link_count(ip->i_sbd, ip->i_di.di_num.no_addr, ip->i_di.di_nlink)) {
+	if(set_link_count(ip->i_di.di_num.no_addr, ip->i_di.di_nlink)) {
 		stack;
 		fsck_inode_put(&ip);
 		return -1;
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index d035e4f..7d10917 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -178,7 +178,6 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
 		log_err( _("Inode %s is in directory %"PRIu64" (0x%" PRIx64 ")\n"),
 			 dh->id->name ? dh->id->name : "", dh->id->parent,
 			 dh->id->parent);
-		inode_hash_remove(inode_hash, ip->i_di.di_num.no_addr);
 		/* Setting the block to invalid means the inode is
 		 * cleared in pass2 */
 		gfs2_blockmap_set(ip->i_sbd, bl, ip->i_di.di_num.no_addr,
@@ -423,12 +422,15 @@ static int handle_dup_blk(struct gfs2_sbd *sbp, struct duptree *b)
 				  (unsigned long long)b->block,
 				  (unsigned long long)b->block);
 			if (query( _("Clear the inode? (y/n) "))) {
+				struct inode_info *ii;
+
 				log_warn( _("Clearing inode %lld (0x%llx)...\n"),
 					 (unsigned long long)id->block_no,
 					 (unsigned long long)id->block_no);
 				ip = fsck_load_inode(sbp, id->block_no);
-				inode_hash_remove(inode_hash,
-						  ip->i_di.di_num.no_addr);
+				ii = inodetree_find(ip->i_di.di_num.no_addr);
+				if (ii)
+					inodetree_delete(ii);
 				/* Setting the block to invalid means the inode
 				   is cleared in pass2 */
 				gfs2_blockmap_set(ip->i_sbd, bl,
diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c
index eb4f413..eff47aa 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -34,8 +34,7 @@ struct metawalk_fxns pass4_fxns_delete = {
 
 /* Updates the link count of an inode to what the fsck has seen for
  * link count */
-static int fix_inode_count(struct gfs2_sbd *sbp, struct inode_info *ii,
-					struct gfs2_inode *ip)
+static int fix_link_count(struct inode_info *ii, struct gfs2_inode *ip)
 {
 	log_info( _("Fixing inode link count (%d->%d) for %llu (0x%llx) \n"),
 		  ip->i_di.di_nlink, ii->counted_links,
@@ -53,8 +52,8 @@ static int fix_inode_count(struct gfs2_sbd *sbp, struct inode_info *ii,
 	return 0;
 }
 
-static int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
-	osi_list_t *tmp;
+static int scan_inode_list(struct gfs2_sbd *sbp) {
+	struct osi_node *tmp;
 	struct inode_info *ii;
 	struct gfs2_inode *ip;
 	int lf_addition = 0;
@@ -62,11 +61,11 @@ static int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
 
 	/* FIXME: should probably factor this out into a generic
 	 * scanning fxn */
-	osi_list_foreach(tmp, list) {
+	for (tmp = osi_first(&inodetree); tmp; tmp = osi_next(tmp)) {
 		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
 			return 0;
-		if(!(ii = osi_list_entry(tmp, struct inode_info, list))) {
-			log_crit( _("osi_list_foreach broken in scan_info_list!!\n"));
+		if(!(ii = (struct inode_info *)tmp)) {
+			log_crit( _("osi_tree broken in scan_info_list!!\n"));
 			exit(FSCK_ERROR);
 		}
 		if(ii->counted_links == 0) {
@@ -142,7 +141,7 @@ static int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
 					fsck_inode_put(&ip);
 					return -1;
 				} else {
-					fix_inode_count(sbp, ii, ip);
+					fix_link_count(ii, ip);
 					lf_addition = 1;
 				}
 			} else
@@ -159,8 +158,8 @@ static int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
 				    " (0x%" PRIx64 ") ? (y/n) "),
 				  ii->inode, ii->inode)) {
 				ip = fsck_load_inode(sbp, ii->inode); /* bread, inode_get */
-				fix_inode_count(sbp, ii, ip);
-				bmodified(ip->i_bh);
+				fix_link_count(ii, ip);
+				ii->link_count = ii->counted_links;
 				fsck_inode_put(&ip); /* out, brelse, free */
 				log_warn( _("Link count updated to %d for "
 					    "inode %" PRIu64 " (0x%"
@@ -176,12 +175,11 @@ static int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
 	} /* osi_list_foreach(tmp, list) */
 
 	if (lf_addition) {
-		if(!(ii = inode_hash_search(inode_hash,
-									lf_dip->i_di.di_num.no_addr))) {
+		if(!(ii = inodetree_find(lf_dip->i_di.di_num.no_addr))) {
 			log_crit( _("Unable to find lost+found inode in inode_hash!!\n"));
 			return -1;
 		} else {
-			fix_inode_count(sbp, ii, lf_dip);
+			fix_link_count(ii, lf_dip);
 		}
 	}
 
@@ -199,20 +197,13 @@ static int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
  */
 int pass4(struct gfs2_sbd *sbp)
 {
-	uint32_t i;
-	osi_list_t *list;
 	if(lf_dip)
 		log_debug( _("At beginning of pass4, lost+found entries is %u\n"),
 				  lf_dip->i_di.di_entries);
 	log_info( _("Checking inode reference counts.\n"));
-	for (i = 0; i < FSCK_HASH_SIZE; i++) {
-		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
-			return FSCK_OK;
-		list = &inode_hash[i];
-		if(scan_inode_list(sbp, list)) {
-			stack;
-			return FSCK_ERROR;
-		}
+	if(scan_inode_list(sbp)) {
+		stack;
+		return FSCK_ERROR;
 	}
 
 	if(lf_dip)