gfs2-utils: master - fsck.gfs2: Undo partially done metadata records
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=67db866e...
Commit: 67db866e25747e9a0a9ecf99968591eeacec071a
Parent: 7dd92e1992ec97792c2a81a53c8f1af27de15e3e
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Apr 15 08:46:16 2016 -0400
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 9 10:50:12 2016 -0500
fsck.gfs2: Undo partially done metadata records
This patch fixes a problem with duplicate block processing where
one reference is as metadata and another is not (reference as data
or ea or something). The problem is that the metadata block may have
been processed as metadata (for example, an indirect block pointing
to a bunch of data blocks, so all blocks it references are now
marked as metadata) but the last resolved duplicate is not as
metadata, so the sub-blocks are never reprocessed, or "undone".
This patch makes it so that basically if the first reference is
as metadata (so we know we processed its sub-blocks) and the inode
referencing it as metadata is the LAST inode to reference it as
metadata, the sub-blocks are sent through "undo" processing.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/fsck/afterpass1_common.c | 33 ++++++++++++++++++++++++++----
gfs2/fsck/afterpass1_common.h | 2 -
gfs2/fsck/metawalk.c | 43 ++++++++++++++++++++++++++++++++--------
gfs2/fsck/util.c | 22 +++++++++++++++++++++
gfs2/fsck/util.h | 2 +-
5 files changed, 85 insertions(+), 17 deletions(-)
diff --git a/gfs2/fsck/afterpass1_common.c b/gfs2/fsck/afterpass1_common.c
index bdea242..95fdbf8 100644
--- a/gfs2/fsck/afterpass1_common.c
+++ b/gfs2/fsck/afterpass1_common.c
@@ -22,10 +22,13 @@
*
* Returns: 1 if there are any remaining references to this block, else 0.
*/
-int find_remove_dup(struct gfs2_inode *ip, uint64_t block, const char *btype)
+static int find_remove_dup(struct gfs2_inode *ip, uint64_t block,
+ const char *btype, int *removed_last_meta)
{
struct duptree *dt;
struct inode_with_dups *id;
+ int deleted_a_meta_ref = 0;
+ int meta_refs_left = 0;
dt = dupfind(block);
if (!dt)
@@ -36,15 +39,30 @@ int find_remove_dup(struct gfs2_inode *ip, uint64_t block, const char *btype)
if (!id)
goto more_refs;
+ if (id->reftypecount[ref_as_meta])
+ deleted_a_meta_ref = 1;
dup_listent_delete(dt, id);
if (dt->refs == 0) {
log_info( _("This was the last reference: it's no longer a "
"duplicate.\n"));
dup_delete(dt); /* not duplicate now */
+ if (deleted_a_meta_ref) {
+ log_debug("Removed the last reference as metadata.\n");
+ *removed_last_meta = 1;
+ }
return 0;
+ } else if (deleted_a_meta_ref) {
+ /* If we deleted a metadata reference, see if there are more
+ references as meta, or if it was the last one. */
+ meta_refs_left = count_dup_meta_refs(dt);
}
more_refs:
- log_info( _("%d block reference(s) remain.\n"), dt->refs);
+ log_info(_("%d block reference(s) remain (%d as metadata).\n"),
+ dt->refs, meta_refs_left);
+ if (deleted_a_meta_ref && meta_refs_left == 0) {
+ log_debug("Removed the last reference as metadata.\n");
+ *removed_last_meta = 1;
+ }
return 1; /* references still exist so do not free the block. */
}
@@ -61,6 +79,7 @@ static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
void *private)
{
int q;
+ int removed_lastmeta;
if (!valid_block(ip->i_sbd, block))
return meta_error;
@@ -75,9 +94,13 @@ static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr);
return meta_is_good;
}
- if (find_remove_dup(ip, block, btype)) { /* a dup */
- if (was_duplicate)
- *was_duplicate = 1;
+ if (find_remove_dup(ip, block, btype, &removed_lastmeta)) { /* a dup */
+ if (was_duplicate) {
+ if (removed_lastmeta)
+ log_debug("Removed last reference as meta.\n");
+ else
+ *was_duplicate = 1;
+ }
log_err( _("Not clearing duplicate reference in inode "
"at block #%llu (0x%llx) to block #%llu (0x%llx) "
"because it's referenced by another inode.\n"),
diff --git a/gfs2/fsck/afterpass1_common.h b/gfs2/fsck/afterpass1_common.h
index 8b345ee..829828f 100644
--- a/gfs2/fsck/afterpass1_common.h
+++ b/gfs2/fsck/afterpass1_common.h
@@ -26,8 +26,6 @@ extern int delete_eattr_extentry(struct gfs2_inode *ip, int i,
struct gfs2_ea_header *ea_hdr,
struct gfs2_ea_header *ea_hdr_prev,
void *private);
-extern int find_remove_dup(struct gfs2_inode *ip, uint64_t block,
- const char *btype);
extern int remove_dentry_from_dir(struct gfs2_sbd *sdp, uint64_t dir,
uint64_t dentryblock);
#endif
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 2d52217..8a1748b 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1217,7 +1217,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
struct gfs2_buffer_head *bh, *nbh, *metabh = ip->i_bh;
osi_list_t *prev_list, *cur_list, *tmp;
int h, head_size, iblk_type;
- uint64_t *ptr, block;
+ uint64_t *ptr, block, *undoptr;
int error, was_duplicate, is_valid;
int maxptrs;
@@ -1297,7 +1297,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
"(0x%llx).\n"),
(unsigned long long)block,
(unsigned long long)block);
- return error;
+ goto error_undo;
}
if (error == meta_skip_further) {
log_info(_("\nUnrecoverable metadata "
@@ -1306,18 +1306,24 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
" will be skipped.\n"),
(unsigned long long)block,
(unsigned long long)block);
- return error;
+ goto error_undo;
}
if (!is_valid) {
log_debug( _("Skipping rejected block "
"%llu (0x%llx)\n"),
(unsigned long long)block,
(unsigned long long)block);
- if (pass->invalid_meta_is_fatal)
- return meta_error;
-
+ if (pass->invalid_meta_is_fatal) {
+ error = meta_error;
+ goto error_undo;
+ }
continue;
}
+ /* Note that there's a special case in which
+ we need to process the metadata block, even
+ if it was a duplicate. That's for cases
+ where we deleted the last reference as
+ metadata. */
if (was_duplicate) {
log_debug( _("Skipping duplicate %llu "
"(0x%llx)\n"),
@@ -1330,9 +1336,10 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
"%lld (0x%llx)\n"),
(unsigned long long)block,
(unsigned long long)block);
- if (pass->invalid_meta_is_fatal)
- return meta_error;
-
+ if (pass->invalid_meta_is_fatal) {
+ error = meta_error;
+ goto error_undo;
+ }
continue;
}
if (!nbh)
@@ -1342,6 +1349,24 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
} /* for blocks at that height */
} /* for height */
return 0;
+
+error_undo: /* undo what we've done so far for this block */
+ if (pass->undo_check_meta == NULL)
+ return error;
+
+ log_info(_("Undoing the work we did before the error on block %llu "
+ "(0x%llx).\n"), (unsigned long long)bh->b_blocknr,
+ (unsigned long long)bh->b_blocknr);
+ for (undoptr = (uint64_t *)(bh->b_data + head_size); undoptr < ptr &&
+ (char *)undoptr < (bh->b_data + ip->i_sbd->bsize);
+ undoptr++) {
+ if (!*undoptr)
+ continue;
+
+ block = be64_to_cpu(*undoptr);
+ pass->undo_check_meta(ip, block, h, pass->private);
+ }
+ return error;
}
/**
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 2e77000..8a8220b 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -293,6 +293,28 @@ struct inode_with_dups *find_dup_ref_inode(struct duptree *dt,
return NULL;
}
+/**
+ * count_dup_meta_refs - count the number of remaining references as metadata
+ */
+int count_dup_meta_refs(struct duptree *dt)
+{
+ osi_list_t *ref;
+ struct inode_with_dups *id;
+ int metarefs = 0;
+
+ osi_list_foreach(ref, &dt->ref_invinode_list) {
+ id = osi_list_entry(ref, struct inode_with_dups, list);
+ if (id->reftypecount[ref_as_meta])
+ metarefs++;
+ }
+ osi_list_foreach(ref, &dt->ref_inode_list) {
+ id = osi_list_entry(ref, struct inode_with_dups, list);
+ if (id->reftypecount[ref_as_meta])
+ metarefs++;
+ }
+ return metarefs;
+}
+
/*
* add_duplicate_ref - Add a duplicate reference to the duplicates tree list
* A new element of the tree will be created as needed
diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h
index 4545594..d93b65d 100644
--- a/gfs2/fsck/util.h
+++ b/gfs2/fsck/util.h
@@ -20,7 +20,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
extern struct inode_with_dups *find_dup_ref_inode(struct duptree *dt,
struct gfs2_inode *ip);
extern void dup_listent_delete(struct duptree *dt, struct inode_with_dups *id);
-
+extern int count_dup_meta_refs(struct duptree *dt);
extern const char *reftypes[ref_types + 1];
#define BLOCKMAP_SIZE1(size) ((size) >> 3)
8 years
gfs2-utils: master - libgfs2: Allocate new GFS1 metadata as type 3,
not type 1
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=7dd92e19...
Commit: 7dd92e1992ec97792c2a81a53c8f1af27de15e3e
Parent: fddac9d152009b7a213011868d91966aba94a325
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Apr 12 14:45:52 2016 -0400
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 9 10:50:12 2016 -0500
libgfs2: Allocate new GFS1 metadata as type 3, not type 1
GFS1 and GFS2 treat metadata differently. In GFS2, only dinodes are
marked as type 3 (dinode). All other GFS2 metadata is considered
data (type 1). In GFS1, all metadata is considered "metadata" which
is type 3. So this patch makes function lgfs2_meta_alloc set the
block type in the bitmap according to the sdp->gfs1 setting.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/libgfs2/fs_ops.c | 22 +++++++++++++++-------
1 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c
index a43a973..3acfb67 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -137,7 +137,7 @@ static uint64_t find_free_block(struct rgrp_tree *rgd)
return blkno;
}
-static int blk_alloc_in_rg(struct gfs2_sbd *sdp, unsigned state, struct rgrp_tree *rgd, uint64_t blkno)
+static int blk_alloc_in_rg(struct gfs2_sbd *sdp, unsigned state, struct rgrp_tree *rgd, uint64_t blkno, int dinode)
{
if (blkno == 0)
return -1;
@@ -145,8 +145,14 @@ static int blk_alloc_in_rg(struct gfs2_sbd *sdp, unsigned state, struct rgrp_tre
if (gfs2_set_bitmap(rgd, blkno, state))
return -1;
- if (state == GFS2_BLKST_DINODE)
- rgd->rg.rg_dinodes++;
+ if (state == GFS2_BLKST_DINODE) {
+ struct gfs_rgrp *gfs1rg = (struct gfs_rgrp *)&rgd->rg;
+
+ if (dinode)
+ rgd->rg.rg_dinodes++;
+ else if (sdp->gfs1)
+ gfs1rg->rg_usedmeta++;
+ }
rgd->rg.rg_free--;
if (sdp->gfs1)
@@ -163,7 +169,7 @@ static int blk_alloc_in_rg(struct gfs2_sbd *sdp, unsigned state, struct rgrp_tre
* resource group with blksreq free blocks but only allocate the one block.
* Returns 0 on success with the allocated block number in *blkno or non-zero otherwise.
*/
-static int block_alloc(struct gfs2_sbd *sdp, const uint64_t blksreq, int state, uint64_t *blkno)
+static int block_alloc(struct gfs2_sbd *sdp, const uint64_t blksreq, int state, uint64_t *blkno, int dinode)
{
int ret;
int release = 0;
@@ -186,7 +192,7 @@ static int block_alloc(struct gfs2_sbd *sdp, const uint64_t blksreq, int state,
}
bn = find_free_block(rgt);
- ret = blk_alloc_in_rg(sdp, state, rgt, bn);
+ ret = blk_alloc_in_rg(sdp, state, rgt, bn, dinode);
if (release)
gfs2_rgrp_relse(rgt);
*blkno = bn;
@@ -195,7 +201,7 @@ static int block_alloc(struct gfs2_sbd *sdp, const uint64_t blksreq, int state,
int lgfs2_dinode_alloc(struct gfs2_sbd *sdp, const uint64_t blksreq, uint64_t *blkno)
{
- int ret = block_alloc(sdp, blksreq, GFS2_BLKST_DINODE, blkno);
+ int ret = block_alloc(sdp, blksreq, GFS2_BLKST_DINODE, blkno, TRUE);
if (ret == 0)
sdp->dinodes_alloced++;
return ret;
@@ -203,7 +209,9 @@ int lgfs2_dinode_alloc(struct gfs2_sbd *sdp, const uint64_t blksreq, uint64_t *b
int lgfs2_meta_alloc(struct gfs2_inode *ip, uint64_t *blkno)
{
- int ret = block_alloc(ip->i_sbd, 1, GFS2_BLKST_USED, blkno);
+ int ret = block_alloc(ip->i_sbd, 1,
+ ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE :
+ GFS2_BLKST_USED, blkno, FALSE);
if (ret == 0) {
ip->i_di.di_goal_meta = *blkno;
bmodified(ip->i_bh);
8 years
gfs2-utils: master - fsck.gfs2: re-add a non-allocating repair_leaf
to pass1
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=fddac9d1...
Commit: fddac9d152009b7a213011868d91966aba94a325
Parent: 2f8d5aab7a90d4f5495224ee126fe1972d21ccbd
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Apr 11 12:13:02 2016 -0400
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 9 10:50:12 2016 -0500
fsck.gfs2: re-add a non-allocating repair_leaf to pass1
In an earlier patch, the repair_leaf function was removed from
pass1. This turns out to cause a problem where there is leaf block
corruption. This patch adds back in a non-allocating function so
things work as they used to.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/fsck/pass1.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 47 insertions(+), 0 deletions(-)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index ee20b9e..6908ac7 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -142,6 +142,52 @@ static int delete_block(struct gfs2_inode *ip, uint64_t block,
return -1;
}
+/* This is a pass1-specific leaf repair. Since we are not allowed to do
+ * block allocations, we do what we can. */
+static int pass1_repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no,
+ int lindex, int ref_count, const char *msg)
+{
+ uint64_t *cpyptr;
+ char *padbuf;
+ int pad_size, i;
+
+ log_err( _("Directory Inode %llu (0x%llx) points to leaf %llu"
+ " (0x%llx) %s.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)*leaf_no,
+ (unsigned long long)*leaf_no, msg);
+ if (!query( _("Attempt to patch around it? (y/n) "))) {
+ log_err( _("Bad leaf left in place.\n"));
+ goto out;
+ }
+
+ padbuf = malloc(ref_count * sizeof(uint64_t));
+ cpyptr = (uint64_t *)padbuf;
+ for (i = 0; i < ref_count; i++) {
+ *cpyptr = 0;
+ cpyptr++;
+ }
+ pad_size = ref_count * sizeof(uint64_t);
+ log_err(_("Writing zeros to the hash table of directory %lld "
+ "(0x%llx) at index: 0x%x for 0x%x pointers.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr, lindex,
+ ref_count);
+ if (ip->i_sbd->gfs1)
+ gfs1_writei(ip, padbuf, lindex * sizeof(uint64_t), pad_size);
+ else
+ gfs2_writei(ip, padbuf, lindex * sizeof(uint64_t), pad_size);
+ free(padbuf);
+ log_err( _("Directory Inode %llu (0x%llx) patched.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
+
+out:
+ *leaf_no = 0;
+ return 0;
+}
+
struct metawalk_fxns pass1_fxns = {
.private = NULL,
.check_leaf = p1check_leaf,
@@ -153,6 +199,7 @@ struct metawalk_fxns pass1_fxns = {
.check_eattr_entry = check_eattr_entries,
.check_eattr_extentry = check_extended_leaf_eattr,
.big_file_msg = big_file_comfort,
+ .repair_leaf = pass1_repair_leaf,
.undo_check_meta = undo_check_metalist,
.undo_check_data = undo_check_data,
.delete_block = delete_block,
8 years
gfs2-utils: master - fsck.gfs2: Add error checks to get_next_leaf
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=2f8d5aab...
Commit: 2f8d5aab7a90d4f5495224ee126fe1972d21ccbd
Parent: d78e95e526daff3e0710626c0f9545de3f3397de
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Apr 11 09:10:55 2016 -0400
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 9 10:50:12 2016 -0500
fsck.gfs2: Add error checks to get_next_leaf
This patch adds some error checking to function get_next_leaf.
Since a leaf block's "lf_next" pointer happens to have the same
block offset as an inode's inode number, we can otherwise get into
an infinite loop whereby a corrupt file system has a leaf block
mistakenly pointing to a dinode, and the dinode has what appears
to be a "lf_next" that points to itself.
I added two checks: First, to guard against situations where a
leaf block points to itself as lf_next, and second, to guard against
situations where a lf_next points to a non-leaf block.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/libgfs2/fs_ops.c | 11 +++++++++++
1 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c
index 2ae27d1..a43a973 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -1139,7 +1139,18 @@ static int get_next_leaf(struct gfs2_inode *dip,struct gfs2_buffer_head *bh_in,
if (!leaf->lf_next)
return -1;
+ /* Check for a leaf that points to itself as "next" */
+ if (be64_to_cpu(leaf->lf_next) == bh_in->b_blocknr)
+ return -1;
*bh_out = bread(dip->i_sbd, be64_to_cpu(leaf->lf_next));
+ if (*bh_out == NULL)
+ return -ENOENT;
+ /* Check for a leaf pointing to a non-leaf */
+ if (gfs2_check_meta(*bh_out, GFS2_METATYPE_LF)) {
+ brelse(*bh_out);
+ *bh_out = NULL;
+ return -ENOENT;
+ }
return 0;
}
8 years
gfs2-utils: master - fsck.gfs2: blocks cannot be UNLINKED in pass1b
or after that
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=d78e95e5...
Commit: d78e95e526daff3e0710626c0f9545de3f3397de
Parent: 1af1cc55be2771dda11f1afebdc42b619183f78f
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Sun Apr 10 11:50:12 2016 -0400
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 9 10:50:12 2016 -0500
fsck.gfs2: blocks cannot be UNLINKED in pass1b or after that
This patch basically changes some checks for blocks in an UNLINKED
state to checking the FREE state instead. If any blocks were in the
UNLINKED state, they would have already been resolved by the time
we get to pass1b, and therefore the checks can only be in error.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/fsck/pass1b.c | 18 +++++++++---------
gfs2/fsck/pass2.c | 10 +---------
gfs2/fsck/pass3.c | 2 +-
gfs2/fsck/pass4.c | 2 +-
4 files changed, 12 insertions(+), 20 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index d6ab285..f5f286a 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -358,7 +358,7 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
0);
fsck_bitmap_set(ip, ip->i_di.di_num.no_addr,
_("duplicate referencing bad"),
- GFS2_BLKST_UNLINKED);
+ GFS2_BLKST_FREE);
/* We delete the dup_handler inode count and
duplicate id BEFORE clearing the metadata,
because if this is the last reference to
@@ -574,13 +574,11 @@ static void resolve_last_reference(struct gfs2_sbd *sdp, struct duptree *dt,
clone_dup_ref_in_inode(ip, dt);
q = bitmap_type(sdp, id->block_no);
- if (q == GFS2_BLKST_UNLINKED) {
- log_debug( _("The remaining reference inode %lld (0x%llx) is "
- "marked invalid: Marking the block as free.\n"),
+ if (q == GFS2_BLKST_FREE) {
+ log_debug( _("The remaining reference inode %lld (0x%llx) was "
+ "already marked free.\n"),
(unsigned long long)id->block_no,
(unsigned long long)id->block_no);
- fsck_bitmap_set(ip, dt->block, _("reference-repaired leaf"),
- GFS2_BLKST_FREE);
} else if (id->reftypecount[ref_is_inode]) {
set_ip_bitmap(ip);
} else if (id->reftypecount[ref_as_data]) {
@@ -941,11 +939,13 @@ int pass1b(struct gfs2_sbd *sdp)
if (q == GFS2_BLKST_FREE || q == GFS2_BLKST_USED || q < 0)
continue;
- if (q == GFS2_BLKST_UNLINKED)
- log_debug( _("Checking invalidated duplicate block "
- "%lld (0x%llx)\n"),
+ if (q == GFS2_BLKST_UNLINKED) {
+ log_debug( _("Error: block %lld (0x%llx) is still "
+ "marked UNLINKED.\n"),
(unsigned long long)i,
(unsigned long long)i);
+ return FSCK_ERROR;
+ }
warm_fuzzy_stuff(i);
if (find_block_ref(sdp, i) < 0) {
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index d4f50d2..ffd58dc 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -1889,7 +1889,7 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
ds.q = bitmap_type(sysinode->i_sbd, iblock);
pass2_fxns.private = (void *) &ds;
- if (ds.q == GFS2_BLKST_UNLINKED) {
+ if (ds.q == GFS2_BLKST_FREE) {
/* First check that the directory's metatree is valid */
error = check_metatree(sysinode, &pass2_fxns);
if (error < 0) {
@@ -1996,14 +1996,6 @@ static int pass2_check_dir(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
int error;
pass2_fxns.private = &ds;
- if (ds.q == GFS2_BLKST_UNLINKED) {
- /* First check that the directory's metatree is valid */
- error = check_metatree(ip, &pass2_fxns);
- if (error < 0) {
- stack;
- return error;
- }
- }
error = check_dir(sdp, ip, &pass2_fxns);
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
return FSCK_OK;
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index 2fa0bdb..fbf8318 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -239,7 +239,7 @@ int pass3(struct gfs2_sbd *sdp)
}
q = bitmap_type(sdp, di->dinode.no_addr);
ip = fsck_load_inode(sdp, di->dinode.no_addr);
- if (q == GFS2_BLKST_UNLINKED) {
+ if (q == GFS2_BLKST_FREE) {
log_err( _("Found unlinked directory "
"containing bad block at block %llu"
" (0x%llx)\n"),
diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c
index 16339cc..313ff0f 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -61,7 +61,7 @@ static int handle_unlinked(struct gfs2_sbd *sdp, uint64_t no_addr,
log_err( _("Found unlinked inode at %llu (0x%llx)\n"),
(unsigned long long)no_addr, (unsigned long long)no_addr);
q = bitmap_type(sdp, no_addr);
- if (q == GFS2_BLKST_UNLINKED) {
+ if (q == GFS2_BLKST_FREE) {
log_err( _("Unlinked inode %llu (0x%llx) contains bad "
"blocks\n"), (unsigned long long)no_addr,
(unsigned long long)no_addr);
8 years
gfs2-utils: master - fsck.gfs2: adjust rgrp inode count when fixing
bitmap
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=1af1cc55...
Commit: 1af1cc55be2771dda11f1afebdc42b619183f78f
Parent: 81d6d1f4516e7bb204d6491a245cba44e0f051f1
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Apr 6 15:04:53 2016 -0400
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 9 10:50:12 2016 -0500
fsck.gfs2: adjust rgrp inode count when fixing bitmap
Before this patch, fsck.gfs2 would adjust the rgrp bitmaps and
rgrp free space when freeing a block. Later, in pass5, it would
fix the rgrp count of dinodes as needed. Now that pass5 is done
immediately after pass1, we need the other passes to make sure
to keep the dinode count in the rgrps in sync. Therefore, we
adjust it as we go.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/fsck/metawalk.c | 45 +++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 9ec4bea..2d52217 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -34,6 +34,7 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, int error_on_dinode,
{
int old_bitmap_state;
struct rgrp_tree *rgd;
+ int treat_as_inode = 0;
const char *allocdesc[2][5] = { /* gfs2 descriptions */
{"free", "data", "unlinked", "inode", "reserved"},
/* gfs1 descriptions: */
@@ -85,11 +86,33 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, int error_on_dinode,
struct inode_info *ii;
dt = dirtree_find(blk);
- if (dt)
+ if (dt) {
dirtree_delete(dt);
+ treat_as_inode = 1;
+ }
ii = inodetree_find(blk);
- if (ii)
+ if (ii) {
inodetree_delete(ii);
+ treat_as_inode = 1;
+ } else if (!sdp->gfs1) {
+ treat_as_inode = 1;
+ } else {
+ /* This is a GFS1 fs (so all metadata is marked
+ inode). We need to verify it is an inode
+ before we can decr the rgrp inode count. */
+ if (link1_type(&nlink1map, blk) == 1)
+ treat_as_inode = 1;
+ }
+ if (old_bitmap_state == GFS2_BLKST_DINODE) {
+ if (treat_as_inode && rgd->rg.rg_dinodes > 0)
+ rgd->rg.rg_dinodes--;
+ else if (sdp->gfs1) {
+ struct gfs_rgrp *gfs1rg =
+ (struct gfs_rgrp *)&rgd->rg;
+ if (gfs1rg->rg_usedmeta > 0)
+ gfs1rg->rg_usedmeta--;
+ }
+ }
link1_set(&nlink1map, blk, 0);
}
rgd->rg.rg_free++;
@@ -99,6 +122,24 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, int error_on_dinode,
else
gfs2_rgrp_out_bh(&rgd->rg, rgd->bits[0].bi_bh);
} else if (old_bitmap_state == GFS2_BLKST_FREE) {
+ if (!sdp->gfs1) {
+ treat_as_inode = 1;
+ } else {
+ /* This is a GFS1 fs (so all metadata is marked inode).
+ We need to verify it is an inode before we can decr
+ the rgrp inode count. */
+ if (link1_type(&nlink1map, blk) == 1)
+ treat_as_inode = 1;
+ }
+ if (new_blockmap_state == GFS2_BLKST_DINODE) {
+ if (treat_as_inode)
+ rgd->rg.rg_dinodes++;
+ else if (sdp->gfs1) {
+ struct gfs_rgrp *gfs1rg =
+ (struct gfs_rgrp *)&rgd->rg;
+ gfs1rg->rg_usedmeta++;
+ }
+ }
rgd->rg.rg_free--;
if (sdp->gfs1)
gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
8 years
gfs2-utils: master - fsck.gfs2: Refactor check_n_fix_bitmap to make
it more readable
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=81d6d1f4...
Commit: 81d6d1f4516e7bb204d6491a245cba44e0f051f1
Parent: f2ffb1e587c71a2aef0b369f7b2e186ccb463e0e
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Apr 15 22:21:09 2016 -0400
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 9 10:50:12 2016 -0500
fsck.gfs2: Refactor check_n_fix_bitmap to make it more readable
This patch should not change functionality. It just refactors the
function check_n_fix_bitmap so it's easier to read and change.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/fsck/metawalk.c | 118 ++++++++++++++++++++++++-------------------------
1 files changed, 58 insertions(+), 60 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 6b7146e..9ec4bea 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -34,6 +34,10 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, int error_on_dinode,
{
int old_bitmap_state;
struct rgrp_tree *rgd;
+ const char *allocdesc[2][5] = { /* gfs2 descriptions */
+ {"free", "data", "unlinked", "inode", "reserved"},
+ /* gfs1 descriptions: */
+ {"free", "data", "free meta", "metadata", "reserved"}};
rgd = gfs2_blk2rgrpd(sdp, blk);
@@ -44,70 +48,64 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, int error_on_dinode,
(unsigned long long)blk, (unsigned long long)blk);
return -1;
}
- if (old_bitmap_state != new_blockmap_state) {
- const char *allocdesc[2][5] = { /* gfs2 descriptions */
- {"free", "data", "unlinked", "inode", "reserved"},
- /* gfs1 descriptions: */
- {"free", "data", "free meta", "metadata", "reserved"}};
-
- if (error_on_dinode && old_bitmap_state == GFS2_BLKST_DINODE &&
- new_blockmap_state != GFS2_BLKST_FREE) {
- log_debug(_("Reference as '%s' to block %llu (0x%llx) "
- "which was marked as dinode. Needs "
- "further investigation.\n"),
- allocdesc[sdp->gfs1][new_blockmap_state],
- (unsigned long long)blk,
- (unsigned long long)blk);
- return 1;
- }
- /* Keep these messages as short as possible, or the output
- gets to be huge and unmanageable. */
- log_err( _("Block %llu (0x%llx) was '%s', should be %s.\n"),
- (unsigned long long)blk, (unsigned long long)blk,
- allocdesc[sdp->gfs1][old_bitmap_state],
- allocdesc[sdp->gfs1][new_blockmap_state]);
- if (query( _("Fix the bitmap? (y/n)"))) {
- /* If the new bitmap state is free (and therefore the
- old state was not) we have to add to the free
- space in the rgrp. If the old bitmap state was
- free (and therefore it no longer is) we have to
- subtract to the free space. If the type changed
- from dinode to data or data to dinode, no change in
- free space. */
- gfs2_set_bitmap(rgd, blk, new_blockmap_state);
- if (new_blockmap_state == GFS2_BLKST_FREE) {
- /* If we're freeing a dinode, get rid of
- the hash table entries for it. */
- if (old_bitmap_state == GFS2_BLKST_DINODE ||
- old_bitmap_state == GFS2_BLKST_UNLINKED) {
- struct dir_info *dt;
- struct inode_info *ii;
-
- dt = dirtree_find(blk);
- if (dt)
- dirtree_delete(dt);
- ii = inodetree_find(blk);
- if (ii)
- inodetree_delete(ii);
- link1_set(&nlink1map, blk, 0);
- }
- rgd->rg.rg_free++;
- if (sdp->gfs1)
- gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
- else
- gfs2_rgrp_out_bh(&rgd->rg, rgd->bits[0].bi_bh);
- } else if (old_bitmap_state == GFS2_BLKST_FREE) {
- rgd->rg.rg_free--;
- if (sdp->gfs1)
- gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
- else
- gfs2_rgrp_out_bh(&rgd->rg, rgd->bits[0].bi_bh);
- }
- log_err( _("The bitmap was fixed.\n"));
- } else {
- log_err( _("The bitmap inconsistency was ignored.\n"));
+ if (old_bitmap_state == new_blockmap_state)
+ return 0;
+
+ if (error_on_dinode && old_bitmap_state == GFS2_BLKST_DINODE &&
+ new_blockmap_state != GFS2_BLKST_FREE) {
+ log_debug(_("Reference as '%s' to block %llu (0x%llx) which "
+ "was marked as dinode. Needs further "
+ "investigation.\n"),
+ allocdesc[sdp->gfs1][new_blockmap_state],
+ (unsigned long long)blk, (unsigned long long)blk);
+ return 1;
+ }
+ /* Keep these messages as short as possible, or the output gets to be
+ huge and unmanageable. */
+ log_err( _("Block %llu (0x%llx) was '%s', should be %s.\n"),
+ (unsigned long long)blk, (unsigned long long)blk,
+ allocdesc[sdp->gfs1][old_bitmap_state],
+ allocdesc[sdp->gfs1][new_blockmap_state]);
+ if (!query( _("Fix the bitmap? (y/n)"))) {
+ log_err( _("The bitmap inconsistency was ignored.\n"));
+ return 0;
+ }
+ /* If the new bitmap state is free (and therefore the old state was
+ not) we have to add to the free space in the rgrp. If the old
+ bitmap state was free (and therefore it no longer is) we have to
+ subtract to the free space. If the type changed from dinode to
+ data or data to dinode, no change in free space. */
+ gfs2_set_bitmap(rgd, blk, new_blockmap_state);
+ if (new_blockmap_state == GFS2_BLKST_FREE) {
+ /* If we're freeing a dinode, get rid of the hash table
+ entries for it. */
+ if (old_bitmap_state == GFS2_BLKST_DINODE ||
+ old_bitmap_state == GFS2_BLKST_UNLINKED) {
+ struct dir_info *dt;
+ struct inode_info *ii;
+
+ dt = dirtree_find(blk);
+ if (dt)
+ dirtree_delete(dt);
+ ii = inodetree_find(blk);
+ if (ii)
+ inodetree_delete(ii);
+ link1_set(&nlink1map, blk, 0);
}
+ rgd->rg.rg_free++;
+ if (sdp->gfs1)
+ gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg,
+ rgd->bits[0].bi_bh);
+ else
+ gfs2_rgrp_out_bh(&rgd->rg, rgd->bits[0].bi_bh);
+ } else if (old_bitmap_state == GFS2_BLKST_FREE) {
+ rgd->rg.rg_free--;
+ if (sdp->gfs1)
+ gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
+ else
+ gfs2_rgrp_out_bh(&rgd->rg, rgd->bits[0].bi_bh);
}
+ log_err( _("The bitmap was fixed.\n"));
return 0;
}
8 years
gfs2-utils: master - fsck.gfs2: Use bitmaps instead of linked list
for inodes w/nlink == 1
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=f2ffb1e5...
Commit: f2ffb1e587c71a2aef0b369f7b2e186ccb463e0e
Parent: 690de2210a3cbd48924a1e536024b0ca6a231205
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Apr 5 12:55:53 2016 -0400
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 9 10:50:12 2016 -0500
fsck.gfs2: Use bitmaps instead of linked list for inodes w/nlink == 1
This patch adds two new in-core bitmaps. Their purpose is to replace
the most common case where inodes have an nlink count equal to 1.
If we've got petabytes of inodes, this will save us a lot of memory.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/fsck/link.c | 110 ++++++++++++++++++++++++++++++++++++-------------
gfs2/fsck/link.h | 4 ++
gfs2/fsck/main.c | 3 +
gfs2/fsck/metawalk.c | 2 +
gfs2/fsck/pass1.c | 40 ++++++++++++++++--
gfs2/fsck/pass1b.c | 3 +
gfs2/fsck/pass2.c | 8 ++++
gfs2/fsck/pass4.c | 80 ++++++++++++++++++++++++------------
gfs2/fsck/util.h | 23 ++++++++++
9 files changed, 214 insertions(+), 59 deletions(-)
diff --git a/gfs2/fsck/link.c b/gfs2/fsck/link.c
index 7e8acb7..0243d85 100644
--- a/gfs2/fsck/link.c
+++ b/gfs2/fsck/link.c
@@ -15,6 +15,26 @@
#include "link.h"
#include "util.h"
+struct gfs2_bmap nlink1map = { 0 }; /* map of dinodes with nlink == 1 */
+struct gfs2_bmap clink1map = { 0 }; /* map of dinodes w/counted links == 1 */
+
+int link1_set(struct gfs2_bmap *bmap, uint64_t bblock, int mark)
+{
+ static unsigned char *byte;
+ static uint64_t b;
+
+ if (!bmap)
+ return 0;
+ if (bblock > bmap->size)
+ return -1;
+
+ byte = bmap->map + BLOCKMAP_SIZE1(bblock);
+ b = BLOCKMAP_BYTE_OFFSET1(bblock);
+ *byte &= ~(BLOCKMAP_MASK1 << b);
+ *byte |= (mark & BLOCKMAP_MASK1) << b;
+ return 0;
+}
+
int set_di_nlink(struct gfs2_inode *ip)
{
struct inode_info *ii;
@@ -32,6 +52,10 @@ int set_di_nlink(struct gfs2_inode *ip)
di->di_nlink = ip->i_di.di_nlink;
return 0;
}
+ if (ip->i_di.di_nlink == 1) {
+ link1_set(&nlink1map, ip->i_di.di_num.no_addr, 1);
+ return 0;
+ }
/*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 */
@@ -45,12 +69,21 @@ int set_di_nlink(struct gfs2_inode *ip)
return 0;
}
+/* I'm making whyincr a macro rather than function so that the debug output
+ * matches older versions. */
+#define whyincr(no_addr, why, referenced_from, counted_links) \
+ log_debug(_("Dir (0x%llx) incremented counted links to %u " \
+ "for (0x%llx) via %s\n"), \
+ (unsigned long long)referenced_from, counted_links, \
+ (unsigned long long)no_addr, why);
+
int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip,
const char *why)
{
struct inode_info *ii = NULL;
uint64_t referenced_from = ip ? ip->i_di.di_num.no_addr : 0;
struct dir_info *di;
+ struct gfs2_inode *link_ip;
di = dirtree_find(no.no_addr);
if (di) {
@@ -58,11 +91,7 @@ int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip,
return 1;
di->counted_links++;
- log_debug( _("Dir (0x%llx) incremented counted links to %u "
- "for (0x%llx) via %s\n"),
- (unsigned long long)referenced_from,
- di->counted_links,
- (unsigned long long)no.no_addr, why);
+ whyincr(no.no_addr, why, referenced_from, di->counted_links);
return 0;
}
ii = inodetree_find(no.no_addr);
@@ -72,27 +101,52 @@ int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip,
return 1;
ii->counted_links++;
- log_debug( _("Dir (0x%llx) incremented counted "
- "links to %u for (0x%llx) via %s\n"),
- (unsigned long long)referenced_from,
- ii->counted_links, (unsigned long long)no.no_addr,
- why);
+ whyincr(no.no_addr, why, referenced_from, ii->counted_links);
return 0;
}
- log_debug( _("Ref: (0x%llx) No match found when incrementing "
- "link for (0x%llx)!\n"),
- (unsigned long long)referenced_from,
- (unsigned long long)no.no_addr);
- /* If no match was found, add a new entry and set its
- * counted links to 1 */
+ if (link1_type(&clink1map, no.no_addr) != 1) {
+ link1_set(&clink1map, no.no_addr, 1);
+ whyincr(no.no_addr, why, referenced_from, 1);
+ return 0;
+ }
+
+ link_ip = fsck_load_inode(ip->i_sbd, no.no_addr);
+ /* Check formal ino against dinode before adding to inode tree. */
+ if (no.no_formal_ino != ip->i_di.di_num.no_formal_ino) {
+ fsck_inode_put(&link_ip);
+ return 1;
+ }
+ /* Move it from the link1 maps to a real inode tree entry */
+ link1_set(&nlink1map, no.no_addr, 0);
+ link1_set(&clink1map, no.no_addr, 0);
+
+ /* If no match was found, it must be a hard link. In theory, it can't
+ be a duplicate because those were resolved in pass1b. Add a new
+ inodetree entry and set its counted links to 2 */
ii = inodetree_insert(no);
- if (ii)
- ii->counted_links = 1;
- else
+ if (!ii) {
+ log_debug( _("Ref: (0x%llx) Error incrementing link for "
+ "(0x%llx)!\n"),
+ (unsigned long long)referenced_from,
+ (unsigned long long)no.no_addr);
+ fsck_inode_put(&link_ip);
return -1;
+ }
+ ii->di_num = link_ip->i_di.di_num;
+ fsck_inode_put(&link_ip);
+ ii->di_nlink = 1; /* Must be 1 or it wouldn't have gotten into the
+ nlink1map */
+ ii->counted_links = 2;
+ whyincr(no.no_addr, why, referenced_from, ii->counted_links);
return 0;
}
+#define whydecr(no_addr, why, referenced_from, counted_links) \
+ log_debug(_("Dir (0x%llx) decremented counted links to %u " \
+ "for (0x%llx) via %s\n"), \
+ (unsigned long long)referenced_from, counted_links, \
+ (unsigned long long)no_addr, why);
+
int decr_link_count(uint64_t inode_no, uint64_t referenced_from, int gfs1,
const char *why)
{
@@ -109,11 +163,7 @@ int decr_link_count(uint64_t inode_no, uint64_t referenced_from, int gfs1,
return 0;
}
di->counted_links--;
- log_debug( _("Dir (0x%llx) decremented counted links to %u "
- "for (0x%llx) via %s\n"),
- (unsigned long long)referenced_from,
- di->counted_links, (unsigned long long)inode_no,
- why);
+ whydecr(inode_no, why, referenced_from, di->counted_links);
return 0;
}
@@ -129,13 +179,15 @@ int decr_link_count(uint64_t inode_no, uint64_t referenced_from, int gfs1,
return 0;
}
ii->counted_links--;
- log_debug( _("Dir (0x%llx) decremented counted "
- "links to %u for (0x%llx) via %s\n"),
- (unsigned long long)referenced_from,
- ii->counted_links, (unsigned long long)inode_no,
- why);
+ whydecr(inode_no, why, referenced_from, ii->counted_links);
return 0;
}
+ if (link1_type(&clink1map, inode_no) == 1) { /* 1 -> 0 */
+ link1_set(&clink1map, inode_no, 0);
+ whydecr(inode_no, why, referenced_from, 0);
+ return 0;
+ }
+
log_debug( _("No match found when decrementing link for (0x%llx)!\n"),
(unsigned long long)inode_no);
return -1;
diff --git a/gfs2/fsck/link.h b/gfs2/fsck/link.h
index 76a195a..14534e5 100644
--- a/gfs2/fsck/link.h
+++ b/gfs2/fsck/link.h
@@ -1,6 +1,10 @@
#ifndef _LINK_H
#define _LINK_H
+extern struct gfs2_bmap nlink1map; /* map of dinodes with nlink == 1 */
+extern struct gfs2_bmap clink1map; /* map of dinodes w/counted links == 1 */
+
+int link1_set(struct gfs2_bmap *bmap, uint64_t bblock, int mark);
int set_di_nlink(struct gfs2_inode *ip);
int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip,
const char *why);
diff --git a/gfs2/fsck/main.c b/gfs2/fsck/main.c
index 91ebe28..c5967bc 100644
--- a/gfs2/fsck/main.c
+++ b/gfs2/fsck/main.c
@@ -20,6 +20,7 @@
#include "copyright.cf"
#include "libgfs2.h"
#include "fsck.h"
+#include "link.h"
#include "osi_list.h"
#include "metawalk.h"
#include "util.h"
@@ -352,6 +353,8 @@ int main(int argc, char **argv)
if (!opts.no && errors_corrected)
log_notice( _("Writing changes to disk\n"));
fsync(sdp->device_fd);
+ link1_destroy(&nlink1map);
+ link1_destroy(&clink1map);
destroy(sdp);
if (sb_fixed)
log_warn(_("Superblock was reset. Use tunegfs2 to manually "
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 3217711..6b7146e 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -14,6 +14,7 @@
#include <logging.h>
#include "libgfs2.h"
+#include "link.h"
#include "osi_tree.h"
#include "fsck.h"
#include "util.h"
@@ -88,6 +89,7 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, int error_on_dinode,
ii = inodetree_find(blk);
if (ii)
inodetree_delete(ii);
+ link1_set(&nlink1map, blk, 0);
}
rgd->rg.rg_free++;
if (sdp->gfs1)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index f4eea49..ee20b9e 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -2018,6 +2018,20 @@ static int gfs2_blockmap_create(struct gfs2_bmap *bmap, uint64_t size)
return 0;
}
+
+static int link1_create(struct gfs2_bmap *bmap, uint64_t size)
+{
+ bmap->size = size;
+
+ /* Have to add 1 to BLOCKMAP_SIZE since it's 0-based and mallocs
+ * must be 1-based */
+ bmap->mapsize = BLOCKMAP_SIZE1(size) + 1;
+
+ if (!(bmap->map = calloc(bmap->mapsize, sizeof(char))))
+ return -ENOMEM;
+ return 0;
+}
+
static struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size,
uint64_t *addl_mem_needed)
{
@@ -2054,6 +2068,14 @@ static void *gfs2_bmap_destroy(struct gfs2_sbd *sdp, struct gfs2_bmap *il)
return il;
}
+static void enomem(uint64_t addl_mem_needed)
+{
+ log_crit( _("This system doesn't have enough memory and swap space to fsck this file system.\n"));
+ log_crit( _("Additional memory needed is approximately: %lluMB\n"),
+ (unsigned long long)(addl_mem_needed / 1048576ULL));
+ log_crit( _("Please increase your swap space by that amount and run gfs2_fsck again.\n"));
+}
+
/**
* pass1 - walk through inodes and check inode state
*
@@ -2079,10 +2101,20 @@ int pass1(struct gfs2_sbd *sdp)
bl = gfs2_bmap_create(sdp, last_fs_block+1, &addl_mem_needed);
if (!bl) {
- log_crit( _("This system doesn't have enough memory and swap space to fsck this file system.\n"));
- log_crit( _("Additional memory needed is approximately: %lluMB\n"),
- (unsigned long long)(addl_mem_needed / 1048576ULL));
- log_crit( _("Please increase your swap space by that amount and run gfs2_fsck again.\n"));
+ enomem(addl_mem_needed);
+ return FSCK_ERROR;
+ }
+ addl_mem_needed = link1_create(&nlink1map, last_fs_block+1);
+ if (addl_mem_needed) {
+ enomem(addl_mem_needed);
+ gfs2_bmap_destroy(sdp, bl);
+ return FSCK_ERROR;
+ }
+ addl_mem_needed = link1_create(&clink1map, last_fs_block+1);
+ if (addl_mem_needed) {
+ enomem(addl_mem_needed);
+ link1_destroy(&nlink1map);
+ gfs2_bmap_destroy(sdp, bl);
return FSCK_ERROR;
}
osi_list_init(&gfs1_rindex_blks.list);
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index db477ff..d6ab285 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -10,6 +10,7 @@
#include <logging.h>
#include "libgfs2.h"
+#include "link.h"
#include "fsck.h"
#include "osi_list.h"
#include "util.h"
@@ -353,6 +354,8 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
di = dirtree_find(ip->i_di.di_num.no_addr);
if (di)
dirtree_delete(di);
+ link1_set(&nlink1map, ip->i_di.di_num.no_addr,
+ 0);
fsck_bitmap_set(ip, ip->i_di.di_num.no_addr,
_("duplicate referencing bad"),
GFS2_BLKST_UNLINKED);
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 3a8646f..d4f50d2 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -195,6 +195,8 @@ static int bad_formal_ino(struct gfs2_inode *ip, struct gfs2_dirent *dent,
di = dirtree_find(entry.no_addr);
if (di)
inum = di->dinode;
+ else if (link1_type(&clink1map, entry.no_addr) == 1)
+ inum = entry;
}
log_err( _("Directory entry '%s' pointing to block %llu (0x%llx) in "
"directory %llu (0x%llx) has the wrong 'formal' inode "
@@ -613,6 +615,12 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent,
di = dirtree_find(entry->no_addr);
if (di)
inum = di->dinode;
+ else if (link1_type(&nlink1map, entry->no_addr) == 1) {
+ /* Since we don't have ii or di, the only way to
+ validate formal_ino is to read in the inode, which
+ would kill performance. So skip it for now. */
+ return 0;
+ }
}
if (inum.no_formal_ino != entry->no_formal_ino) {
log_err( _("Directory entry '%s' pointing to block %llu "
diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c
index c65d321..16339cc 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -9,6 +9,7 @@
#include <logging.h>
#include "libgfs2.h"
#include "fsck.h"
+#include "link.h"
#include "lost_n_found.h"
#include "inode_hash.h"
#include "metawalk.h"
@@ -153,11 +154,30 @@ static void handle_inconsist(struct gfs2_sbd *sdp, uint64_t no_addr,
}
}
+static int adjust_lf_links(int lf_addition)
+{
+ struct dir_info *lf_di;
+
+ if (lf_dip == NULL)
+ return 0;
+
+ if (!lf_addition)
+ return 0;
+
+ if (!(lf_di = dirtree_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_link_count(lf_di->counted_links, lf_dip);
+ }
+ return 0;
+}
+
static int scan_inode_list(struct gfs2_sbd *sdp)
{
struct osi_node *tmp, *next = NULL;
struct inode_info *ii;
- struct dir_info *lf_di;
int lf_addition = 0;
/* FIXME: should probably factor this out into a generic
@@ -187,25 +207,13 @@ static int scan_inode_list(struct gfs2_sbd *sdp)
(unsigned long long)ii->di_num.no_addr, ii->di_nlink);
} /* osi_list_foreach(tmp, list) */
- if (lf_dip == NULL)
- return 0;
-
- if (lf_addition) {
- if (!(lf_di = dirtree_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_link_count(lf_di->counted_links, lf_dip);
- }
- }
-
- return 0;
+ return adjust_lf_links(lf_addition);
}
static int scan_dir_list(struct gfs2_sbd *sdp)
{
struct osi_node *tmp, *next = NULL;
- struct dir_info *di, *lf_di;
+ struct dir_info *di;
int lf_addition = 0;
/* FIXME: should probably factor this out into a generic
@@ -232,19 +240,33 @@ static int scan_dir_list(struct gfs2_sbd *sdp)
(unsigned long long)di->dinode.no_addr, di->di_nlink);
} /* osi_list_foreach(tmp, list) */
- if (lf_dip == NULL)
- return 0;
+ return adjust_lf_links(lf_addition);
+}
- if (lf_addition) {
- if (!(lf_di = dirtree_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_link_count(lf_di->counted_links, lf_dip);
+static int scan_nlink1_list(struct gfs2_sbd *sdp)
+{
+ uint64_t blk;
+ uint32_t counted_links;
+ int lf_addition = 0;
+
+ for (blk = 0; blk < last_fs_block; blk++) {
+ if (skip_this_pass || fsck_abort)
+ return 0;
+ if (link1_type(&nlink1map, blk) == 0)
+ continue;
+
+ if (link1_type(&clink1map, blk) == 0) {
+ /* In other cases, counted_links is a pointer to a
+ real count that gets incremented when it's added
+ to lost+found. In this case, however, there's not a
+ real count, so we fake it out to be 1. */
+ counted_links = 1;
+ if (handle_unlinked(sdp, blk, &counted_links,
+ &lf_addition))
+ continue;
}
}
-
- return 0;
+ return adjust_lf_links(lf_addition);
}
/**
@@ -261,15 +283,21 @@ int pass4(struct gfs2_sbd *sdp)
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"));
+ log_info( _("Checking inode reference counts: multi-links.\n"));
if (scan_inode_list(sdp)) {
stack;
return FSCK_ERROR;
}
+ log_info( _("Checking inode reference counts: directories.\n"));
if (scan_dir_list(sdp)) {
stack;
return FSCK_ERROR;
}
+ log_info( _("Checking inode reference counts: normal links.\n"));
+ if (scan_nlink1_list(sdp)) {
+ stack;
+ return FSCK_ERROR;
+ }
if (lf_dip)
log_debug( _("At end of pass4, lost+found entries is %u\n"),
diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h
index aa01552..4545594 100644
--- a/gfs2/fsck/util.h
+++ b/gfs2/fsck/util.h
@@ -23,9 +23,12 @@ extern void dup_listent_delete(struct duptree *dt, struct inode_with_dups *id);
extern const char *reftypes[ref_types + 1];
+#define BLOCKMAP_SIZE1(size) ((size) >> 3)
#define BLOCKMAP_SIZE2(size) ((size) >> 2)
#define BLOCKMAP_BYTE_OFFSET2(x) ((x & 0x0000000000000003) << 1)
+#define BLOCKMAP_BYTE_OFFSET1(x) (x & 0x0000000000000007)
#define BLOCKMAP_MASK2 (0x3)
+#define BLOCKMAP_MASK1 (1)
struct fsck_pass {
const char *name;
@@ -44,6 +47,26 @@ static inline int block_type(struct gfs2_bmap *bl, uint64_t bblock)
return btype;
}
+static inline int link1_type(struct gfs2_bmap *bl, uint64_t bblock)
+{
+ static unsigned char *byte;
+ static uint64_t b;
+ static int btype;
+
+ byte = bl->map + BLOCKMAP_SIZE1(bblock);
+ b = BLOCKMAP_BYTE_OFFSET1(bblock);
+ btype = (*byte & (BLOCKMAP_MASK1 << b )) >> b;
+ return btype;
+}
+
+static inline void link1_destroy(struct gfs2_bmap *bmap)
+{
+ if (bmap->map)
+ free(bmap->map);
+ bmap->size = 0;
+ bmap->mapsize = 0;
+}
+
static inline int bitmap_type(struct gfs2_sbd *sdp, uint64_t bblock)
{
struct rgrp_tree *rgd;
8 years
gfs2-utils: master - fsck.gfs2: move link count info for directories
to directory tree
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=690de221...
Commit: 690de2210a3cbd48924a1e536024b0ca6a231205
Parent: c7f0e58b2da4be0fab413b51efd9c4cd715c8363
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Mar 30 14:32:30 2016 -0400
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 9 10:50:12 2016 -0500
fsck.gfs2: move link count info for directories to directory tree
This patch saves memory in fsck.gfs2. Instead of keeping an
inode_info structure in a tree for directories, we keep the info
we need--the link counts--in the directory tree structure instead.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/fsck/fsck.h | 2 +
gfs2/fsck/inode_hash.c | 3 +-
gfs2/fsck/link.c | 49 ++++++++++++++++++++++++++++++++++++++++-
gfs2/fsck/link.h | 2 +-
gfs2/fsck/lost_n_found.c | 2 +-
gfs2/fsck/pass1b.c | 4 +++
gfs2/fsck/pass2.c | 34 +++++++++++++++++++++------
gfs2/fsck/pass3.c | 2 +-
gfs2/fsck/pass4.c | 55 +++++++++++++++++++++++++++++++++++++++++++--
9 files changed, 136 insertions(+), 17 deletions(-)
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index 54b40ea..09b96ed 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -46,6 +46,8 @@ struct dir_info
struct gfs2_inum dinode;
uint64_t treewalk_parent;
struct gfs2_inum dotdot_parent;
+ uint32_t di_nlink;
+ uint32_t counted_links;
uint8_t checked:1;
};
diff --git a/gfs2/fsck/inode_hash.c b/gfs2/fsck/inode_hash.c
index eeb0a84..09303d7 100644
--- a/gfs2/fsck/inode_hash.c
+++ b/gfs2/fsck/inode_hash.c
@@ -53,8 +53,7 @@ struct inode_info *inodetree_insert(struct gfs2_inum di_num)
return NULL;
}
/* Add new node and rebalance tree. */
- data->di_num.no_addr = di_num.no_addr;
- data->di_num.no_formal_ino = di_num.no_formal_ino;
+ data->di_num = di_num;
osi_link_node(&data->node, parent, newn);
osi_insert_color(&data->node, &inodetree);
diff --git a/gfs2/fsck/link.c b/gfs2/fsck/link.c
index 9a958b4..7e8acb7 100644
--- a/gfs2/fsck/link.c
+++ b/gfs2/fsck/link.c
@@ -13,11 +13,25 @@
#include "fsck.h"
#include "inode_hash.h"
#include "link.h"
+#include "util.h"
int set_di_nlink(struct gfs2_inode *ip)
{
struct inode_info *ii;
+ struct dir_info *di;
+ if (is_dir(&ip->i_di, ip->i_sbd->gfs1)) {
+ di = dirtree_find(ip->i_di.di_num.no_addr);
+ if (di == NULL) {
+ log_err(_("Error: directory %lld (0x%llx) is not "
+ "in the dir_tree (set).\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
+ return -1;
+ }
+ di->di_nlink = ip->i_di.di_nlink;
+ return 0;
+ }
/*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 */
@@ -36,7 +50,21 @@ int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip,
{
struct inode_info *ii = NULL;
uint64_t referenced_from = ip ? ip->i_di.di_num.no_addr : 0;
+ struct dir_info *di;
+
+ di = dirtree_find(no.no_addr);
+ if (di) {
+ if (di->dinode.no_formal_ino != no.no_formal_ino)
+ return 1;
+ di->counted_links++;
+ log_debug( _("Dir (0x%llx) incremented counted links to %u "
+ "for (0x%llx) via %s\n"),
+ (unsigned long long)referenced_from,
+ di->counted_links,
+ (unsigned long long)no.no_addr, why);
+ return 0;
+ }
ii = inodetree_find(no.no_addr);
/* If the list has entries, look for one that matches inode_no */
if (ii) {
@@ -65,10 +93,29 @@ int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip,
return 0;
}
-int decr_link_count(uint64_t inode_no, uint64_t referenced_from,
+int decr_link_count(uint64_t inode_no, uint64_t referenced_from, int gfs1,
const char *why)
{
struct inode_info *ii = NULL;
+ struct dir_info *di;
+
+ di = dirtree_find(inode_no);
+ if (di) {
+ if (!di->counted_links) {
+ log_debug( _("Dir (0x%llx)'s link to "
+ "(0x%llx) via %s is zero!\n"),
+ (unsigned long long)referenced_from,
+ (unsigned long long)inode_no, why);
+ return 0;
+ }
+ di->counted_links--;
+ log_debug( _("Dir (0x%llx) decremented counted links to %u "
+ "for (0x%llx) via %s\n"),
+ (unsigned long long)referenced_from,
+ di->counted_links, (unsigned long long)inode_no,
+ why);
+ return 0;
+ }
ii = inodetree_find(inode_no);
/* If the list has entries, look for one that matches
diff --git a/gfs2/fsck/link.h b/gfs2/fsck/link.h
index 842afb9..76a195a 100644
--- a/gfs2/fsck/link.h
+++ b/gfs2/fsck/link.h
@@ -4,7 +4,7 @@
int set_di_nlink(struct gfs2_inode *ip);
int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip,
const char *why);
-int decr_link_count(uint64_t inode_no, uint64_t referenced_from,
+int decr_link_count(uint64_t inode_no, uint64_t referenced_from, int gfs1,
const char *why);
#endif /* _LINK_H */
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index 9c85f52..197ae7d 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -43,7 +43,7 @@ static void add_dotdot(struct gfs2_inode *ip)
if (dip->i_di.di_num.no_formal_ino ==
di->dotdot_parent.no_formal_ino) {
decr_link_count(di->dotdot_parent.no_addr,
- ip->i_di.di_num.no_addr,
+ ip->i_di.di_num.no_addr, sdp->gfs1,
_(".. unlinked, moving to lost+found"));
if (dip->i_di.di_nlink > 0) {
dip->i_di.di_nlink--;
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 182c6cb..db477ff 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -203,6 +203,7 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
};
enum dup_ref_type this_ref;
struct inode_info *ii;
+ struct dir_info *di;
int found_good_ref = 0;
int q;
@@ -349,6 +350,9 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
ii = inodetree_find(ip->i_di.di_num.no_addr);
if (ii)
inodetree_delete(ii);
+ di = dirtree_find(ip->i_di.di_num.no_addr);
+ if (di)
+ dirtree_delete(di);
fsck_bitmap_set(ip, ip->i_di.di_num.no_addr,
_("duplicate referencing bad"),
GFS2_BLKST_UNLINKED);
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 02d82e4..3a8646f 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -181,12 +181,21 @@ static int bad_formal_ino(struct gfs2_inode *ip, struct gfs2_dirent *dent,
struct gfs2_buffer_head *bh)
{
struct inode_info *ii;
+ struct dir_info *di = NULL;
struct gfs2_inode *child_ip;
struct gfs2_inum childs_dotdot;
struct gfs2_sbd *sdp = ip->i_sbd;
int error;
+ struct gfs2_inum inum = { 0 };
ii = inodetree_find(entry.no_addr);
+ if (ii)
+ inum = ii->di_num;
+ else {
+ di = dirtree_find(entry.no_addr);
+ if (di)
+ inum = di->dinode;
+ }
log_err( _("Directory entry '%s' pointing to block %llu (0x%llx) in "
"directory %llu (0x%llx) has the wrong 'formal' inode "
"number.\n"), tmp_name, (unsigned long long)entry.no_addr,
@@ -196,8 +205,8 @@ static int bad_formal_ino(struct gfs2_inode *ip, struct gfs2_dirent *dent,
log_err( _("The directory entry has %llu (0x%llx) but the inode has "
"%llu (0x%llx)\n"), (unsigned long long)entry.no_formal_ino,
(unsigned long long)entry.no_formal_ino,
- (unsigned long long)ii->di_num.no_formal_ino,
- (unsigned long long)ii->di_num.no_formal_ino);
+ (unsigned long long)inum.no_formal_ino,
+ (unsigned long long)inum.no_formal_ino);
if (q != GFS2_BLKST_DINODE || !strcmp("..", tmp_name)) {
if (query( _("Remove the corrupt directory entry? (y/n) ")))
return 1;
@@ -214,7 +223,7 @@ static int bad_formal_ino(struct gfs2_inode *ip, struct gfs2_dirent *dent,
"linkage.\n"));
if (query( _("Fix the bad directory entry? (y/n) "))) {
log_err( _("Fixing the corrupt directory entry.\n"));
- entry.no_formal_ino = ii->di_num.no_formal_ino;
+ entry.no_formal_ino = inum.no_formal_ino;
de->de_inum.no_formal_ino = entry.no_formal_ino;
gfs2_dirent_out(de, (char *)dent);
bmodified(bh);
@@ -446,6 +455,8 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent,
struct gfs2_inode *entry_ip = NULL;
int error;
struct inode_info *ii;
+ struct dir_info *di = NULL;
+ struct gfs2_inum inum = { 0 };
*isdir = 0;
if (!valid_block(ip->i_sbd, entry->no_addr)) {
@@ -541,7 +552,7 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent,
/* Don't decrement the link here: Here in pass2, we increment
only when we know it's okay.
- decr_link_count(ip->i_di.di_num.no_addr); */
+ decr_link_count(ip->i_di.di_num.no_addr, blah); */
/* If it was previously marked invalid (i.e. known
to be bad, not just a free block, etc.) then the temptation
would be to delete any metadata it holds. The trouble is:
@@ -596,7 +607,14 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent,
/* We need to verify the formal inode number matches. If it doesn't,
it needs to be deleted. */
ii = inodetree_find(entry->no_addr);
- if (ii && ii->di_num.no_formal_ino != entry->no_formal_ino) {
+ if (ii)
+ inum = ii->di_num;
+ else {
+ di = dirtree_find(entry->no_addr);
+ if (di)
+ inum = di->dinode;
+ }
+ if (inum.no_formal_ino != entry->no_formal_ino) {
log_err( _("Directory entry '%s' pointing to block %llu "
"(0x%llx) in directory %llu (0x%llx) has the "
"wrong 'formal' inode number.\n"), tmp_name,
@@ -608,15 +626,15 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent,
"inode has %llu (0x%llx)\n"),
(unsigned long long)entry->no_formal_ino,
(unsigned long long)entry->no_formal_ino,
- (unsigned long long)ii->di_num.no_formal_ino,
- (unsigned long long)ii->di_num.no_formal_ino);
+ (unsigned long long)inum.no_formal_ino,
+ (unsigned long long)inum.no_formal_ino);
return 1;
}
/* Check for a special case where a (bad) GFS1 dirent points to what
* is not a known inode. It could be other GFS1 metadata, such as an
* eattr or indirect block, but marked "dinode" in the bitmap because
* gfs1 marked all gfs1 metadata that way. */
- if (ii == NULL && sdp->gfs1) {
+ if (ii == NULL && di == NULL && sdp->gfs1) {
struct gfs2_buffer_head *tbh;
tbh = bread(sdp, entry->no_addr);
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index d5f4ea2..2fa0bdb 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -38,7 +38,7 @@ static int attach_dotdot_to(struct gfs2_sbd *sdp, uint64_t newdotdot,
if (gfs2_dirent_del(ip, filename, filename_len))
log_warn( _("Unable to remove \"..\" directory entry.\n"));
else
- decr_link_count(olddotdot, block, _("old \"..\""));
+ decr_link_count(olddotdot, block, sdp->gfs1, _("old \"..\""));
err = dir_add(ip, filename, filename_len, &pip->i_di.di_num,
(sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
if (err) {
diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c
index 5dc6e73..c65d321 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -157,6 +157,7 @@ static int scan_inode_list(struct gfs2_sbd *sdp)
{
struct osi_node *tmp, *next = NULL;
struct inode_info *ii;
+ struct dir_info *lf_di;
int lf_addition = 0;
/* FIXME: should probably factor this out into a generic
@@ -169,7 +170,6 @@ static int scan_inode_list(struct gfs2_sbd *sdp)
/* Don't check reference counts on the special gfs files */
if (sdp->gfs1 &&
((ii->di_num.no_addr == sdp->md.riinode->i_di.di_num.no_addr) ||
- (ii->di_num.no_addr == sdp->md.jiinode->i_di.di_num.no_addr) ||
(ii->di_num.no_addr == sdp->md.qinode->i_di.di_num.no_addr) ||
(ii->di_num.no_addr == sdp->md.statfs->i_di.di_num.no_addr)))
continue;
@@ -191,11 +191,56 @@ static int scan_inode_list(struct gfs2_sbd *sdp)
return 0;
if (lf_addition) {
- if (!(ii = inodetree_find(lf_dip->i_di.di_num.no_addr))) {
+ if (!(lf_di = dirtree_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_link_count(ii->counted_links, lf_dip);
+ fix_link_count(lf_di->counted_links, lf_dip);
+ }
+ }
+
+ return 0;
+}
+
+static int scan_dir_list(struct gfs2_sbd *sdp)
+{
+ struct osi_node *tmp, *next = NULL;
+ struct dir_info *di, *lf_di;
+ int lf_addition = 0;
+
+ /* FIXME: should probably factor this out into a generic
+ * scanning fxn */
+ for (tmp = osi_first(&dirtree); tmp; tmp = next) {
+ if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
+ return 0;
+ next = osi_next(tmp);
+ di = (struct dir_info *)tmp;
+ /* Don't check reference counts on the special gfs files */
+ if (sdp->gfs1 &&
+ di->dinode.no_addr == sdp->md.jiinode->i_di.di_num.no_addr)
+ continue;
+ if (di->counted_links == 0) {
+ if (handle_unlinked(sdp, di->dinode.no_addr,
+ &di->counted_links, &lf_addition))
+ continue;
+ } else if (di->di_nlink != di->counted_links) {
+ handle_inconsist(sdp, di->dinode.no_addr,
+ &di->di_nlink, di->counted_links);
+ }
+ log_debug( _("block %llu (0x%llx) has link count %d\n"),
+ (unsigned long long)di->dinode.no_addr,
+ (unsigned long long)di->dinode.no_addr, di->di_nlink);
+ } /* osi_list_foreach(tmp, list) */
+
+ if (lf_dip == NULL)
+ return 0;
+
+ if (lf_addition) {
+ if (!(lf_di = dirtree_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_link_count(lf_di->counted_links, lf_dip);
}
}
@@ -221,6 +266,10 @@ int pass4(struct gfs2_sbd *sdp)
stack;
return FSCK_ERROR;
}
+ if (scan_dir_list(sdp)) {
+ stack;
+ return FSCK_ERROR;
+ }
if (lf_dip)
log_debug( _("At end of pass4, lost+found entries is %u\n"),
8 years
gfs2-utils: master - fsck.gfs2: Fix white space problems
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=c7f0e58b...
Commit: c7f0e58b2da4be0fab413b51efd9c4cd715c8363
Parent: 14b459c35510ebf1b3ec5155d9f06d4439ddd169
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Mar 30 14:29:04 2016 -0400
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 9 10:50:12 2016 -0500
fsck.gfs2: Fix white space problems
This patch changes some white space from spaces to tabs.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/fsck/fsck.h | 19 +++++++++----------
1 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index d57ccfd..54b40ea 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -33,21 +33,20 @@ struct gfs2_bmap {
struct inode_info
{
- struct osi_node node;
- struct gfs2_inum di_num;
- uint32_t di_nlink; /* the number of links the inode
+ struct osi_node node;
+ struct gfs2_inum di_num;
+ uint32_t di_nlink; /* the number of links the inode
* thinks it has */
- uint32_t counted_links; /* the number of links we've found */
+ uint32_t counted_links; /* the number of links we've found */
};
struct dir_info
{
- struct osi_node node;
- struct gfs2_inum dinode;
- uint64_t treewalk_parent;
- struct gfs2_inum dotdot_parent;
- uint8_t checked:1;
-
+ struct osi_node node;
+ struct gfs2_inum dinode;
+ uint64_t treewalk_parent;
+ struct gfs2_inum dotdot_parent;
+ uint8_t checked:1;
};
struct dir_status {
8 years