Sophie

Sophie

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

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

commit c30fd6a2560452a111dad8584951765d9ddb787b
Author: Bob Peterson <bob@ganesha.peterson>
Date:   Mon Jan 25 11:13:31 2010 -0600

    Create a standard metadata delete interface
    
    This patch creates a standard set of functions to delete metadata
    that has been deemed invalid.  The fsck.gfs2 program had several
    places where it would delete or invalidate blocks it deemed bad
    without regard to previous designation as a duplicate block
    reference.  A block would be marked data, then duplicate, then
    deleted, then the duplicate block was resolved, leaving it in a
    questionable state.  This lays some groundwork for deleteing
    blocks that already have duplicate references.
    
    rhbz#455300

diff --git a/gfs2/fsck/eattr.c b/gfs2/fsck/eattr.c
index 0eed835..c0de8b6 100644
--- a/gfs2/fsck/eattr.c
+++ b/gfs2/fsck/eattr.c
@@ -17,36 +17,8 @@
 
 #include "libgfs2.h"
 #include "fsck.h"
-#include "eattr.h"
 #include "metawalk.h"
-
-static int clear_blk_nodup(struct gfs2_inode *ip, uint64_t block)
-{
-	if(is_duplicate(block)) {
-		log_debug( _("Not clearing block with marked as a duplicate\n"));
-		return 1;
-	}
-
-	fsck_blockmap_set(ip, block, _("cleared eattr block"),
-			  gfs2_block_free);
-
-	return 0;
-
-}
-
-int clear_eattr_indir(struct gfs2_inode *ip, uint64_t block,
-		      uint64_t parent, struct gfs2_buffer_head **bh,
-		      void *private)
-{
-	return clear_blk_nodup(ip, block);
-}
-
-int clear_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
-		     uint64_t parent, struct gfs2_buffer_head **bh,
-		     void *private)
-{
-	return clear_blk_nodup(ip, block);
-}
+#include "eattr.h"
 
 int clear_eattr_entry (struct gfs2_inode *ip,
 		       struct gfs2_buffer_head *leaf_bh,
@@ -94,8 +66,7 @@ int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
 {
 	uint64_t block = be64_to_cpu(*ea_data_ptr);
 
-	return clear_blk_nodup(ip, block);
-
+	return delete_eattr_leaf(ip, block, 0, &leaf_bh, private);
 }
 
 
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index c4db990..fa7ef82 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -920,6 +920,63 @@ static int check_leaf_eattr(struct gfs2_inode *ip, uint64_t block,
 }
 
 /**
+ * delete_block - delete a block associated with an inode
+ */
+int delete_block(struct gfs2_inode *ip, uint64_t block,
+		 struct gfs2_buffer_head **bh, const char *btype,
+		 void *private)
+{
+	if (gfs2_check_range(ip->i_sbd, block) == 0) {
+		fsck_blockmap_set(ip, block, btype, gfs2_block_free);
+		return 0;
+	}
+	return -1;
+}
+
+/**
+ * delete_block_if_notdup - delete blocks associated with an inode
+ *
+ * Ignore blocks that are already marked free.
+ * If it has been identified as duplicate, remove the duplicate reference.
+ * If all duplicate references have been removed, delete the block.
+ */
+static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
+				  struct gfs2_buffer_head **bh,
+				  const char *btype, void *private)
+{
+	uint8_t q;
+	struct duptree *d;
+
+	if (gfs2_check_range(ip->i_sbd, block) != 0)
+		return -EFAULT;
+
+	q = block_type(block);
+	if (q == gfs2_block_free) {
+		log_info( _("%s block %lld (0x%llx), part of inode "
+			    "%lld (0x%llx), was already free.\n"),
+			  btype, (unsigned long long)block,
+			  (unsigned long long)block,
+			  (unsigned long long)ip->i_di.di_num.no_addr,
+			  (unsigned long long)ip->i_di.di_num.no_addr);
+		return 0;
+	}
+	d = dupfind(block);
+	if (d) {
+		log_info( _("Removing duplicate reference %d "
+			    "to block %lld (0x%llx).\n"), d->refs,
+			  (unsigned long long)block,
+			  (unsigned long long)block);
+		d->refs--; /* one less reference */
+		if (d->refs == 1) /* If down to the last reference */
+			dup_delete(d); /* not duplicate now */
+		return 1; /* but the original ref still exists
+			     so return (do not free it). */
+	}
+	fsck_blockmap_set(ip, block, btype, gfs2_block_free);
+	return 0;
+}
+
+/**
  * check_indirect_eattr
  * @ip: the inode the eattr comes from
  * @indirect_block
@@ -1001,11 +1058,9 @@ static int check_indirect_eattr(struct gfs2_inode *ip, uint64_t indirect,
 							 leaf_pointer_errors,
 							 pass->private);
 			}
-			if (leaf_pointer_errors == leaf_pointers) {
-				fsck_blockmap_set(ip, indirect,
-						  _("indirect extended "
-						    "attribute"),
-						  gfs2_block_free);
+			if (leaf_pointer_errors &&
+			    leaf_pointer_errors == leaf_pointers) {
+				delete_block(ip, indirect, NULL, "leaf", NULL);
 				error = 1;
 			}
 		}
@@ -1401,51 +1456,36 @@ int remove_dentry_from_dir(struct gfs2_sbd *sbp, uint64_t dir,
 	return error;
 }
 
-/**
- * delete_blocks - delete blocks associated with an inode
- */
-int delete_blocks(struct gfs2_inode *ip, uint64_t block,
-		  struct gfs2_buffer_head **bh, const char *btype,
-		  void *private)
+int delete_metadata(struct gfs2_inode *ip, uint64_t block,
+		    struct gfs2_buffer_head **bh, void *private)
 {
-	if (gfs2_check_range(ip->i_sbd, block) == 0) {
-		if(!is_duplicate(block)) {
-			log_info( _("Deleting %s block %lld (0x%llx) as part "
-				    "of inode %lld (0x%llx)\n"), btype,
-				  (unsigned long long)block,
-				  (unsigned long long)block,
-				  (unsigned long long)ip->i_di.di_num.no_addr,
-				  (unsigned long long)ip->i_di.di_num.no_addr);
-			fsck_blockmap_set(ip, block, btype, gfs2_block_free);
-			gfs2_free_block(ip->i_sbd, block);
-		}
-	}
-	return 0;
+	return delete_block_if_notdup(ip, block, bh, _("metadata"), private);
 }
 
-int delete_metadata(struct gfs2_inode *ip, uint64_t block,
-		    struct gfs2_buffer_head **bh, void *private)
+int delete_leaf(struct gfs2_inode *ip, uint64_t block,
+		struct gfs2_buffer_head *bh, void *private)
 {
-	return delete_blocks(ip, block, bh, _("metadata"), private);
+	return delete_block_if_notdup(ip, block, &bh, _("leaf"), private);
 }
 
 int delete_data(struct gfs2_inode *ip, uint64_t block, void *private)
 {
-	return delete_blocks(ip, block, NULL, _("data"), private);
+	return delete_block_if_notdup(ip, block, NULL, _("data"), private);
 }
 
 int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
 		       struct gfs2_buffer_head **bh, void *private)
 {
-	return delete_blocks(ip, block, NULL, _("indirect extended attribute"),
-			     private);
+	return delete_block_if_notdup(ip, block, NULL,
+				      _("indirect extended attribute"),
+				      private);
 }
 
 int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
 		      struct gfs2_buffer_head **bh, void *private)
 {
-	return delete_blocks(ip, block, NULL, _("extended attribute"),
-			     private);
+	return delete_block_if_notdup(ip, block, NULL, _("extended attribute"),
+				      private);
 }
 
 static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index c4c6d84..13f4c70 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -26,19 +26,19 @@ extern int check_dir(struct gfs2_sbd *sbp, uint64_t block,
 extern int check_linear_dir(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
 			    struct metawalk_fxns *pass);
 extern int remove_dentry_from_dir(struct gfs2_sbd *sbp, uint64_t dir,
-				  uint64_t dentryblock);
-extern int delete_blocks(struct gfs2_inode *ip, uint64_t block,
-			 struct gfs2_buffer_head **bh, const char *btype,
-			 void *private);
+						   uint64_t dentryblock);
+extern int delete_block(struct gfs2_inode *ip, uint64_t block,
+		 struct gfs2_buffer_head **bh, const char *btype,
+		 void *private);
 extern int delete_metadata(struct gfs2_inode *ip, uint64_t block,
-			   struct gfs2_buffer_head **bh, void *private);
+		    struct gfs2_buffer_head **bh, void *private);
+extern int delete_leaf(struct gfs2_inode *ip, uint64_t block,
+		struct gfs2_buffer_head *bh, void *private);
 extern int delete_data(struct gfs2_inode *ip, uint64_t block, void *private);
-extern int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block,
-			      uint64_t parent, struct gfs2_buffer_head **bh,
-			      void *private);
-extern int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
-			     uint64_t parent, struct gfs2_buffer_head **bh,
-			     void *private);
+extern int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
+		       struct gfs2_buffer_head **bh, void *private);
+extern int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
+		      struct gfs2_buffer_head **bh, void *private);
 extern int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
 		       const char *btype, enum gfs2_mark_block mark,
 		       const char *caller, int line);
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 78fb2d7..cbc981b 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -269,10 +269,8 @@ static int clear_eas(struct gfs2_inode *ip, struct block_count *bc,
 			log_err( _("The bad extended attribute was "
 				   "removed.\n"));
 		} else if (!duplicate) {
-			fsck_blockmap_set(ip, block, _("removed eattr"),
-					  gfs2_block_free);
-			log_err( _("The bad Extended Attribute was "
-				   "removed.\n"));
+			delete_block(ip, block, NULL,
+				     _("bad extended attribute"), NULL);
 		}
 		return 1;
 	} else {
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 480715d..c86140d 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -167,6 +167,7 @@ struct metawalk_fxns pass2_fxns_delete = {
 	.private = NULL,
 	.check_metalist = delete_metadata,
 	.check_data = delete_data,
+	.check_leaf = delete_leaf,
 	.check_eattr_indir = delete_eattr_indir,
 	.check_eattr_leaf = delete_eattr_leaf,
 };
@@ -193,8 +194,8 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 	gfs2_dirent_in(&dentry, (char *)dent);
 	de = &dentry;
 
-	clear_eattrs.check_eattr_indir = clear_eattr_indir;
-	clear_eattrs.check_eattr_leaf = clear_eattr_leaf;
+	clear_eattrs.check_eattr_indir = delete_eattr_indir;
+	clear_eattrs.check_eattr_leaf = delete_eattr_leaf;
 	clear_eattrs.check_eattr_entry = clear_eattr_entry;
 	clear_eattrs.check_eattr_extentry = clear_eattr_extentry;