cluster: RHEL6 - fsck.gfs2: replace recent i_goal fixes with simple logic
by Abhijith Das
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=75fa0e0b3bd...
Commit: 75fa0e0b3bdb82b368cd71f5fa43b8705aa93357
Parent: 353cec33e438d32a4be1a3eeb165abad57133864
Author: Abhi Das <adas(a)redhat.com>
AuthorDate: Sun Jul 5 23:49:05 2015 -0500
Committer: Abhi Das <adas(a)redhat.com>
CommitterDate: Fri Jul 10 11:03:06 2015 -0500
fsck.gfs2: replace recent i_goal fixes with simple logic
This patch reverses the recent set of i_goal fixes for fsck.gfs2.
This is because of two problems.
1. It is not possible to determine if a valid block within the fs
is the correct goal block for a given inode.
2. Conversely, given an inode, it is also not possible to accurately
determine what its goal block should be.
The previous patches assumed that the last block of a file is its
goal block, but that is not true if the file is a directory or if
its blocks are not allocated sequentially. fsck.gfs2 would flag
these inodes incorrectly as having bad i_goal values.
This patch takes a simple approach. It checks if the i_goal of a
given inode is out of bounds of the fs. If so, we can be certain
that it is wrong and we set it to the inode metadata block. This
is a safe starting point for gfs2 to determine where to allocate
from next.
This patch is already upstream and in RHEL7
Resolves: rhbz#1238754
Signed-off-by: Abhi Das <adas(a)redhat.com>
---
gfs2/fsck/metawalk.c | 86 +++---------------------------------------------
gfs2/fsck/metawalk.h | 5 ---
gfs2/fsck/pass1.c | 35 +++++++++++++++++---
gfs2/libgfs2/libgfs2.h | 1 -
4 files changed, 35 insertions(+), 92 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 07e5c18..959b905 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1333,8 +1333,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
*/
static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
struct gfs2_buffer_head *bh, int head_size,
- uint64_t *last_block, uint64_t *blks_checked,
- uint64_t *error_blk)
+ uint64_t *blks_checked, uint64_t *error_blk)
{
int error = 0, rc = 0;
uint64_t block, *ptr;
@@ -1349,7 +1348,7 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
if (skip_this_pass || fsck_abort)
return error;
- *last_block = block = be64_to_cpu(*ptr);
+ block = be64_to_cpu(*ptr);
/* It's important that we don't call valid_block() and
bypass calling check_data on invalid blocks because that
would defeat the rangecheck_block related functions in
@@ -1429,15 +1428,12 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
struct gfs2_buffer_head *bh;
uint32_t height = ip->i_di.di_height;
int i, head_size;
- uint64_t blks_checked = 0, last_block = 0;
+ uint64_t blks_checked = 0;
int error, rc;
int metadata_clean = 0;
uint64_t error_blk = 0;
int hit_error_blk = 0;
- if (!height && pass->check_i_goal)
- pass->check_i_goal(ip, ip->i_di.di_num.no_addr,
- pass->private);
if (!height && !is_dir(&ip->i_di, ip->i_sbd->gfs1))
return 0;
@@ -1456,9 +1452,6 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
* comprise the directory hash table, so we perform the directory
* checks and exit. */
if (is_dir(&ip->i_di, ip->i_sbd->gfs1)) {
- last_block = ip->i_di.di_num.no_addr;
- if (pass->check_i_goal)
- pass->check_i_goal(ip, last_block, pass->private);
if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH))
goto out;
/* check validity of leaf blocks and leaf chains */
@@ -1482,10 +1475,10 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
head_size = hdr_size(bh, height);
if (!head_size)
continue;
-
+
if (pass->check_data)
error = check_data(ip, pass, bh, head_size,
- &last_block, &blks_checked, &error_blk);
+ &blks_checked, &error_blk);
if (pass->big_file_msg && ip->i_di.di_blocks > COMFORTABLE_BLKS)
pass->big_file_msg(ip, blks_checked);
@@ -1498,8 +1491,6 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
(unsigned long long)ip->i_di.di_num.no_addr);
fflush(stdout);
}
- if (!error && pass->check_i_goal)
- pass->check_i_goal(ip, last_block, pass->private);
undo_metalist:
if (!error)
goto out;
@@ -1833,72 +1824,6 @@ static int alloc_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
return 0;
}
-/**
- * rgrp_contains_block - Check if the rgrp provided contains the
- * given block. Taken directly from the gfs2 kernel code
- * @rgd: The rgrp to search within
- * @block: The block to search for
- *
- * Returns: 1 if present, 0 if not.
- */
-static inline int rgrp_contains_block(struct rgrp_tree *rgd, uint64_t block)
-{
- uint64_t first = rgd->ri.ri_data0;
- uint64_t last = first + rgd->ri.ri_data;
- return first <= block && block < last;
-}
-
-/**
- * check_i_goal
- * @ip
- * @goal_blk: What the goal block should be for this inode
- *
- * The goal block for a regular file is typically the last
- * data block of the file. If we can't get the right value,
- * the inode metadata block is the next best thing.
- *
- * Returns: 0 if corrected, 1 if not corrected
- */
-int check_i_goal(struct gfs2_inode *ip, uint64_t goal_blk,
- void *private)
-{
- struct gfs2_sbd *sdp = ip->i_sbd;
- uint64_t i_block = ip->i_di.di_num.no_addr;
-
- /* Don't fix gfs1 inodes, system inodes or inodes whose goal blocks are
- * set to the inode blocks themselves. */
- if (sdp->gfs1 || ip->i_di.di_flags & GFS2_DIF_SYSTEM ||
- ip->i_di.di_goal_meta == i_block)
- return 0;
- /* We default to the inode block */
- if (!goal_blk)
- goal_blk = i_block;
-
- if (ip->i_di.di_goal_meta != goal_blk) {
- /* If the existing goal block is in the same rgrp as the inode,
- * we give the benefit of doubt and assume the value is correct */
- if (ip->i_rgd &&
- rgrp_contains_block(ip->i_rgd, ip->i_di.di_goal_meta))
- goto skip;
- log_err( _("Error: inode %llu (0x%llx) has invalid "
- "allocation goal block %llu (0x%llx). Should"
- " be %llu (0x%llx)\n"),
- (unsigned long long)i_block, (unsigned long long)i_block,
- (unsigned long long)ip->i_di.di_goal_meta,
- (unsigned long long)ip->i_di.di_goal_meta,
- (unsigned long long)goal_blk, (unsigned long long)goal_blk);
- if (query( _("Fix the invalid goal block? (y/n) "))) {
- ip->i_di.di_goal_meta = ip->i_di.di_goal_data = goal_blk;
- bmodified(ip->i_bh);
- } else {
- log_err(_("Invalid goal block not fixed.\n"));
- return 1;
- }
- }
-skip:
- return 0;
-}
-
struct metawalk_fxns alloc_fxns = {
.private = NULL,
.check_leaf = alloc_leaf,
@@ -1909,7 +1834,6 @@ struct metawalk_fxns alloc_fxns = {
.check_dentry = NULL,
.check_eattr_entry = NULL,
.check_eattr_extentry = NULL,
- .check_i_goal = check_i_goal,
.finish_eattr_indir = NULL,
};
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 8bd604d..5e30bfe 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -51,8 +51,6 @@ extern int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
extern int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk,
int error_on_dinode,
enum gfs2_mark_block new_blockmap_state);
-extern int check_i_goal(struct gfs2_inode *ip, uint64_t goal_blk,
- void *private);
extern void reprocess_inode(struct gfs2_inode *ip, const char *desc);
extern struct duptree *dupfind(uint64_t block);
extern struct gfs2_inode *fsck_system_inode(struct gfs2_sbd *sdp,
@@ -92,7 +90,6 @@ enum meta_check_rc {
* check_dentry:
* check_eattr_entry:
* check_eattr_extentry:
- * check_i_goal:
*/
struct metawalk_fxns {
void *private;
@@ -143,8 +140,6 @@ struct metawalk_fxns {
struct gfs2_ea_header *ea_hdr,
struct gfs2_ea_header *ea_hdr_prev,
void *private);
- int (*check_i_goal) (struct gfs2_inode *ip, uint64_t goal_blk,
- void *private);
int (*finish_eattr_indir) (struct gfs2_inode *ip, int leaf_pointers,
int leaf_pointer_errors, void *private);
void (*big_file_msg) (struct gfs2_inode *ip, uint64_t blks_checked);
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 1162066..4d31cff 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -97,7 +97,6 @@ struct metawalk_fxns pass1_fxns = {
.check_dentry = NULL,
.check_eattr_entry = check_eattr_entries,
.check_eattr_extentry = check_extended_leaf_eattr,
- .check_i_goal = check_i_goal,
.finish_eattr_indir = finish_eattr_indir,
.big_file_msg = big_file_comfort,
.repair_leaf = pass1_repair_leaf,
@@ -1167,12 +1166,37 @@ bad_dinode:
return -1;
}
+static void check_i_goal(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
+{
+ if (sdp->gfs1 || ip->i_di.di_flags & GFS2_DIF_SYSTEM)
+ return;
+
+ if (ip->i_di.di_goal_meta <= sdp->sb_addr ||
+ ip->i_di.di_goal_meta > sdp->fssize) {
+ log_err(_("Inode #%llu (0x%llx): Bad allocation goal block "
+ "found: %llu (0x%llx)\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_goal_meta,
+ (unsigned long long)ip->i_di.di_goal_meta);
+ if (query( _("Fix goal block in inode #%llu (0x%llx)? (y/n) "),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr)) {
+ ip->i_di.di_goal_meta = ip->i_di.di_num.no_addr;
+ bmodified(ip->i_bh);
+ } else
+ log_err(_("Allocation goal block in inode #%lld "
+ "(0x%llx) not fixed\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
+ }
+}
+
/*
* handle_di - This is now a wrapper function that takes a gfs2_buffer_head
* and calls handle_ip, which takes an in-code dinode structure.
*/
-static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
- struct rgrp_tree *rgd)
+static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh)
{
int error = 0;
uint64_t block = bh->b_blocknr;
@@ -1212,7 +1236,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
(unsigned long long)block,
(unsigned long long)block);
}
- ip->i_rgd = rgd;
+ check_i_goal(sdp, ip);
error = handle_ip(sdp, ip);
fsck_inode_put(&ip);
return error;
@@ -1315,6 +1339,7 @@ static int check_system_inode(struct gfs2_sbd *sdp,
"directory entries.\n"), filename);
}
}
+ check_i_goal(sdp, *sysinode);
error = handle_ip(sdp, *sysinode);
return error ? error : err;
}
@@ -1610,7 +1635,7 @@ int pass1(struct gfs2_sbd *sdp)
check_n_fix_bitmap(sdp, block, 0,
gfs2_block_free);
}
- } else if (handle_di(sdp, bh, rgd) < 0) {
+ } else if (handle_di(sdp, bh) < 0) {
stack;
brelse(bh);
gfs2_special_free(&gfs1_rindex_blks);
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 25286d1..3de693f 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -131,7 +131,6 @@ struct gfs2_inode {
struct gfs2_dinode i_di;
struct gfs2_buffer_head *i_bh;
struct gfs2_sbd *i_sbd;
- struct rgrp_tree *i_rgd; /* The rgrp this inode is in */
};
#define BUF_HASH_SHIFT (13) /* # hash buckets = 8K */
8 years, 9 months
gfs2-utils: RHEL7 - fsck.gfs2: Detect, fix and clone duplicate block refs within a dinode
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=ce7b371a...
Commit: ce7b371a5ef76526eeba90b2eb62e1912d9b772f
Parent: f9b17da3f2e4b278bfcb04465a7a22c45c441d04
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Jun 29 10:53:52 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Thu Jul 2 13:01:40 2015 -0500
fsck.gfs2: Detect, fix and clone duplicate block refs within a dinode
Prior to this patch, fsck.gfs2 was unable to detect and fix duplicate
block references within the same file. This patch detects when data
blocks are duplicated within a dinode, then tries to clone the data
to a new block.
rhbz#1236669
---
gfs2/fsck/fs_recovery.c | 3 +-
gfs2/fsck/fsck.h | 2 +
gfs2/fsck/metawalk.c | 9 ++-
gfs2/fsck/metawalk.h | 6 ++-
gfs2/fsck/pass1.c | 15 ++++--
gfs2/fsck/pass1b.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++-
gfs2/fsck/pass2.c | 3 +-
gfs2/fsck/util.c | 7 ++-
8 files changed, 150 insertions(+), 16 deletions(-)
diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c
index 9be5a95..ce11fb4 100644
--- a/gfs2/fsck/fs_recovery.c
+++ b/gfs2/fsck/fs_recovery.c
@@ -668,7 +668,8 @@ static int rangecheck_jmeta(struct gfs2_inode *ip, uint64_t block,
}
static int rangecheck_jdata(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
return rangecheck_jblock(ip, block);
}
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index 78e8ad4..a3c5f72 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -58,6 +58,8 @@ struct dir_status {
};
#define DUPFLAG_REF1_FOUND 1 /* Has the original reference been found? */
+#define DUPFLAG_REF1_IS_DUPL 2 /* The original reference is also where we
+ determined there was a duplicate. */
struct duptree {
struct osi_node node;
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 4d5a660..333bec6 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1449,7 +1449,8 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
would defeat the rangecheck_block related functions in
pass1. Therefore the individual check_data functions
should do a range check. */
- rc = pass->check_data(ip, metablock, block, pass->private);
+ rc = pass->check_data(ip, metablock, block, pass->private,
+ bh, ptr);
if (rc && (!error || (rc < error))) {
log_info("\n");
if (rc < 0) {
@@ -1787,7 +1788,8 @@ int delete_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
}
int delete_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private, struct gfs2_buffer_head *bh,
+ uint64_t *ptr)
{
return delete_block_if_notdup(ip, block, NULL, _("data"), NULL,
private);
@@ -1915,7 +1917,8 @@ static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
}
static int alloc_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
uint8_t q;
const char *desc = (const char *)private;
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index fa4c850..8ec38d0 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -29,7 +29,8 @@ extern int delete_metadata(struct gfs2_inode *ip, uint64_t block,
int *was_duplicate, void *private);
extern int delete_leaf(struct gfs2_inode *ip, uint64_t block, void *private);
extern int delete_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private);
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr);
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,
@@ -117,7 +118,8 @@ struct metawalk_fxns {
int *is_valid, int *was_duplicate,
void *private);
int (*check_data) (struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private);
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr);
int (*check_eattr_indir) (struct gfs2_inode *ip, uint64_t block,
uint64_t parent,
struct gfs2_buffer_head **bh, void *private);
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 0909873..c0f2f1e 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -44,7 +44,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
int h, void *private);
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private);
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr);
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
void *private);
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
@@ -72,7 +73,8 @@ static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
void *private);
static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private);
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr);
static int invalidate_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent,
struct gfs2_buffer_head **bh,
@@ -441,7 +443,8 @@ out:
}
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bbh, uint64_t *ptr)
{
uint8_t q;
struct block_count *bc = (struct block_count *) private;
@@ -969,7 +972,8 @@ static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
}
static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
return mark_block_invalid(ip, block, ref_as_data, _("data"),
NULL, NULL);
@@ -1069,7 +1073,8 @@ static int rangecheck_leaf(struct gfs2_inode *ip, uint64_t block,
}
static int rangecheck_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
return rangecheck_block(ip, block, NULL, btype_data, private);
}
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index a8f3d28..c1598ff 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -28,6 +28,11 @@ struct dup_handler {
int ref_count;
};
+struct clone_target {
+ uint64_t dup_block;
+ int first;
+};
+
static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval)
{
char reftypestring[32];
@@ -249,6 +254,116 @@ static void revise_dup_handler(uint64_t dup_blk, struct dup_handler *dh)
}
}
+static int clone_check_meta(struct gfs2_inode *ip, uint64_t block,
+ struct gfs2_buffer_head **bh, int h,
+ int *is_valid, int *was_duplicate, void *private)
+{
+ *was_duplicate = 0;
+ *is_valid = 1;
+ *bh = bread(ip->i_sbd, block);
+ return 0;
+}
+
+/* clone_data - clone a duplicate reference
+ *
+ * This function remembers the first reference to the specified block, and
+ * clones all subsequent references to it (with permission).
+ */
+static int clone_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
+{
+ struct clone_target *clonet = (struct clone_target *)private;
+ struct gfs2_buffer_head *clone_bh;
+ uint64_t cloneblock;
+ int error;
+
+ if (block != clonet->dup_block)
+ return 0;
+
+ if (clonet->first) {
+ log_debug(_("Inode %lld (0x%llx)'s first reference to "
+ "block %lld (0x%llx) is targeted for cloning.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)block,
+ (unsigned long long)block);
+ clonet->first = 0;
+ return 0;
+ }
+ log_err(_("Error: Inode %lld (0x%llx)'s subsequent reference to "
+ "block %lld (0x%llx) is an error.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)block, (unsigned long long)block);
+ if (query( _("Okay to clone the duplicated reference? (y/n) "))) {
+ error = lgfs2_meta_alloc(ip, &cloneblock);
+ if (!error) {
+ clone_bh = bread(ip->i_sbd, clonet->dup_block);
+ if (clone_bh) {
+ fsck_blockmap_set(ip, cloneblock, _("data"),
+ GFS2_BLKST_USED);
+ clone_bh->b_blocknr = cloneblock;
+ bmodified(clone_bh);
+ brelse(clone_bh);
+ /* Now fix the reference: */
+ *ptr = cpu_to_be64(cloneblock);
+ bmodified(bh);
+ log_err(_("Duplicate reference to block %lld "
+ "(0x%llx) was cloned to block %lld "
+ "(0x%llx).\n"),
+ (unsigned long long)block,
+ (unsigned long long)block,
+ (unsigned long long)cloneblock,
+ (unsigned long long)cloneblock);
+ return 0;
+ }
+ }
+ log_err(_("Error: Unable to allocate a new data block.\n"));
+ if (!query("Should I zero the reference instead? (y/n)")) {
+ log_err(_("Duplicate reference to block %lld "
+ "(0x%llx) was not fixed.\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ return 0;
+ }
+ *ptr = 0;
+ bmodified(bh);
+ log_err(_("Duplicate reference to block %lld (0x%llx) was "
+ "zeroed.\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ } else {
+ log_err(_("Duplicate reference to block %lld (0x%llx) "
+ "was not fixed.\n"), (unsigned long long)block,
+ (unsigned long long)block);
+ }
+ return 0;
+}
+
+/* clone_dup_ref_in_inode - clone a duplicate reference within a single inode
+ *
+ * This function traverses the metadata tree of an inode, cloning all
+ * but the first reference to a duplicate block reference.
+ */
+static void clone_dup_ref_in_inode(struct gfs2_inode *ip, struct duptree *dt)
+{
+ int error;
+ struct clone_target clonet = {.dup_block = dt->block, .first = 1};
+ struct metawalk_fxns pass1b_fxns_clone = {
+ .private = &clonet,
+ .check_metalist = clone_check_meta,
+ .check_data = clone_data,
+ };
+
+ error = check_metatree(ip, &pass1b_fxns_clone);
+ if (error) {
+ log_err(_("Error cloning duplicate reference(s) to block %lld "
+ "(0x%llx).\n"), (unsigned long long)dt->block,
+ (unsigned long long)dt->block);
+ }
+}
+
/* handle_dup_blk - handle a duplicate block reference.
*
* This function should resolve and delete the duplicate block reference given,
@@ -389,6 +504,9 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt)
(unsigned long long)id->block_no);
ip = fsck_load_inode(sdp, id->block_no);
+ if (dt->dup_flags & DUPFLAG_REF1_IS_DUPL)
+ clone_dup_ref_in_inode(ip, dt);
+
q = block_type(id->block_no);
if (q == GFS2_BLKST_UNLINKED) {
log_debug( _("The remaining reference inode %lld "
@@ -468,7 +586,8 @@ static int check_metalist_refs(struct gfs2_inode *ip, uint64_t block,
}
static int check_data_refs(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
return add_duplicate_ref(ip, block, ref_as_data, 1, INODE_VALID);
}
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index b31fbd4..900d4e1 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -1580,7 +1580,8 @@ static int check_metalist_qc(struct gfs2_inode *ip, uint64_t block,
}
static int check_data_qc(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bbh, uint64_t *ptr)
{
struct gfs2_buffer_head *bh;
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 4022fee..a6a5cdc 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -339,15 +339,16 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
resolve it. The first reference can't be the second reference. */
if (id && first && !(dt->dup_flags & DUPFLAG_REF1_FOUND)) {
log_info(_("Original reference to block %llu (0x%llx) was "
- "previously found to be bad and deleted.\n"),
+ "either found to be bad and deleted, or else "
+ "a duplicate within the same inode.\n"),
(unsigned long long)block,
(unsigned long long)block);
log_info(_("I'll consider the reference from inode %llu "
"(0x%llx) the first reference.\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- dt->dup_flags |= DUPFLAG_REF1_FOUND;
- return meta_is_good;
+ dt->dup_flags |= DUPFLAG_REF1_IS_DUPL;
+ dt->refs++;
}
/* The first time this is called from pass1 is actually the second
8 years, 9 months
gfs2-utils: RHEL7 - fsck.gfs2: Change duptree structure to have generic flags
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=f9b17da3...
Commit: f9b17da3f2e4b278bfcb04465a7a22c45c441d04
Parent: a523af584645a01bb4900b10d0c9232d0ae50339
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jun 26 12:18:59 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Thu Jul 2 13:01:12 2015 -0500
fsck.gfs2: Change duptree structure to have generic flags
This patch does not change any functionality. It merely changes the
specialized first_ref_found flag to a flag within a multi-flag var.
rhbz#1236669
---
gfs2/fsck/fsck.h | 4 +++-
gfs2/fsck/util.c | 9 ++++-----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index 09db668..78e8ad4 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -57,9 +57,11 @@ struct dir_status {
uint32_t entry_count;
};
+#define DUPFLAG_REF1_FOUND 1 /* Has the original reference been found? */
+
struct duptree {
struct osi_node node;
- int first_ref_found; /* Has the original reference been found? */
+ int dup_flags;
int refs;
uint64_t block;
osi_list_t ref_inode_list; /* list of inodes referencing a dup block */
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index efdd132..4022fee 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -261,7 +261,6 @@ static struct duptree *gfs2_dup_set(uint64_t dblock, int create)
dt->block = dblock;
dt->refs = 1; /* reference 1 is actually the reference we need to
discover in pass1b. */
- dt->first_ref_found = 0;
osi_list_init(&dt->ref_inode_list);
osi_list_init(&dt->ref_invinode_list);
osi_link_node(&dt->node, parent, newn);
@@ -326,7 +325,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
/* If we found the duplicate reference but we've already discovered
the first reference (in pass1b) and the other references in pass1,
we don't need to count it, so just return. */
- if (dt->first_ref_found)
+ if (dt->dup_flags & DUPFLAG_REF1_FOUND)
return meta_is_good;
/* Check for a previous reference to this duplicate */
@@ -338,7 +337,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
that case, we don't want to be confused and consider this second
reference the same as the first. If we do, we'll never be able to
resolve it. The first reference can't be the second reference. */
- if (id && first && !dt->first_ref_found) {
+ if (id && first && !(dt->dup_flags & DUPFLAG_REF1_FOUND)) {
log_info(_("Original reference to block %llu (0x%llx) was "
"previously found to be bad and deleted.\n"),
(unsigned long long)block,
@@ -347,7 +346,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
"(0x%llx) the first reference.\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- dt->first_ref_found = 1;
+ dt->dup_flags |= DUPFLAG_REF1_FOUND;
return meta_is_good;
}
@@ -356,7 +355,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
reference, we don't want to increment the reference count because
it's already accounted for. */
if (first) {
- dt->first_ref_found = 1;
+ dt->dup_flags |= DUPFLAG_REF1_FOUND;
dups_found_first++; /* We found another first ref. */
} else {
dt->refs++;
8 years, 9 months
gfs2-utils: master - fsck.gfs2: Detect, fix and clone duplicate block refs within a dinode
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=68927eb5...
Commit: 68927eb5fb3e6fa418de94eb929b79efc4fea3f6
Parent: b90dbab5aa516f356cca24739564e2c4e3c0c815
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Jun 29 10:53:52 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Wed Jul 1 09:47:41 2015 -0500
fsck.gfs2: Detect, fix and clone duplicate block refs within a dinode
Prior to this patch, fsck.gfs2 was unable to detect and fix duplicate
block references within the same file. This patch detects when data
blocks are duplicated within a dinode, then tries to clone the data
to a new block.
---
gfs2/fsck/fs_recovery.c | 3 +-
gfs2/fsck/fsck.h | 2 +
gfs2/fsck/metawalk.c | 9 ++-
gfs2/fsck/metawalk.h | 6 ++-
gfs2/fsck/pass1.c | 15 ++++--
gfs2/fsck/pass1b.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++-
gfs2/fsck/pass2.c | 3 +-
gfs2/fsck/util.c | 7 ++-
8 files changed, 150 insertions(+), 16 deletions(-)
diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c
index 9be5a95..ce11fb4 100644
--- a/gfs2/fsck/fs_recovery.c
+++ b/gfs2/fsck/fs_recovery.c
@@ -668,7 +668,8 @@ static int rangecheck_jmeta(struct gfs2_inode *ip, uint64_t block,
}
static int rangecheck_jdata(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
return rangecheck_jblock(ip, block);
}
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index 78e8ad4..a3c5f72 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -58,6 +58,8 @@ struct dir_status {
};
#define DUPFLAG_REF1_FOUND 1 /* Has the original reference been found? */
+#define DUPFLAG_REF1_IS_DUPL 2 /* The original reference is also where we
+ determined there was a duplicate. */
struct duptree {
struct osi_node node;
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 4d5a660..333bec6 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1449,7 +1449,8 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
would defeat the rangecheck_block related functions in
pass1. Therefore the individual check_data functions
should do a range check. */
- rc = pass->check_data(ip, metablock, block, pass->private);
+ rc = pass->check_data(ip, metablock, block, pass->private,
+ bh, ptr);
if (rc && (!error || (rc < error))) {
log_info("\n");
if (rc < 0) {
@@ -1787,7 +1788,8 @@ int delete_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
}
int delete_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private, struct gfs2_buffer_head *bh,
+ uint64_t *ptr)
{
return delete_block_if_notdup(ip, block, NULL, _("data"), NULL,
private);
@@ -1915,7 +1917,8 @@ static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
}
static int alloc_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
uint8_t q;
const char *desc = (const char *)private;
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index fa4c850..8ec38d0 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -29,7 +29,8 @@ extern int delete_metadata(struct gfs2_inode *ip, uint64_t block,
int *was_duplicate, void *private);
extern int delete_leaf(struct gfs2_inode *ip, uint64_t block, void *private);
extern int delete_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private);
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr);
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,
@@ -117,7 +118,8 @@ struct metawalk_fxns {
int *is_valid, int *was_duplicate,
void *private);
int (*check_data) (struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private);
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr);
int (*check_eattr_indir) (struct gfs2_inode *ip, uint64_t block,
uint64_t parent,
struct gfs2_buffer_head **bh, void *private);
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 0909873..c0f2f1e 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -44,7 +44,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
int h, void *private);
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private);
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr);
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
void *private);
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
@@ -72,7 +73,8 @@ static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
void *private);
static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private);
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr);
static int invalidate_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent,
struct gfs2_buffer_head **bh,
@@ -441,7 +443,8 @@ out:
}
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bbh, uint64_t *ptr)
{
uint8_t q;
struct block_count *bc = (struct block_count *) private;
@@ -969,7 +972,8 @@ static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
}
static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
return mark_block_invalid(ip, block, ref_as_data, _("data"),
NULL, NULL);
@@ -1069,7 +1073,8 @@ static int rangecheck_leaf(struct gfs2_inode *ip, uint64_t block,
}
static int rangecheck_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
return rangecheck_block(ip, block, NULL, btype_data, private);
}
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index a8f3d28..c1598ff 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -28,6 +28,11 @@ struct dup_handler {
int ref_count;
};
+struct clone_target {
+ uint64_t dup_block;
+ int first;
+};
+
static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval)
{
char reftypestring[32];
@@ -249,6 +254,116 @@ static void revise_dup_handler(uint64_t dup_blk, struct dup_handler *dh)
}
}
+static int clone_check_meta(struct gfs2_inode *ip, uint64_t block,
+ struct gfs2_buffer_head **bh, int h,
+ int *is_valid, int *was_duplicate, void *private)
+{
+ *was_duplicate = 0;
+ *is_valid = 1;
+ *bh = bread(ip->i_sbd, block);
+ return 0;
+}
+
+/* clone_data - clone a duplicate reference
+ *
+ * This function remembers the first reference to the specified block, and
+ * clones all subsequent references to it (with permission).
+ */
+static int clone_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
+{
+ struct clone_target *clonet = (struct clone_target *)private;
+ struct gfs2_buffer_head *clone_bh;
+ uint64_t cloneblock;
+ int error;
+
+ if (block != clonet->dup_block)
+ return 0;
+
+ if (clonet->first) {
+ log_debug(_("Inode %lld (0x%llx)'s first reference to "
+ "block %lld (0x%llx) is targeted for cloning.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)block,
+ (unsigned long long)block);
+ clonet->first = 0;
+ return 0;
+ }
+ log_err(_("Error: Inode %lld (0x%llx)'s subsequent reference to "
+ "block %lld (0x%llx) is an error.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)block, (unsigned long long)block);
+ if (query( _("Okay to clone the duplicated reference? (y/n) "))) {
+ error = lgfs2_meta_alloc(ip, &cloneblock);
+ if (!error) {
+ clone_bh = bread(ip->i_sbd, clonet->dup_block);
+ if (clone_bh) {
+ fsck_blockmap_set(ip, cloneblock, _("data"),
+ GFS2_BLKST_USED);
+ clone_bh->b_blocknr = cloneblock;
+ bmodified(clone_bh);
+ brelse(clone_bh);
+ /* Now fix the reference: */
+ *ptr = cpu_to_be64(cloneblock);
+ bmodified(bh);
+ log_err(_("Duplicate reference to block %lld "
+ "(0x%llx) was cloned to block %lld "
+ "(0x%llx).\n"),
+ (unsigned long long)block,
+ (unsigned long long)block,
+ (unsigned long long)cloneblock,
+ (unsigned long long)cloneblock);
+ return 0;
+ }
+ }
+ log_err(_("Error: Unable to allocate a new data block.\n"));
+ if (!query("Should I zero the reference instead? (y/n)")) {
+ log_err(_("Duplicate reference to block %lld "
+ "(0x%llx) was not fixed.\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ return 0;
+ }
+ *ptr = 0;
+ bmodified(bh);
+ log_err(_("Duplicate reference to block %lld (0x%llx) was "
+ "zeroed.\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ } else {
+ log_err(_("Duplicate reference to block %lld (0x%llx) "
+ "was not fixed.\n"), (unsigned long long)block,
+ (unsigned long long)block);
+ }
+ return 0;
+}
+
+/* clone_dup_ref_in_inode - clone a duplicate reference within a single inode
+ *
+ * This function traverses the metadata tree of an inode, cloning all
+ * but the first reference to a duplicate block reference.
+ */
+static void clone_dup_ref_in_inode(struct gfs2_inode *ip, struct duptree *dt)
+{
+ int error;
+ struct clone_target clonet = {.dup_block = dt->block, .first = 1};
+ struct metawalk_fxns pass1b_fxns_clone = {
+ .private = &clonet,
+ .check_metalist = clone_check_meta,
+ .check_data = clone_data,
+ };
+
+ error = check_metatree(ip, &pass1b_fxns_clone);
+ if (error) {
+ log_err(_("Error cloning duplicate reference(s) to block %lld "
+ "(0x%llx).\n"), (unsigned long long)dt->block,
+ (unsigned long long)dt->block);
+ }
+}
+
/* handle_dup_blk - handle a duplicate block reference.
*
* This function should resolve and delete the duplicate block reference given,
@@ -389,6 +504,9 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt)
(unsigned long long)id->block_no);
ip = fsck_load_inode(sdp, id->block_no);
+ if (dt->dup_flags & DUPFLAG_REF1_IS_DUPL)
+ clone_dup_ref_in_inode(ip, dt);
+
q = block_type(id->block_no);
if (q == GFS2_BLKST_UNLINKED) {
log_debug( _("The remaining reference inode %lld "
@@ -468,7 +586,8 @@ static int check_metalist_refs(struct gfs2_inode *ip, uint64_t block,
}
static int check_data_refs(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
return add_duplicate_ref(ip, block, ref_as_data, 1, INODE_VALID);
}
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index b31fbd4..900d4e1 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -1580,7 +1580,8 @@ static int check_metalist_qc(struct gfs2_inode *ip, uint64_t block,
}
static int check_data_qc(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bbh, uint64_t *ptr)
{
struct gfs2_buffer_head *bh;
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 4022fee..a6a5cdc 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -339,15 +339,16 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
resolve it. The first reference can't be the second reference. */
if (id && first && !(dt->dup_flags & DUPFLAG_REF1_FOUND)) {
log_info(_("Original reference to block %llu (0x%llx) was "
- "previously found to be bad and deleted.\n"),
+ "either found to be bad and deleted, or else "
+ "a duplicate within the same inode.\n"),
(unsigned long long)block,
(unsigned long long)block);
log_info(_("I'll consider the reference from inode %llu "
"(0x%llx) the first reference.\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- dt->dup_flags |= DUPFLAG_REF1_FOUND;
- return meta_is_good;
+ dt->dup_flags |= DUPFLAG_REF1_IS_DUPL;
+ dt->refs++;
}
/* The first time this is called from pass1 is actually the second
8 years, 9 months
gfs2-utils: master - fsck.gfs2: Change duptree structure to have generic flags
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=b90dbab5...
Commit: b90dbab5aa516f356cca24739564e2c4e3c0c815
Parent: 335552bcf1345d9083690e1ef892fa856ac1e59e
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jun 26 12:18:59 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Wed Jul 1 09:47:27 2015 -0500
fsck.gfs2: Change duptree structure to have generic flags
This patch does not change any functionality. It merely changes the
specialized first_ref_found flag to a flag within a multi-flag var.
---
gfs2/fsck/fsck.h | 4 +++-
gfs2/fsck/util.c | 9 ++++-----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index 09db668..78e8ad4 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -57,9 +57,11 @@ struct dir_status {
uint32_t entry_count;
};
+#define DUPFLAG_REF1_FOUND 1 /* Has the original reference been found? */
+
struct duptree {
struct osi_node node;
- int first_ref_found; /* Has the original reference been found? */
+ int dup_flags;
int refs;
uint64_t block;
osi_list_t ref_inode_list; /* list of inodes referencing a dup block */
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index efdd132..4022fee 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -261,7 +261,6 @@ static struct duptree *gfs2_dup_set(uint64_t dblock, int create)
dt->block = dblock;
dt->refs = 1; /* reference 1 is actually the reference we need to
discover in pass1b. */
- dt->first_ref_found = 0;
osi_list_init(&dt->ref_inode_list);
osi_list_init(&dt->ref_invinode_list);
osi_link_node(&dt->node, parent, newn);
@@ -326,7 +325,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
/* If we found the duplicate reference but we've already discovered
the first reference (in pass1b) and the other references in pass1,
we don't need to count it, so just return. */
- if (dt->first_ref_found)
+ if (dt->dup_flags & DUPFLAG_REF1_FOUND)
return meta_is_good;
/* Check for a previous reference to this duplicate */
@@ -338,7 +337,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
that case, we don't want to be confused and consider this second
reference the same as the first. If we do, we'll never be able to
resolve it. The first reference can't be the second reference. */
- if (id && first && !dt->first_ref_found) {
+ if (id && first && !(dt->dup_flags & DUPFLAG_REF1_FOUND)) {
log_info(_("Original reference to block %llu (0x%llx) was "
"previously found to be bad and deleted.\n"),
(unsigned long long)block,
@@ -347,7 +346,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
"(0x%llx) the first reference.\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- dt->first_ref_found = 1;
+ dt->dup_flags |= DUPFLAG_REF1_FOUND;
return meta_is_good;
}
@@ -356,7 +355,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
reference, we don't want to increment the reference count because
it's already accounted for. */
if (first) {
- dt->first_ref_found = 1;
+ dt->dup_flags |= DUPFLAG_REF1_FOUND;
dups_found_first++; /* We found another first ref. */
} else {
dt->refs++;
8 years, 9 months