cluster: RHEL6 - fsck.gfs2: Print step 2 duplicate debug msg first
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 165021e9be8503dd8ffc37edd2da71d1aa994df0
Parent: 0a25dd5b441e6743180e94100b241ed137bfda76
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 6 14:19:09 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Jan 20 08:26:27 2012 -0600
fsck.gfs2: Print step 2 duplicate debug msg first
In testing fsck.gfs2 I noticed that when duplicates were resolved,
the "step 2" debug message was printed after step 2 was actually
done. That's misleading, so this patch changes it.
rhbz#675723
---
gfs2/fsck/pass1b.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index da71f99..39c3289 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -642,15 +642,15 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
* directory inode referencing a data block as a leaf block.
*/
if (!last_reference) {
- last_reference = resolve_dup_references(sdp, b,
- &b->ref_inode_list,
- &dh, 0,
- acceptable_ref);
log_debug( _("----------------------------------------------\n"
"Step 2: Eliminate references to block %llu "
"(0x%llx) that need the wrong block type.\n"),
(unsigned long long)b->block,
(unsigned long long)b->block);
+ last_reference = resolve_dup_references(sdp, b,
+ &b->ref_inode_list,
+ &dh, 0,
+ acceptable_ref);
}
/* Step 3 - We have multiple dinodes referencing it as the correct
* type. Just blast one of them.
12 years, 3 months
cluster: RHEL6 - fsck.gfs2: Recognize partially gfs2-converted dinodes
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 0a25dd5b441e6743180e94100b241ed137bfda76
Parent: 9b917c047a4ceafc6b15994bdd5a9bd13120173b
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 6 14:16:59 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Jan 20 08:26:27 2012 -0600
fsck.gfs2: Recognize partially gfs2-converted dinodes
In testing fsck.gfs2 I noticed that if a file system had some
leftover gfs2 dinodes (due to an interrupted gfs2_convert or
in my case, because I had previously loaded gfs2 metadata that
left gfs2 blocks laying around the gfs1 file system) those gfs2
dinodes were not properly processed. In particular, it would not
recognize gfs2-style directories as directories because of the
difference in where dinode mode information is kept. This patch
gives fsck.gfs2 the ability to correctly identify gfs2 dinodes
when checking a gfs1 file system.
rhbz#675723
---
gfs2/fsck/lost_n_found.c | 4 ++--
gfs2/fsck/util.c | 2 +-
gfs2/fsck/util.h | 11 +++++++++--
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index c028f8d..16afb11 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -207,7 +207,7 @@ int add_inode_to_lf(struct gfs2_inode *ip){
lf_blocks = lf_dip->i_di.di_blocks;
if (sdp->gfs1)
- mode = gfs_to_gfs2_mode(ip->i_di.__pad1);
+ mode = gfs_to_gfs2_mode(ip);
else
mode = ip->i_di.di_mode & S_IFMT;
@@ -266,7 +266,7 @@ int add_inode_to_lf(struct gfs2_inode *ip){
incr_link_count(ip->i_di.di_num.no_addr, lf_dip->i_di.di_num.no_addr,
_("from lost+found"));
/* If it's a directory, lost+found is back-linked to it via .. */
- if (is_dir(&ip->i_di, sdp->gfs1))
+ if (mode == S_IFDIR)
incr_link_count(lf_dip->i_di.di_num.no_addr,
ip->i_di.di_num.no_addr, _("to lost+found"));
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 0be86de..92818fb 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -479,7 +479,7 @@ int set_ip_blockmap(struct gfs2_inode *ip, int instree)
uint32_t mode;
if (sdp->gfs1)
- mode = gfs_to_gfs2_mode(ip->i_di.__pad1);
+ mode = gfs_to_gfs2_mode(ip);
else
mode = ip->i_di.di_mode & S_IFMT;
diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h
index 6581cb1..2f74af3 100644
--- a/gfs2/fsck/util.h
+++ b/gfs2/fsck/util.h
@@ -143,8 +143,10 @@ static inline int is_dir(struct gfs2_dinode *dinode, int gfs1)
return 0;
}
-static inline uint32_t gfs_to_gfs2_mode(uint32_t gfs1mode)
+static inline uint32_t gfs_to_gfs2_mode(struct gfs2_inode *ip)
{
+ uint16_t gfs1mode = ip->i_di.__pad1;
+
switch (gfs1mode) {
case GFS_FILE_DIR:
return S_IFDIR;
@@ -161,7 +163,12 @@ static inline uint32_t gfs_to_gfs2_mode(uint32_t gfs1mode)
case GFS_FILE_SOCK:
return S_IFSOCK;
default:
- return S_IFREG;
+ /* This could be an aborted gfs2_convert so look for both. */
+ if (ip->i_di.di_entries ||
+ (ip->i_di.di_mode & S_IFMT) == S_IFDIR)
+ return S_IFDIR;
+ else
+ return S_IFREG;
}
}
12 years, 3 months
cluster: RHEL6 - fsck.gfs2: system dinodes take priority over user dinodes
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 9b917c047a4ceafc6b15994bdd5a9bd13120173b
Parent: e648de42ea46cccc0257e0bc5cb13cbeecf45a5f
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 6 14:14:29 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Jan 20 08:26:27 2012 -0600
fsck.gfs2: system dinodes take priority over user dinodes
In testing fsck.gfs2 I noticed some incorrect behavior: If a block
was referenced incorrectly by two dinodes, fsck deleted which
ever reference it found first. Therefore, if a system dinode
and a user dinode referenced the same block, fsck.gfs2 could
mistakenly delete the system dinode. For example, a journal could
get deleted because a user dinode improperly referenced one of its
blocks. This patch gives priority to system dinodes when resolving
duplicates.
rhbz#675723
---
gfs2/fsck/pass1b.c | 9 ++++++++-
gfs2/fsck/util.c | 14 ++++++++++++--
2 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index b7be683..da71f99 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -483,7 +483,14 @@ static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
continue; /* don't delete the dinode */
}
}
-
+ /* If this reference is from a system inode, for example, if
+ it's data or metadata inside a journal, the reference
+ should take priority over user dinodes that reference the
+ block. */
+ if (!found_good_ref && fsck_system_inode(sdp, id->block_no)) {
+ found_good_ref = 1;
+ continue; /* don't delete the dinode */
+ }
log_warn( _("Inode %s (%lld/0x%llx) references block "
"%llu (0x%llx) as '%s', but the block is "
"really %s.\n"),
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 69bf328..0be86de 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -280,8 +280,18 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
inode reference list otherwise put it on the normal list. */
if (!inode_valid || q == gfs2_inode_invalid)
osi_list_add_prev(&id->list, &dt->ref_invinode_list);
- else
- osi_list_add_prev(&id->list, &dt->ref_inode_list);
+ else {
+ /* If this is a system dinode, we want the duplicate
+ processing to find it first. That way references
+ from inside journals, et al, will take priority.
+ We don't want to delete journals in favor of dinodes
+ that reference a block inside a journal. */
+ if (fsck_system_inode(ip->i_sbd, id->block_no))
+ osi_list_add(&id->list, &dt->ref_inode_list);
+ else
+ osi_list_add_prev(&id->list,
+ &dt->ref_inode_list);
+ }
}
id->reftypecount[reftype]++;
id->dup_count++;
12 years, 3 months
cluster: RHEL6 - fsck.gfs2: Increment link count reporting wrong dinode
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: e648de42ea46cccc0257e0bc5cb13cbeecf45a5f
Parent: 180cde49a993e2bd32d4fc0664aad1b6703a6f41
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 6 14:11:11 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Jan 20 08:26:27 2012 -0600
fsck.gfs2: Increment link count reporting wrong dinode
The output from fsck.gfs2 was wrong when it reported about a
link count change for lost+found. This patch fixes the message
so it reports the correct dinode block number.
rhbz#675723
---
gfs2/fsck/lost_n_found.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index af4189f..c028f8d 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -268,7 +268,7 @@ int add_inode_to_lf(struct gfs2_inode *ip){
/* If it's a directory, lost+found is back-linked to it via .. */
if (is_dir(&ip->i_di, sdp->gfs1))
incr_link_count(lf_dip->i_di.di_num.no_addr,
- ip->i_di.di_mode, _("to lost+found"));
+ ip->i_di.di_num.no_addr, _("to lost+found"));
log_notice( _("Added inode #%llu (0x%llx) to lost+found\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
12 years, 3 months
cluster: RHEL6 - fsck.gfs2: Shorten debug output
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 180cde49a993e2bd32d4fc0664aad1b6703a6f41
Parent: 07afbc65f31ec524396cc5beb3ca421330e9bbaf
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 6 14:06:09 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Jan 20 08:26:27 2012 -0600
fsck.gfs2: Shorten debug output
This patch considerably shortens the debug output of fsck.gfs2 by
doing a few things. First, if fsck is just reporting the setting
of block types, it abbreviates the output by just listing other
blocks in parenthesis. Second, some of the key debug messages now give
only the block number in hexadecimal rather than both decimal and hex.
In one fsck.gfs2 run I did, it reduced the output from 32GB to 6.7GB.
rhbz#675723
---
gfs2/fsck/link.c | 38 ++++++++++++---------------
gfs2/fsck/metawalk.c | 69 ++++++++++++++++++++++++++++++++-----------------
gfs2/fsck/pass2.c | 6 ++--
3 files changed, 65 insertions(+), 48 deletions(-)
diff --git a/gfs2/fsck/link.c b/gfs2/fsck/link.c
index 18aeeb9..47365d8 100644
--- a/gfs2/fsck/link.c
+++ b/gfs2/fsck/link.c
@@ -35,22 +35,20 @@ int incr_link_count(uint64_t inode_no, uint64_t referenced_from,
struct inode_info *ii = NULL;
ii = inodetree_find(inode_no);
- /* If the list has entries, look for one that matches
- * inode_no */
+ /* If the list has entries, look for one that matches inode_no */
if (ii) {
ii->counted_links++;
- log_debug( _("Directory %lld (0x%llx) incremented counted "
- "links to %u for %"PRIu64" (0x%" PRIx64 ") "
- "via %s\n"),
+ log_debug( _("Dir (0x%llx) incremented counted "
+ "links to %u for (0x%llx) via %s\n"),
(unsigned long long)referenced_from,
- (unsigned long long)referenced_from,
- ii->counted_links, inode_no, inode_no, why);
+ ii->counted_links, (unsigned long long)inode_no,
+ why);
return 0;
}
- log_debug( _("Ref: %lld (0x%llx) No match found when incrementing "
- "link for %" PRIu64 " (0x%" PRIx64 ")!\n"),
+ log_debug( _("Ref: (0x%llx) No match found when incrementing "
+ "link for (0x%llx)!\n"),
(unsigned long long)referenced_from,
- (unsigned long long)referenced_from, inode_no, inode_no);
+ (unsigned long long)inode_no);
/* If no match was found, add a new entry and set its
* counted links to 1 */
ii = inodetree_insert(inode_no);
@@ -71,24 +69,22 @@ int decr_link_count(uint64_t inode_no, uint64_t referenced_from,
* inode_no */
if (ii) {
if (!ii->counted_links) {
- log_debug( _("Directory %lld (0x%llx)'s link to "
- " %"PRIu64" (0x%" PRIx64 ") via %s is zero!\n"),
- (unsigned long long)referenced_from,
+ log_debug( _("Dir (0x%llx)'s link to "
+ "(0x%llx) via %s is zero!\n"),
(unsigned long long)referenced_from,
- inode_no, inode_no, why);
+ (unsigned long long)inode_no, why);
return 0;
}
ii->counted_links--;
- log_debug( _("Directory %lld (0x%llx) decremented counted "
- "links to %u for %"PRIu64" (0x%" PRIx64 ") "
- "via %s\n"),
- (unsigned long long)referenced_from,
+ log_debug( _("Dir (0x%llx) decremented counted "
+ "links to %u for (0x%llx) via %s\n"),
(unsigned long long)referenced_from,
- ii->counted_links, inode_no, inode_no, why);
+ ii->counted_links, (unsigned long long)inode_no,
+ why);
return 0;
}
- log_debug( _("No match found when decrementing link for %" PRIu64
- " (0x%" PRIx64 ")!\n"), inode_no, inode_no);
+ log_debug( _("No match found when decrementing link for (0x%llx)!\n"),
+ (unsigned long long)inode_no);
return -1;
}
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index db7168b..6ddc936 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -107,36 +107,57 @@ int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
const char *caller, int fline)
{
int error;
+ static int prev_ino_addr = 0;
+ static enum gfs2_mark_block prev_mark = 0;
+ static int prevcount = 0;
if (print_level >= MSG_DEBUG) {
+ if ((ip->i_di.di_num.no_addr == prev_ino_addr) &&
+ (mark == prev_mark)) {
+ log_info("(0x%llx) ", (unsigned long long)bblock);
+ prevcount++;
+ if (prevcount > 10) {
+ log_info("\n");
+ prevcount = 0;
+ }
/* I'm circumventing the log levels here on purpose to make the
output easier to debug. */
- if (ip->i_di.di_num.no_addr == bblock) {
- print_fsck_log(MSG_DEBUG, caller, fline,
- _("%s inode found at block "
- "0x%llx: marking as '%s'\n"),
- btype, (unsigned long long)
- ip->i_di.di_num.no_addr,
- block_type_string(mark));
+ } else if (ip->i_di.di_num.no_addr == bblock) {
+ if (prevcount) {
+ log_info("\n");
+ prevcount = 0;
+ }
+ printf( _("(%s:%d) %s inode found at block "
+ "(0x%llx): marking as '%s'\n"), caller, fline,
+ btype,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ block_type_string(mark));
+
} else if (mark == gfs2_bad_block || mark == gfs2_meta_inval) {
- print_fsck_log(MSG_DEBUG, caller, fline,
- _("inode 0x%llx references "
- "%s block 0x%llx: "
- "marking as '%s'\n"),
- (unsigned long long)
- ip->i_di.di_num.no_addr,
- btype, (unsigned long long)bblock,
- block_type_string(mark));
+ if (prevcount) {
+ log_info("\n");
+ prevcount = 0;
+ }
+ printf( _("(%s:%d) inode (0x%llx) references %s block"
+ " (0x%llx): marking as '%s'\n"),
+ caller, fline,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ btype, (unsigned long long)bblock,
+ block_type_string(mark));
} else {
- print_fsck_log(MSG_DEBUG, caller, fline,
- _("inode 0x%llx references "
- "%s block 0x%llx: "
- "marking as '%s'\n"),
- (unsigned long long)
- ip->i_di.di_num.no_addr, btype,
- (unsigned long long)bblock,
- block_type_string(mark));
+ if (prevcount) {
+ log_info("\n");
+ prevcount = 0;
+ }
+ printf( _("(%s:%d) inode (0x%llx) references %s block"
+ " (0x%llx): marking as '%s'\n"),
+ caller, fline,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ btype, (unsigned long long)bblock,
+ block_type_string(mark));
}
+ prev_ino_addr = ip->i_di.di_num.no_addr;
+ prev_mark = mark;
}
/* First, check the rgrp bitmap against what we think it should be.
@@ -699,7 +720,7 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
if (!leaf.lf_next || error)
break;
leaf_no = leaf.lf_next;
- log_debug( _("Leaf chain 0x%llx detected.\n"),
+ log_debug( _("Leaf chain (0x%llx) detected.\n"),
(unsigned long long)leaf_no);
} while (1); /* while we have chained leaf blocks */
} /* for every leaf block */
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index e02fdd0..be0e5fe 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -69,7 +69,7 @@ static int set_dotdot_dir(struct gfs2_sbd *sdp, uint64_t childblock,
}
if (di->dinode != childblock) {
log_debug("'..' doesn't point to what we found: childblock "
- "0x%llx != dinode 0x%llx\n",
+ "(0x%llx) != dinode (0x%llx)\n",
(unsigned long long)childblock,
(unsigned long long)di->dinode);
return -1;
@@ -86,8 +86,8 @@ static int set_dotdot_dir(struct gfs2_sbd *sdp, uint64_t childblock,
(unsigned long long)di->dotdot_parent);
return -1;
}
- log_debug("Setting '..' for directory block 0x%llx to parent 0x%llx\n",
- (unsigned long long)childblock,
+ log_debug("Setting '..' for directory block (0x%llx) to parent "
+ "(0x%llx)\n", (unsigned long long)childblock,
(unsigned long long)parentblock);
di->dotdot_parent = parentblock;
return 0;
12 years, 3 months
cluster: RHEL6 - libgfs2: Make rebuild functions not re-read ip
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 07afbc65f31ec524396cc5beb3ca421330e9bbaf
Parent: b9070aae3f60ade86055a44caef0e1dbe08a18f9
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 6 13:55:38 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Jan 20 08:26:27 2012 -0600
libgfs2: Make rebuild functions not re-read ip
Before this patch, the libgfs2 rebuild functions in structures.c
were not consistent about reading in the gfs2_inode in-core struct.
Some of the functions did and some didn't. The previous patch to
make fsck.gfs2 operate on gfs1 introduced a problem because the code
was changed to re-read the inum and statfs files if they were rebuilt.
But since the functions already did the read, it was a double-read.
A double-read is a bad thing because inode writes are now done on
the last inode put, and the double-read messed up the counter.
(Number of inode gets should match puts). This patch makes all the
build functions consistent: they all put the inode after building,
except for root and master which have no parent inodes.
There was also a minor problem whereby leaf searches were getting
the number of entries from the directory buffer rather than from
the dinode itself. (The buffer may be out of date, but the dinode
should always be current). So there were circumstances where you
could add a new dirent to "master" but the count of entries was not
correct in the buffer, which caused the search to stop prematurely.
rhbz#675723
---
gfs2/convert/gfs2_convert.c | 3 +++
gfs2/fsck/initialize.c | 5 +++++
gfs2/libgfs2/fs_ops.c | 10 +++++-----
gfs2/libgfs2/structures.c | 4 ++--
gfs2/mkfs/main_mkfs.c | 2 ++
5 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index 9cc3258..43d0093 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -2158,9 +2158,12 @@ int main(int argc, char **argv)
build_per_node(&sb2);
/* Create the empty inode number file */
build_inum(&sb2); /* Does not do inode_put */
+ gfs2_lookupi(sb2.master_dir, "inum", 4, &sb2.md.inum);
/* Create the statfs file */
build_statfs(&sb2); /* Does not do inode_put */
+ gfs2_lookupi(sb2.master_dir, "statfs", 6, &sb2.md.statfs);
+ do_init_statfs(&sb2);
/* Create the resource group index file */
build_rindex(&sb2);
/* Create the quota file */
diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c
index cee1f49..75b363b 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -392,6 +392,7 @@ static int rebuild_master(struct gfs2_sbd *sdp)
IF2DT(S_IFREG | 0600));
} else {
build_inum(sdp);
+ gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
}
if (fix_md.statfs) {
@@ -401,6 +402,7 @@ static int rebuild_master(struct gfs2_sbd *sdp)
IF2DT(S_IFREG | 0600));
} else {
build_statfs(sdp);
+ gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
}
if (fix_md.riinode) {
@@ -422,6 +424,8 @@ static int rebuild_master(struct gfs2_sbd *sdp)
}
log_err(_("Master directory rebuilt.\n"));
+ inode_put(&sdp->md.inum);
+ inode_put(&sdp->md.statfs);
inode_put(&sdp->master_dir);
return 0;
}
@@ -635,6 +639,7 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
"a valid statfs file; aborting.\n"));
goto fail;
}
+ do_init_statfs(sdp);
}
buf = malloc(sdp->md.statfs->i_di.di_size);
// FIXME: handle failed malloc
diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c
index e99cc2a..0163371 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -1243,6 +1243,7 @@ static void dir_l_add(struct gfs2_inode *dip, const char *filename, int len,
dent->de_hash = cpu_to_be32(dent->de_hash);
dent->de_type = cpu_to_be16(type);
memcpy((char *)(dent + 1), filename, len);
+ bmodified(dip->i_bh);
}
void dir_add(struct gfs2_inode *dip, const char *filename, int len,
@@ -1437,10 +1438,9 @@ static int leaf_search(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
if (type == IS_LEAF){
struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data;
entries = be16_to_cpu(leaf->lf_entries);
- } else if (type == IS_DINODE) {
- struct gfs2_dinode *dinode = (struct gfs2_dinode *)bh->b_data;
- entries = be32_to_cpu(dinode->di_entries);
- } else
+ } else if (type == IS_DINODE)
+ entries = dip->i_di.di_entries;
+ else
return -1;
hash = gfs2_disk_hash(filename, len);
@@ -1453,7 +1453,7 @@ static int leaf_search(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
if (be32_to_cpu(dent->de_hash) == hash &&
gfs2_filecmp(filename, (char *)(dent + 1),
- be16_to_cpu(dent->de_name_len))){
+ be16_to_cpu(dent->de_name_len))) {
*dent_out = dent;
if (dent_prev)
*dent_prev = prev;
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index f53b4af..b998f2d 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -284,7 +284,7 @@ int build_inum(struct gfs2_sbd *sdp)
gfs2_dinode_print(&ip->i_di);
}
- sdp->md.inum = ip;
+ inode_put(&ip);
return 0;
}
@@ -300,7 +300,7 @@ int build_statfs(struct gfs2_sbd *sdp)
gfs2_dinode_print(&ip->i_di);
}
- sdp->md.statfs = ip;
+ inode_put(&ip);
return 0;
}
diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c
index 3db3b14..ee2a5da 100644
--- a/gfs2/mkfs/main_mkfs.c
+++ b/gfs2/mkfs/main_mkfs.c
@@ -650,7 +650,9 @@ void main_mkfs(int argc, char *argv[])
build_jindex(sdp);
build_per_node(sdp);
build_inum(sdp);
+ gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
build_statfs(sdp);
+ gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
build_rindex(sdp);
build_quota(sdp);
12 years, 3 months
cluster: RHEL6 - fsck.gfs2: Bad extended attributes not deleted properly
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: b9070aae3f60ade86055a44caef0e1dbe08a18f9
Parent: d4e3d33ad9c93930e044f571f25cf04e829a3d15
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Thu Aug 18 15:58:13 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Jan 20 08:26:27 2012 -0600
fsck.gfs2: Bad extended attributes not deleted properly
This patch fixes a couple of problems fsck.gfs2 when it discovered
corrupt extended attributes and tried to delete them. First, in
check_eattr_entries it wasn't reporting the corruption. Second,
when the EA block was freed, it wasn't returning a proper return
code which caused fsck to not update the inode accordingly.
Third, it wasn't zeroing out the EA block address properly.
Fourth, I did a small amount of reformatting.
rhbz#675723
---
gfs2/fsck/metawalk.c | 56 ++++++++++++++++++++++++++++++++++++++++---------
gfs2/fsck/pass1.c | 4 +--
gfs2/fsck/pass1c.c | 7 +++--
gfs2/fsck/pass2.c | 9 +++++--
4 files changed, 56 insertions(+), 20 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 94b0148..db7168b 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -755,6 +755,13 @@ static int check_eattr_entries(struct gfs2_inode *ip,
bh, ea_hdr,
ea_hdr_prev,
pass->private)) {
+ log_err(_("Bad extended attribute "
+ "found at block %lld "
+ "(0x%llx)"),
+ (unsigned long long)
+ be64_to_cpu(*ea_data_ptr),
+ (unsigned long long)
+ be64_to_cpu(*ea_data_ptr));
if (query( _("Repair the bad Extended "
"Attribute? (y/n) "))) {
ea_hdr->ea_num_ptrs = i;
@@ -807,12 +814,14 @@ static int check_leaf_eattr(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct metawalk_fxns *pass)
{
struct gfs2_buffer_head *bh = NULL;
- int error = 0;
-
- log_debug( _("Checking EA leaf block #%"PRIu64" (0x%" PRIx64 ").\n"),
- block, block);
if (pass->check_eattr_leaf) {
+ int error = 0;
+
+ log_debug( _("Checking EA leaf block #%llu (0x%llx).\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+
error = pass->check_eattr_leaf(ip, block, parent, &bh,
pass->private);
if (error < 0) {
@@ -886,13 +895,18 @@ int find_remove_dup(struct gfs2_inode *ip, uint64_t block, const char *btype)
/**
* free_block_if_notdup - free blocks associated with an inode, but if it's a
* duplicate, just remove that designation instead.
- * Returns: 0 if the block was freed, 1 if a duplicate reference was removed
+ * Returns: 1 if the block was freed, 0 if a duplicate reference was removed
+ * Note: The return code is handled this way because there are places in
+ * metawalk.c that assume "1" means "change was made" and "0" means
+ * change was not made.
*/
int free_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
const char *btype)
{
- if (!find_remove_dup(ip, block, btype))
+ if (!find_remove_dup(ip, block, btype)) { /* not a dup */
fsck_blockmap_set(ip, block, btype, gfs2_block_free);
+ return 1;
+ }
return 0;
}
@@ -1446,16 +1460,36 @@ int delete_data(struct gfs2_inode *ip, uint64_t block, void *private)
int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
struct gfs2_buffer_head **bh, void *private)
{
- return delete_block_if_notdup(ip, block, NULL,
- _("indirect extended attribute"),
- private);
+ int ret;
+
+ ret = delete_block_if_notdup(ip, block, NULL,
+ _("indirect extended attribute"),
+ private);
+ /* Even if it's a duplicate reference, we want to eliminate the
+ reference itself, and adjust di_blocks accordingly. */
+ if (ip->i_di.di_eattr) {
+ ip->i_di.di_blocks--;
+ if (block == ip->i_di.di_eattr)
+ ip->i_di.di_eattr = 0;
+ bmodified(ip->i_bh);
+ }
+ return ret;
}
int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
struct gfs2_buffer_head **bh, void *private)
{
- return delete_block_if_notdup(ip, block, NULL, _("extended attribute"),
- private);
+ int ret;
+
+ ret = delete_block_if_notdup(ip, block, NULL, _("extended attribute"),
+ private);
+ if (ip->i_di.di_eattr) {
+ ip->i_di.di_blocks--;
+ if (block == ip->i_di.di_eattr)
+ ip->i_di.di_eattr = 0;
+ bmodified(ip->i_bh);
+ }
+ return ret;
}
static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 32ebfba..3e6b816 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1181,9 +1181,7 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
check_metatree(ip, &invalidate_fxns);
- if (fsck_blockmap_set(ip, block, _("invalid mode"),
- gfs2_inode_invalid))
- goto bad_dinode;
+ check_inode_eattr(ip, &invalidate_fxns);
return 0;
} else if (error)
goto bad_dinode;
diff --git a/gfs2/fsck/pass1c.c b/gfs2/fsck/pass1c.c
index 150dc2f..f7a7842 100644
--- a/gfs2/fsck/pass1c.c
+++ b/gfs2/fsck/pass1c.c
@@ -62,9 +62,10 @@ static int ask_remove_eattr(struct gfs2_inode *ip)
ip->i_di.di_eattr = 0;
bmodified(ip->i_bh);
log_err( _("Bad Extended Attribute removed.\n"));
- } else
- log_err( _("Bad Extended Attribute not removed.\n"));
- return 1;
+ return 1;
+ }
+ log_err( _("Bad Extended Attribute not removed.\n"));
+ return 0;
}
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 7e20315..e02fdd0 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -203,9 +203,9 @@ static int delete_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
struct gfs2_ea_header *ea_hdr_prev,
void *private)
{
- uint64_t block = be64_to_cpu(*ea_data_ptr);
+ uint64_t block = be64_to_cpu(*ea_data_ptr);
- return delete_metadata(ip, block, NULL, 0, private);
+ return delete_metadata(ip, block, NULL, 0, private);
}
struct metawalk_fxns pass2_fxns_delete = {
@@ -343,7 +343,10 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
entry_ip = ip;
else
entry_ip = fsck_load_inode(sdp, entryblock);
- check_inode_eattr(entry_ip, &pass2_fxns_delete);
+ if (ip->i_di.di_eattr) {
+ check_inode_eattr(entry_ip,
+ &pass2_fxns_delete);
+ }
check_metatree(entry_ip, &pass2_fxns_delete);
if (entry_ip != ip)
fsck_inode_put(&entry_ip);
12 years, 3 months
cluster: RHEL6 - fsck.gfs2: Handle duplicate reference to dinode blocks
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: d4e3d33ad9c93930e044f571f25cf04e829a3d15
Parent: a07ef06fdd7048154aee94e24a3972b582d4d85a
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Thu Aug 18 11:49:07 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Jan 20 08:26:27 2012 -0600
fsck.gfs2: Handle duplicate reference to dinode blocks
The fsck.gfs2 tool was not properly handling cases where dinode
blocks were referenced by other dinodes as another type. For example,
if some dinode wrongly thought that another dinode was one of its
metadata blocks or data blocks. This patch fixes that situation by
introducing a new "ref_is_inode" duplicate reference type. The only
thing that should ever reference a dinode is a directory, and that's
a special case. Any other reference is wrong and should be removed.
This patch takes care of those situations.
The patch also moves the code that marks dinodes as their
proper type to a new function in util.c called set_ip_blockmap.
That allows duplicate processing to set the proper type in the
blockmap in cases where the invalid reference was found first
(before the dinode itself was encountered). It also removes the
redundant "reftype_str" array of descriptions in favor of a central
one already in util.c called "reftypes".
rhbz#675723
---
gfs2/fsck/fsck.h | 11 +++++---
gfs2/fsck/pass1.c | 50 +++---------------------------------
gfs2/fsck/pass1b.c | 57 +++++++++++++++++++++++++----------------
gfs2/fsck/util.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++-
gfs2/fsck/util.h | 3 +-
5 files changed, 119 insertions(+), 73 deletions(-)
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index e2640d8..edd73d7 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -61,10 +61,13 @@ struct duptree {
};
enum dup_ref_type {
- ref_as_data = 0,
- ref_as_meta = 1,
- ref_as_ea = 2,
- ref_types = 3
+ ref_as_data = 0, /* dinode references this block as a data block */
+ ref_as_meta = 1, /* dinode references this block as a metadata block */
+ ref_as_ea = 2, /* dinode references this block as an extended attr */
+ ref_is_inode= 3, /* The reference is itself a dinode. In other words,
+ it's a dinode, not pointed to as data or
+ metadata */
+ ref_types = 4,
};
struct inode_with_dups {
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 515f50a..32ebfba 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1143,7 +1143,6 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
struct block_count bc = {0};
long bad_pointers;
uint64_t block = ip->i_bh->b_blocknr;
- uint32_t mode;
bad_pointers = 0L;
@@ -1164,49 +1163,8 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
return 0;
}
- if (sdp->gfs1)
- mode = gfs_to_gfs2_mode(ip->i_di.__pad1);
- else
- mode = ip->i_di.di_mode & S_IFMT;
-
- switch (mode) {
- case S_IFDIR:
- if (fsck_blockmap_set(ip, block, _("directory"),
- gfs2_inode_dir))
- goto bad_dinode;
- if (!dirtree_insert(block))
- goto bad_dinode;
- break;
- case S_IFREG:
- if (fsck_blockmap_set(ip, block, _("file"), gfs2_inode_file))
- goto bad_dinode;
- break;
- case S_IFLNK:
- if (fsck_blockmap_set(ip, block, _("symlink"),
- gfs2_inode_lnk))
- goto bad_dinode;
- break;
- case S_IFBLK:
- if (fsck_blockmap_set(ip, block, _("block device"),
- gfs2_inode_device))
- goto bad_dinode;
- break;
- case S_IFCHR:
- if (fsck_blockmap_set(ip, block, _("character device"),
- gfs2_inode_device))
- goto bad_dinode;
- break;
- case S_IFIFO:
- if (fsck_blockmap_set(ip, block, _("fifo"),
- gfs2_inode_fifo))
- goto bad_dinode;
- break;
- case S_IFSOCK:
- if (fsck_blockmap_set(ip, block, _("socket"),
- gfs2_inode_sock))
- goto bad_dinode;
- break;
- default:
+ error = set_ip_blockmap(ip, 1);
+ if (error == -EINVAL) {
/* We found a dinode that has an invalid mode, so we can't
tell if it's a data file, directory or a socket.
Regardless, we have to invalidate its metadata in case there
@@ -1227,7 +1185,9 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
gfs2_inode_invalid))
goto bad_dinode;
return 0;
- }
+ } else if (error)
+ goto bad_dinode;
+
if (set_di_nlink(ip))
goto bad_dinode;
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 003d696..b7be683 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -13,10 +13,6 @@
#include "metawalk.h"
#include "inode_hash.h"
-const char *reftype_str[ref_types + 1] = {"data", "metadata",
- "extended attribute",
- "unimportant"};
-
struct fxn_info {
uint64_t block;
int found;
@@ -347,6 +343,10 @@ static int find_block_ref(struct gfs2_sbd *sdp, uint64_t inode)
(unsigned long long)inode);
return 1;
}
+ /* Check to see if this inode was referenced by another by mistake */
+ add_duplicate_ref(ip, inode, ref_is_inode, 1, INODE_VALID);
+
+ /* Check this dinode's metadata for references to known duplicates */
error = check_metatree(ip, &find_refs);
if (error < 0) {
stack;
@@ -374,19 +374,25 @@ static int find_block_ref(struct gfs2_sbd *sdp, uint64_t inode)
are the same type, and if so, return the type. */
static enum dup_ref_type get_ref_type(struct inode_with_dups *id)
{
- if (id->reftypecount[ref_as_ea] &&
- !id->reftypecount[ref_as_data] &&
- !id->reftypecount[ref_as_meta])
- return ref_as_ea;
- if (!id->reftypecount[ref_as_ea] &&
- id->reftypecount[ref_as_data] &&
- !id->reftypecount[ref_as_meta])
- return ref_as_data;
- if (!id->reftypecount[ref_as_ea] &&
- !id->reftypecount[ref_as_data] &&
- id->reftypecount[ref_as_meta])
- return ref_as_meta;
- return ref_types; /* multiple references */
+ enum dup_ref_type t, i;
+ int found_type_with_ref;
+ int found_other_types;
+
+ for (t = ref_as_data; t < ref_types; t++) {
+ found_type_with_ref = 0;
+ found_other_types = 0;
+ for (i = ref_as_data; i < ref_types; i++) {
+ if (id->reftypecount[i]) {
+ if (t == i)
+ found_type_with_ref = 1;
+ else
+ found_other_types = 1;
+ }
+ }
+ if (found_type_with_ref)
+ return found_other_types ? ref_types : t;
+ }
+ return ref_types;
}
static void log_inode_reference(struct duptree *b, osi_list_t *tmp, int inval)
@@ -396,9 +402,10 @@ static void log_inode_reference(struct duptree *b, osi_list_t *tmp, int inval)
id = osi_list_entry(tmp, struct inode_with_dups, list);
if (id->dup_count == 1)
- sprintf(reftypestring, "as %s", reftype_str[get_ref_type(id)]);
+ sprintf(reftypestring, "as %s", reftypes[get_ref_type(id)]);
else
- sprintf(reftypestring, "%d/%d/%d",
+ sprintf(reftypestring, "%d/%d/%d/%d",
+ id->reftypecount[ref_is_inode],
id->reftypecount[ref_as_data],
id->reftypecount[ref_as_meta],
id->reftypecount[ref_as_ea]);
@@ -484,8 +491,7 @@ static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
(unsigned long long)id->block_no,
(unsigned long long)b->block,
(unsigned long long)b->block,
- reftype_str[this_ref],
- reftype_str[acceptable_ref]);
+ reftypes[this_ref], reftypes[acceptable_ref]);
if (!(query( _("Okay to delete %s inode %lld (0x%llx)? "
"(y/n) "),
(inval ? _("invalidated") : ""),
@@ -511,7 +517,7 @@ static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
clear_dup_fxns.private = (void *) dh;
/* Clear the EAs for the inode first */
check_inode_eattr(ip, &clear_dup_fxns);
- /* If the dup wasn't only in the EA, clear the inode */
+ /* If the dup was in data or metadata, clear the dinode */
if (id->reftypecount[ref_as_data] ||
id->reftypecount[ref_as_meta])
check_metatree(ip, &clear_dup_fxns);
@@ -577,7 +583,12 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
ctype = ((struct gfs2_meta_header *)(bh->b_data))->mh_type;
brelse(bh);
+ /* If this is a dinode, any references to it (except in directory
+ entries) are invalid and should be deleted. */
if (be32_to_cpu(cmagic) == GFS2_MAGIC &&
+ be32_to_cpu(ctype) == GFS2_METATYPE_DI)
+ acceptable_ref = ref_is_inode;
+ else if (be32_to_cpu(cmagic) == GFS2_MAGIC &&
(be32_to_cpu(ctype) == GFS2_METATYPE_EA ||
be32_to_cpu(ctype) == GFS2_METATYPE_ED))
acceptable_ref = ref_as_ea;
@@ -689,6 +700,8 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
fsck_blockmap_set(ip, b->block,
_("reference-repaired leaf"),
gfs2_block_free);
+ } else if (id->reftypecount[ref_is_inode]) {
+ set_ip_blockmap(ip, 0); /* 0=do not add to dirtree */
} else if (id->reftypecount[ref_as_data]) {
fsck_blockmap_set(ip, b->block,
_("reference-repaired data"),
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 4075aec..69bf328 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -10,9 +10,12 @@
#include "libgfs2.h"
#include "fs_bits.h"
+#include "metawalk.h"
#include "util.h"
-const char *reftypes[3] = {"data", "metadata", "extended attribute"};
+const char *reftypes[ref_types + 1] = {"data", "metadata",
+ "extended attribute", "itself",
+ "unimportant"};
void big_file_comfort(struct gfs2_inode *ip, uint64_t blks_checked)
{
@@ -452,3 +455,69 @@ void *gfs2_bmap_destroy(struct gfs2_sbd *sdp, struct gfs2_bmap *il)
gfs2_special_free(&sdp->eattr_blocks);
return il;
}
+
+/* set_ip_blockmap - set the blockmap for a dinode
+ *
+ * instree: Set to 1 if directories should be inserted into the directory tree
+ * otherwise 0.
+ * returns: 0 if no error, -EINVAL if dinode has a bad mode, -EPERM on error
+ */
+int set_ip_blockmap(struct gfs2_inode *ip, int instree)
+{
+ uint64_t block = ip->i_bh->b_blocknr;
+ struct gfs2_sbd *sdp = ip->i_sbd;
+ uint32_t mode;
+
+ if (sdp->gfs1)
+ mode = gfs_to_gfs2_mode(ip->i_di.__pad1);
+ else
+ mode = ip->i_di.di_mode & S_IFMT;
+
+ switch (mode) {
+ case S_IFDIR:
+ if (fsck_blockmap_set(ip, block, _("directory"),
+ gfs2_inode_dir))
+ goto bad_dinode;
+ if (instree && !dirtree_insert(block))
+ goto bad_dinode;
+ break;
+ case S_IFREG:
+ if (fsck_blockmap_set(ip, block, _("file"), gfs2_inode_file))
+ goto bad_dinode;
+ break;
+ case S_IFLNK:
+ if (fsck_blockmap_set(ip, block, _("symlink"),
+ gfs2_inode_lnk))
+ goto bad_dinode;
+ break;
+ case S_IFBLK:
+ if (fsck_blockmap_set(ip, block, _("block device"),
+ gfs2_inode_device))
+ goto bad_dinode;
+ break;
+ case S_IFCHR:
+ if (fsck_blockmap_set(ip, block, _("character device"),
+ gfs2_inode_device))
+ goto bad_dinode;
+ break;
+ case S_IFIFO:
+ if (fsck_blockmap_set(ip, block, _("fifo"),
+ gfs2_inode_fifo))
+ goto bad_dinode;
+ break;
+ case S_IFSOCK:
+ if (fsck_blockmap_set(ip, block, _("socket"),
+ gfs2_inode_sock))
+ goto bad_dinode;
+ break;
+ default:
+ fsck_blockmap_set(ip, block, _("invalid mode"),
+ gfs2_inode_invalid);
+ return -EINVAL;
+ }
+ return 0;
+
+bad_dinode:
+ stack;
+ return -EPERM;
+}
diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h
index fd75212..6581cb1 100644
--- a/gfs2/fsck/util.h
+++ b/gfs2/fsck/util.h
@@ -21,7 +21,7 @@ extern struct inode_with_dups *find_dup_ref_inode(struct duptree *dt,
struct gfs2_inode *ip);
extern void dup_listent_delete(struct inode_with_dups *id);
-extern const char *reftypes[3];
+extern const char *reftypes[ref_types + 1];
static inline uint8_t block_type(uint64_t bblock)
{
@@ -170,4 +170,5 @@ extern struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size,
extern void *gfs2_bmap_destroy(struct gfs2_sbd *sdp, struct gfs2_bmap *il);
extern int gfs2_blockmap_set(struct gfs2_bmap *il, uint64_t block,
enum gfs2_mark_block mark);
+extern int set_ip_blockmap(struct gfs2_inode *ip, int instree);
#endif /* __UTIL_H__ */
12 years, 3 months
cluster: RHEL6 - fsck.gfs2: Add ability to check gfs1 file systems
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 94ada9a53b0c5bdf273c9801e2ffe1877356478d
Parent: 7a55740823bc98268dc7765eb99f365e42f4803b
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Thu Aug 11 14:51:08 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Jan 20 08:26:27 2012 -0600
fsck.gfs2: Add ability to check gfs1 file systems
This patch gives fsck.gfs2 the ability to check GFS1 file systems.
rhbz#675723
---
gfs2/fsck/fs_recovery.c | 37 ++++--
gfs2/fsck/fsck.h | 3 +
gfs2/fsck/initialize.c | 302 +++++++++++++++++++++++++++++++++++----------
gfs2/fsck/lost_n_found.c | 96 ++++++++++++---
gfs2/fsck/main.c | 14 ++-
gfs2/fsck/metawalk.c | 90 ++++++++++----
gfs2/fsck/pass1.c | 167 +++++++++++++++++++++-----
gfs2/fsck/pass1b.c | 5 +-
gfs2/fsck/pass2.c | 40 ++++---
gfs2/fsck/pass3.c | 39 +++++-
gfs2/fsck/pass4.c | 7 +
gfs2/fsck/pass5.c | 87 ++++++++++++-
gfs2/fsck/rgrepair.c | 20 +++-
gfs2/fsck/util.h | 111 ++++++++++++-----
gfs2/libgfs2/libgfs2.h | 3 +
gfs2/libgfs2/structures.c | 29 +++--
16 files changed, 836 insertions(+), 214 deletions(-)
diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c
index 8e29167..907e37f 100644
--- a/gfs2/fsck/fs_recovery.c
+++ b/gfs2/fsck/fs_recovery.c
@@ -629,7 +629,9 @@ int ji_update(struct gfs2_sbd *sdp)
{
struct gfs2_inode *jip, *ip = sdp->md.jiinode;
char journal_name[JOURNAL_NAME_SIZE];
- int i;
+ int i, error;
+ char buf[sizeof(struct gfs_jindex)];
+ struct gfs_jindex ji;
if (!ip) {
log_crit("Journal index inode not found.\n");
@@ -640,24 +642,41 @@ int ji_update(struct gfs2_sbd *sdp)
plus two for "." and "..". So we subtract the 2 and divide by 3.
If per_node is missing or damaged, we have to trust jindex has
the correct number of entries. */
- if (sdp->md.pinode) /* if per_node was read in properly */
+ if (sdp->gfs1)
+ sdp->md.journals = ip->i_di.di_size / sizeof(struct gfs_jindex);
+ else if (sdp->md.pinode) /* if per_node was read in properly */
sdp->md.journals = (sdp->md.pinode->i_di.di_entries - 2) / 3;
else
sdp->md.journals = ip->i_di.di_entries - 2;
if (!(sdp->md.journal = calloc(sdp->md.journals,
- sizeof(struct gfs2_inode *)))) {
+ sizeof(struct gfs2_inode *)))) {
log_err("Unable to allocate journal index\n");
return -1;
}
memset(journal_name, 0, sizeof(*journal_name));
for (i = 0; i < sdp->md.journals; i++) {
- /* FIXME check snprintf return code */
- snprintf(journal_name, JOURNAL_NAME_SIZE, "journal%u", i);
- gfs2_lookupi(sdp->md.jiinode, journal_name, strlen(journal_name),
- &jip);
- sdp->md.journal[i] = jip;
+ if (sdp->gfs1) {
+ error = gfs2_readi(ip,
+ buf, i * sizeof(struct gfs_jindex),
+ sizeof(struct gfs_jindex));
+ if (!error)
+ break;
+ if (error != sizeof(struct gfs_jindex)){
+ log_err("An error occurred while reading the"
+ " journal index file.\n");
+ return -1;
+ }
+ gfs_jindex_in(&ji, buf);
+ sdp->md.journal[i] = inode_read(sdp, ji.ji_addr);
+ } else {
+ /* FIXME check snprintf return code */
+ snprintf(journal_name, JOURNAL_NAME_SIZE,
+ "journal%u", i);
+ gfs2_lookupi(sdp->md.jiinode, journal_name,
+ strlen(journal_name), &jip);
+ sdp->md.journal[i] = jip;
+ }
}
return 0;
-
}
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index 0fed06b..e2640d8 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -113,6 +113,7 @@ extern void gfs2_dup_free(void);
extern int fsck_query(const char *format, ...)
__attribute__((format(printf,1,2)));
extern struct dir_info *dirtree_find(uint64_t block);
+extern void dup_listent_delete(struct inode_with_dups *id);
extern void dup_delete(struct duptree *b);
extern void dirtree_delete(struct dir_info *b);
@@ -135,4 +136,6 @@ extern struct osi_root inodetree;
extern int dups_found; /* How many duplicate references have we found? */
extern int dups_found_first; /* How many duplicates have we found the original
reference for? */
+extern struct gfs_sb *sbd1;
+
#endif /* _FSCK_H */
diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c
index d7586de..cee1f49 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -9,6 +9,7 @@
#include <unistd.h>
#include <libintl.h>
#include <errno.h>
+#include <time.h>
#define _(String) gettext(String)
@@ -191,12 +192,14 @@ static void check_rgrp_integrity(struct gfs2_sbd *sdp, struct rgrp_list *rgd,
int *fixit, int *this_rg_fixed,
int *this_rg_bad)
{
- uint32_t rg_free, rg_reclaimed;
+ uint32_t rg_free, rg_reclaimed, rg_unlinked;
int rgb, x, y, off, bytes_to_check, total_bytes_to_check, asked = 0;
unsigned int state;
+ struct gfs_rgrp *gfs1rg = (struct gfs_rgrp *)&rgd->rg;
- rg_free = rg_reclaimed = 0;
+ rg_free = rg_reclaimed = rg_unlinked = 0;
total_bytes_to_check = rgd->ri.ri_bitbytes;
+
*this_rg_fixed = *this_rg_bad = 0;
for (rgb = 0; rgb < rgd->ri.ri_length; rgb++){
@@ -244,8 +247,10 @@ static void check_rgrp_integrity(struct gfs2_sbd *sdp, struct rgrp_list *rgd,
if (query("%s", msg))
*fixit = 1;
}
- if (!(*fixit))
+ if (!(*fixit)) {
+ rg_unlinked++;
continue;
+ }
*byte &= ~(GFS2_BIT_MASK <<
(GFS2_BIT_SIZE * y));
bmodified(rgd->bh[rgb]);
@@ -267,7 +272,29 @@ static void check_rgrp_integrity(struct gfs2_sbd *sdp, struct rgrp_list *rgd,
rg_reclaimed);
if (query( _("Fix the rgrp free blocks count? (y/n)"))) {
rgd->rg.rg_free = rg_free;
- gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
+ if (sdp->gfs1)
+ gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg,
+ rgd->bh[0]);
+ else
+ gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
+ *this_rg_fixed = 1;
+ log_err( _("The rgrp was fixed.\n"));
+ } else
+ log_err( _("The rgrp was not fixed.\n"));
+ }
+ if (sdp->gfs1 && gfs1rg->rg_freemeta != rg_unlinked) {
+ *this_rg_bad = 1;
+ log_err( _("Error: resource group %lld (0x%llx): "
+ "free meta (%d) does not match bitmap (%d)\n"),
+ (unsigned long long)rgd->ri.ri_addr,
+ (unsigned long long)rgd->ri.ri_addr,
+ gfs1rg->rg_freemeta, rg_unlinked);
+ if (rg_reclaimed)
+ log_err( _("(%d blocks were reclaimed)\n"),
+ rg_reclaimed);
+ if (query( _("Fix the rgrp free meta blocks count? (y/n)"))) {
+ gfs1rg->rg_freemeta = rg_unlinked;
+ gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bh[0]);
*this_rg_fixed = 1;
log_err( _("The rgrp was fixed.\n"));
} else
@@ -455,7 +482,7 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
uint64_t inumbuf;
char *buf;
struct gfs2_statfs_change sc;
- int rgcount, sane = 1;
+ int rgcount, sane = 1, err = 0;
enum rgindex_trust_level trust_lvl;
uint64_t addl_mem_needed;
const char *level_desc[] = {
@@ -482,7 +509,10 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
/* Get root dinode */
sdp->md.rooti = inode_read(sdp, sdp->sd_sb.sb_root_dir.no_addr);
- gfs2_lookupi(sdp->master_dir, "rindex", 6, &sdp->md.riinode);
+ if (sdp->gfs1)
+ sdp->md.riinode = inode_read(sdp, sbd1->sb_rindex_di.no_addr);
+ else
+ gfs2_lookupi(sdp->master_dir, "rindex", 6, &sdp->md.riinode);
if (!sdp->md.riinode) {
if (query( _("The gfs2 system rindex inode is missing. "
"Okay to rebuild it? (y/n) ")))
@@ -495,7 +525,10 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
/* rgrepair requires the journals be read in in order to distinguish
"real" rgrps from rgrps that are just copies left in journals. */
- gfs2_lookupi(sdp->master_dir, "jindex", 6, &sdp->md.jiinode);
+ if (sdp->gfs1)
+ sdp->md.jiinode = inode_read(sdp, sbd1->sb_jindex_di.no_addr);
+ else
+ gfs2_lookupi(sdp->master_dir, "jindex", 6, &sdp->md.jiinode);
if (!sdp->md.jiinode) {
if (query( _("The gfs2 system jindex inode is missing. "
"Okay to rebuild it? (y/n) ")))
@@ -513,7 +546,7 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
*******************************************************************/
log_warn( _("Validating Resource Group index.\n"));
for (trust_lvl = blind_faith; trust_lvl <= indignation; trust_lvl++) {
- int ret;
+ int ret = 0;
log_warn( _("Level %d rgrp check: %s.\n"), trust_lvl + 1,
level_desc[trust_lvl]);
@@ -547,27 +580,60 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
/*******************************************************************
***************** Initialize more system inodes *****************
*******************************************************************/
- /* Look for "inum" entry in master dinode */
- gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
- if (!sdp->md.inum) {
- if (query( _("The gfs2 system inum inode is missing. "
- "Okay to rebuild it? (y/n) ")))
- build_inum(sdp);
+ if (!sdp->gfs1) {
+ /* Look for "inum" entry in master dinode */
+ gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
+ if (!sdp->md.inum) {
+ if (!query( _("The gfs2 system inum inode is missing. "
+ "Okay to rebuild it? (y/n) "))) {
+ log_err( _("fsck.gfs2 cannot continue without "
+ "a valid inum file; aborting.\n"));
+ goto fail;
+ }
+ err = build_inum(sdp);
+ if (err) {
+ log_crit(_("Error rebuilding inum inode: %s\n"),
+ strerror(err));
+ exit(-1);
+ }
+ gfs2_lookupi(sdp->master_dir, "inum", 4,
+ &sdp->md.inum);
+ if (!sdp->md.inum) {
+ log_crit("System inum inode was not rebuilt. "
+ "Aborting.\n");
+ goto fail;
+ }
+ }
+ /* Read inum entry into buffer */
+ gfs2_readi(sdp->md.inum, &inumbuf, 0,
+ sdp->md.inum->i_di.di_size);
+ /* call gfs2_inum_range_in() to retrieve range */
+ sdp->md.next_inum = be64_to_cpu(inumbuf);
}
- /* Read inum entry into buffer */
- gfs2_readi(sdp->md.inum, &inumbuf, 0, sdp->md.inum->i_di.di_size);
- /* call gfs2_inum_range_in() to retrieve range */
- sdp->md.next_inum = be64_to_cpu(inumbuf);
- gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
- if (!sdp->md.statfs) {
- if (query( _("The gfs2 system statfs inode is missing. "
- "Okay to rebuild it? (y/n) ")))
- build_statfs(sdp);
- else {
- log_err( _("fsck.gfs2 cannot continue without a "
- "valid statfs file; aborting.\n"));
- return FSCK_ERROR;
+ if (sdp->gfs1)
+ sdp->md.statfs = inode_read(sdp, sbd1->sb_license_di.no_addr);
+ else
+ gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
+ if (!sdp->gfs1 && !sdp->md.statfs) {
+ if (!query( _("The gfs2 system statfs inode is missing. "
+ "Okay to rebuild it? (y/n) "))) {
+ log_err( _("fsck.gfs2 cannot continue without a valid "
+ "statfs file; aborting.\n"));
+ goto fail;
+ }
+ err = build_statfs(sdp);
+ if (err) {
+ log_crit(_("Error rebuilding statfs inode: %s\n"),
+ strerror(err));
+ exit(-1);
+ }
+ gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
+ if (!sdp->md.statfs) {
+ log_err( _("Rebuild of statfs system file failed."));
+ log_err( _("fsck.gfs2 cannot continue without "
+ "a valid statfs file; aborting.\n"));
+ goto fail;
}
}
buf = malloc(sdp->md.statfs->i_di.di_size);
@@ -577,16 +643,36 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
gfs2_statfs_change_in(&sc, buf);
free(buf);
- gfs2_lookupi(sdp->master_dir, "quota", 5, &sdp->md.qinode);
- if (!sdp->md.qinode) {
- if (query( _("The gfs2 system quota inode is missing. "
- "Okay to rebuild it? (y/n) ")))
- build_quota(sdp);
+ if (sdp->gfs1)
+ sdp->md.qinode = inode_read(sdp, sbd1->sb_quota_di.no_addr);
+ else
+ gfs2_lookupi(sdp->master_dir, "quota", 5, &sdp->md.qinode);
+ if (!sdp->gfs1 && !sdp->md.qinode) {
+ if (!query( _("The gfs2 system quota inode is missing. "
+ "Okay to rebuild it? (y/n) "))) {
+ log_crit("System quota inode was not "
+ "rebuilt. Aborting.\n");
+ goto fail;
+ }
+ err = build_quota(sdp);
+ if (err) {
+ log_crit(_("Error rebuilding quota inode: %s\n"),
+ strerror(err));
+ exit(-1);
+ }
+ gfs2_lookupi(sdp->master_dir, "quota", 5, &sdp->md.qinode);
+ if (!sdp->md.qinode) {
+ log_crit("Unable to rebuild system quota file "
+ "inode. Aborting.\n");
+ goto fail;
+ }
}
/* Try to lookup the per_node inode. If it was missing, it is now
safe to rebuild it. */
- lookup_per_node(sdp, 1);
+ if (!sdp->gfs1)
+ lookup_per_node(sdp, 1);
+
/*******************************************************************
******* Now, set boundary fields in the super block *************
*******************************************************************/
@@ -699,13 +785,15 @@ static void peruse_system_dinode(struct gfs2_sbd *sdp, struct gfs2_dinode *di,
return;
}
ip = inode_read(sdp, di->di_num.no_addr);
- if (di->di_num.no_formal_ino == 3) {
+ if ((!sdp->gfs1 && di->di_num.no_formal_ino == 3) ||
+ (sdp->gfs1 && (di->di_flags & GFS2_DIF_JDATA) &&
+ (di->di_size % sizeof(struct gfs_jindex) == 0))) {
if (fix_md.jiinode || is_journal_copy(ip, bh))
return;
log_warn(_("Found system jindex file at: 0x%llx\n"),
di->di_num.no_addr);
fix_md.jiinode = ip;
- } else if (S_ISDIR(di->di_mode)) {
+ } else if (!sdp->gfs1 && is_dir(di, sdp->gfs1)) {
/* Check for a jindex dir entry. Only one system dir has a
jindex: master */
gfs2_lookupi(ip, "jindex", 6, &child_ip);
@@ -741,7 +829,7 @@ static void peruse_system_dinode(struct gfs2_sbd *sdp, struct gfs2_dinode *di,
log_debug(_("Unknown system directory at block 0x%llx\n"),
di->di_num.no_addr);
inode_put(&ip);
- } else if (di->di_size == 8) {
+ } else if (!sdp->gfs1 && di->di_size == 8) {
if (fix_md.inum || is_journal_copy(ip, bh))
return;
fix_md.inum = ip;
@@ -783,7 +871,7 @@ static void peruse_user_dinode(struct gfs2_sbd *sdp, struct gfs2_dinode *di,
if (sdp->sd_sb.sb_root_dir.no_addr) /* if we know the root dinode */
return; /* we don't need to find the root */
- if (!S_ISDIR(di->di_mode)) /* if this isn't a directory */
+ if (!is_dir(di, sdp->gfs1)) /* if this isn't a directory */
return; /* it can't lead us to the root anyway */
if (di->di_num.no_formal_ino == 1) {
@@ -918,7 +1006,6 @@ static int peruse_metadata(struct gfs2_sbd *sdp, uint64_t startblock)
uint64_t blk, max_rg_size;
struct gfs2_buffer_head *bh;
struct gfs2_dinode di;
- int found_gfs2_dinodes = 0, possible_gfs1_dinodes = 0;
max_rg_size = 2147483648ull / sdp->bsize;
/* Max RG size is 2GB. 2G / bsize. */
@@ -929,18 +1016,6 @@ static int peruse_metadata(struct gfs2_sbd *sdp, uint64_t startblock)
continue;
}
gfs2_dinode_in(&di, bh);
- if (!found_gfs2_dinodes &&
- di.di_num.no_addr == di.di_num.no_formal_ino) {
- possible_gfs1_dinodes++;
- if (possible_gfs1_dinodes > 5) {
- log_err(_("Found several gfs (version 1) "
- "dinodes; aborting.\n"));
- brelse(bh);
- return -1;
- }
- } else {
- found_gfs2_dinodes++;
- }
if (di.di_flags & GFS2_DIF_SYSTEM)
peruse_system_dinode(sdp, &di, bh);
else
@@ -1067,6 +1142,8 @@ static int sb_repair(struct gfs2_sbd *sdp)
*/
static int fill_super_block(struct gfs2_sbd *sdp)
{
+ int ret;
+
sync();
/********************************************************************
@@ -1091,19 +1168,109 @@ static int fill_super_block(struct gfs2_sbd *sdp)
log_crit(_("Bad constants (1)\n"));
exit(-1);
}
- if (read_sb(sdp, 0) < 0) {
- /* First, check for a gfs1 (not gfs2) file system */
- if (sdp->sd_sb.sb_header.mh_magic == GFS2_MAGIC &&
- sdp->sd_sb.sb_header.mh_type == GFS2_METATYPE_SB)
- return -1; /* This is gfs1, don't try to repair */
- /* It's not a "sane" gfs1 fs so try to repair it */
+ ret = read_sb(sdp, 1);
+ if (ret < 0) {
if (sb_repair(sdp) != 0)
return -1; /* unrepairable, so exit */
/* Now that we've tried to repair it, re-read it. */
- if (read_sb(sdp, 0) < 0)
+ ret = read_sb(sdp, 1);
+ if (ret < 0)
return -1;
}
+ if (sdp->gfs1)
+ sbd1 = (struct gfs_sb *)&sdp->sd_sb;
+ return 0;
+}
+
+static void gfs_log_header_out(struct gfs_log_header *head, char *buf)
+{
+ struct gfs_log_header *str = (struct gfs_log_header *) buf;
+
+ str->lh_header.mh_magic = cpu_to_be32(head->lh_header.mh_magic);
+ str->lh_header.mh_type = cpu_to_be32(head->lh_header.mh_type);
+ str->lh_header.mh_format = cpu_to_be32(head->lh_header.mh_format);
+ str->lh_header.__pad0 = cpu_to_be32(head->lh_header.__pad0);
+
+ str->lh_flags = cpu_to_be32(head->lh_flags);
+ str->lh_pad = cpu_to_be32(head->lh_pad);
+ str->lh_first = cpu_to_be64(head->lh_first);
+ str->lh_sequence = cpu_to_be64(head->lh_sequence);
+ str->lh_tail = cpu_to_be64(head->lh_tail);
+ str->lh_last_dump = cpu_to_be64(head->lh_last_dump);
+}
+
+/*
+ * reconstruct_single_journal - write a fresh GFS1 journal
+ * @sdp: superblock
+ * @jnum: journal number
+ *
+ * This function will write a fresh journal over the top of
+ * the previous journal. All journal information is lost. This
+ * process is basically stolen from write_journals() in the mkfs code.
+ *
+ * Returns: -1 on error, 0 otherwise
+ */
+static int reconstruct_single_journal(struct gfs2_sbd *sdp, int jnum,
+ uint32_t ji_nsegment)
+{
+ struct gfs_log_header lh;
+ uint32_t seg, sequence;
+ struct gfs2_buffer_head *bh;
+
+ srandom(time(NULL));
+ sequence = ji_nsegment / (RAND_MAX + 1.0) * random();
+
+ log_info("Clearing journal %d\n", jnum);
+
+ for (seg = 0; seg < ji_nsegment; seg++){
+ bh = bget(sdp, lh.lh_first * sdp->bsize);
+ memset(bh->b_data, 0, sdp->bsize);
+ memset(&lh, 0, sizeof(struct gfs_log_header));
+
+ lh.lh_header.mh_magic = GFS2_MAGIC;
+ lh.lh_header.mh_type = GFS2_METATYPE_LH;
+ lh.lh_header.mh_format = GFS2_FORMAT_LH;
+ lh.lh_header.__pad0 = 0x101674; /* mh_generation */
+ lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT;
+ lh.lh_first = sdp->md.journal[jnum]->i_di.di_num.no_addr +
+ (seg * sbd1->sb_seg_size);
+ lh.lh_sequence = sequence;
+
+ gfs_log_header_out(&lh, bh->b_data);
+ gfs_log_header_out(&lh, bh->b_data + GFS2_BASIC_BLOCK -
+ sizeof(struct gfs_log_header));
+ brelse(bh);
+
+ if (++sequence == ji_nsegment)
+ sequence = 0;
+ }
+ return 0;
+}
+
+/*
+ * reconstruct_journals - write fresh journals for GFS1 only
+ * sdp: the super block
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int reconstruct_journals(struct gfs2_sbd *sdp)
+{
+ int i;
+ struct gfs_jindex ji;
+ char buf[sizeof(struct gfs_jindex)];
+
+ log_err("Clearing GFS journals (this may take a while)");
+ for (i = 0; i < sdp->md.journals; i++) {
+ gfs2_readi(sdp->md.jiinode, buf, i * sizeof(struct gfs_jindex),
+ sizeof(struct gfs_jindex));
+ gfs_jindex_in(&ji, buf);
+ if ((i % 2) == 0)
+ log_err(".");
+ if (reconstruct_single_journal(sdp, i, ji.ji_nsegment))
+ return -1;
+ }
+ log_err("\nJournals cleared.\n");
return 0;
}
@@ -1175,10 +1342,15 @@ int initialize(struct gfs2_sbd *sdp, int force_check, int preen,
}
/* Get master dinode */
- sdp->master_dir = inode_read(sdp, sdp->sd_sb.sb_master_dir.no_addr);
- if (sdp->master_dir->i_di.di_header.mh_magic != GFS2_MAGIC ||
- sdp->master_dir->i_di.di_header.mh_type != GFS2_METATYPE_DI ||
- !sdp->master_dir->i_di.di_size) {
+ if (sdp->gfs1)
+ sdp->master_dir = NULL;
+ else
+ sdp->master_dir = inode_read(sdp,
+ sdp->sd_sb.sb_master_dir.no_addr);
+ if (!sdp->gfs1 &&
+ (sdp->master_dir->i_di.di_header.mh_magic != GFS2_MAGIC ||
+ sdp->master_dir->i_di.di_header.mh_type != GFS2_METATYPE_DI ||
+ !sdp->master_dir->i_di.di_size)) {
inode_put(&sdp->master_dir);
rebuild_master(sdp);
sdp->master_dir = inode_read(sdp,
@@ -1188,11 +1360,15 @@ int initialize(struct gfs2_sbd *sdp, int force_check, int preen,
/* Look up the "per_node" inode. If there are journals missing, we
need to figure out what's missing from per_node. And we need all
our journals to be there before we can replay them. */
- lookup_per_node(sdp, 0);
+ if (!sdp->gfs1)
+ lookup_per_node(sdp, 0);
/* verify various things */
- if (replay_journals(sdp, preen, force_check, &clean_journals)) {
+ if (sdp->gfs1) {
+ if (reconstruct_journals(sdp))
+ return FSCK_ERROR;
+ } else if (replay_journals(sdp, preen, force_check, &clean_journals)) {
if (!opts.no && preen_is_safe(sdp, preen, force_check))
block_mounters(sdp, 0);
stack;
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index 0de4f8e..af4189f 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -28,7 +28,7 @@ static void add_dotdot(struct gfs2_inode *ip)
/* If there's a pre-existing .. directory entry, we have to
back out the links. */
di = dirtree_find(ip->i_di.di_num.no_addr);
- if (di && !valid_block(sdp, di->dotdot_parent) == 0) {
+ if (di && valid_block(sdp, di->dotdot_parent)) {
struct gfs2_inode *dip;
log_debug(_("Directory %lld (0x%llx) already had a "
@@ -75,7 +75,47 @@ static void add_dotdot(struct gfs2_inode *ip)
log_warn( _("add_inode_to_lf: Unable to remove "
"\"..\" directory entry.\n"));
- dir_add(ip, "..", 2, &(lf_dip->i_di.di_num), DT_DIR);
+ dir_add(ip, "..", 2, &(lf_dip->i_di.di_num),
+ (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
+}
+
+static uint64_t find_free_blk(struct gfs2_sbd *sdp)
+{
+ osi_list_t *tmp, *head;
+ struct rgrp_list *rl = NULL;
+ struct gfs2_rindex *ri;
+ struct gfs2_rgrp *rg;
+ unsigned int block, bn = 0, x = 0, y = 0;
+ unsigned int state;
+ struct gfs2_buffer_head *bh;
+
+ memset(&rg, 0, sizeof(rg));
+ for (head = &sdp->rglist, tmp = head->next; tmp != head;
+ tmp = tmp->next) {
+ rl = osi_list_entry(tmp, struct rgrp_list, list);
+ if (rl->rg.rg_free)
+ break;
+ }
+
+ if (tmp == head)
+ return 0;
+
+ ri = &rl->ri;
+ rg = &rl->rg;
+
+ for (block = 0; block < ri->ri_length; block++) {
+ bh = rl->bh[block];
+ x = (block) ? sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_rgrp);
+
+ for (; x < sdp->bsize; x++)
+ for (y = 0; y < GFS2_NBBY; y++) {
+ state = (bh->b_data[x] >> (GFS2_BIT_SIZE * y)) & 0x03;
+ if (state == GFS2_BLKST_FREE)
+ return ri->ri_data0 + bn;
+ bn++;
+ }
+ }
+ return 0;
}
/* add_inode_to_lf - Add dir entry to lost+found for the inode
@@ -93,16 +133,33 @@ int add_inode_to_lf(struct gfs2_inode *ip){
uint64_t lf_blocks;
struct gfs2_sbd *sdp = ip->i_sbd;
struct dir_info *di;
+ uint32_t mode;
if (!lf_dip) {
uint8_t q;
log_info( _("Locating/Creating lost+found directory\n"));
- lf_dip = createi(sdp->md.rooti, "lost+found",
- S_IFDIR | 0700, 0);
+ /* if this is gfs1, we have to trick createi into using
+ no_formal_ino = no_addr, so we set next_inum to the
+ free block we're about to allocate. */
+ if (sdp->gfs1)
+ sdp->md.next_inum = find_free_blk(sdp);
+ mode = (sdp->gfs1 ? DT2IF(GFS_FILE_DIR) : S_IFDIR) | 0700;
+ if (sdp->gfs1)
+ lf_dip = gfs_createi(sdp->md.rooti, "lost+found",
+ mode, 0);
+ else
+ lf_dip = createi(sdp->md.rooti, "lost+found",
+ S_IFDIR | 0700, 0);
+ if (lf_dip == NULL) {
+ log_crit(_("Error creating lost+found: %s\n"),
+ strerror(errno));
+ exit(FSCK_ERROR);
+ }
+
/* createi will have incremented the di_nlink link count for
- the root directory. We must increment the nlink value
+ the root directory. We must set the nlink value
in the hash table to keep them in sync so that pass4 can
detect and fix any descrepancies. */
set_di_nlink(sdp->md.rooti);
@@ -129,7 +186,9 @@ int add_inode_to_lf(struct gfs2_inode *ip){
/* lost+found link for '..' back to root */
incr_link_count(lf_dip->i_di.di_num.no_addr,
sdp->md.rooti->i_di.di_num.no_addr,
- "\"..\"");
+ "\"..\"");
+ if (sdp->gfs1)
+ lf_dip->i_di.__pad1 = GFS_FILE_DIR;
}
log_info( _("lost+found directory is dinode %lld (0x%llx)\n"),
(unsigned long long)lf_dip->i_di.di_num.no_addr,
@@ -147,47 +206,52 @@ int add_inode_to_lf(struct gfs2_inode *ip){
}
lf_blocks = lf_dip->i_di.di_blocks;
- switch(ip->i_di.di_mode & S_IFMT){
+ if (sdp->gfs1)
+ mode = gfs_to_gfs2_mode(ip->i_di.__pad1);
+ else
+ mode = ip->i_di.di_mode & S_IFMT;
+
+ switch (mode) {
case S_IFDIR:
add_dotdot(ip);
sprintf(tmp_name, "lost_dir_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_DIR;
+ inode_type = (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR);
break;
case S_IFREG:
sprintf(tmp_name, "lost_file_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_REG;
+ inode_type = (sdp->gfs1 ? GFS_FILE_REG : DT_REG);
break;
case S_IFLNK:
sprintf(tmp_name, "lost_link_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_LNK;
+ inode_type = (sdp->gfs1 ? GFS_FILE_LNK : DT_LNK);
break;
case S_IFBLK:
sprintf(tmp_name, "lost_blkdev_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_BLK;
+ inode_type = (sdp->gfs1 ? GFS_FILE_BLK : DT_BLK);
break;
case S_IFCHR:
sprintf(tmp_name, "lost_chrdev_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_CHR;
+ inode_type = (sdp->gfs1 ? GFS_FILE_CHR : DT_CHR);
break;
case S_IFIFO:
sprintf(tmp_name, "lost_fifo_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_FIFO;
+ inode_type = (sdp->gfs1 ? GFS_FILE_FIFO : DT_FIFO);
break;
case S_IFSOCK:
sprintf(tmp_name, "lost_socket_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_SOCK;
+ inode_type = (sdp->gfs1 ? GFS_FILE_SOCK : DT_SOCK);
break;
default:
sprintf(tmp_name, "lost_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_REG;
+ inode_type = (sdp->gfs1 ? GFS_FILE_REG : DT_REG);
break;
}
@@ -202,7 +266,7 @@ int add_inode_to_lf(struct gfs2_inode *ip){
incr_link_count(ip->i_di.di_num.no_addr, lf_dip->i_di.di_num.no_addr,
_("from lost+found"));
/* If it's a directory, lost+found is back-linked to it via .. */
- if (S_ISDIR(ip->i_di.di_mode))
+ if (is_dir(&ip->i_di, sdp->gfs1))
incr_link_count(lf_dip->i_di.di_num.no_addr,
ip->i_di.di_mode, _("to lost+found"));
diff --git a/gfs2/fsck/main.c b/gfs2/fsck/main.c
index 5dae096..75ccc11 100644
--- a/gfs2/fsck/main.c
+++ b/gfs2/fsck/main.c
@@ -33,6 +33,7 @@ struct osi_root dup_blocks = (struct osi_root) { NULL, };
struct osi_root dirtree = (struct osi_root) { NULL, };
struct osi_root inodetree = (struct osi_root) { NULL, };
int dups_found = 0, dups_found_first = 0;
+struct gfs_sb *sbd1 = NULL;
/* This function is for libgfs2's sake. */
void print_it(const char *label, const char *fmt, const char *fmt2, ...)
@@ -153,6 +154,10 @@ static void check_statfs(struct gfs2_sbd *sdp)
char buf[sizeof(struct gfs2_statfs_change)];
int count;
+ if (sdp->gfs1 && !sdp->md.statfs->i_di.di_size) {
+ log_info("This GFS1 file system is not using fast_statfs.\n");
+ return;
+ }
/* Read the current statfs values */
count = gfs2_readi(sdp->md.statfs, buf, 0,
sdp->md.statfs->i_di.di_size);
@@ -338,16 +343,19 @@ int main(int argc, char **argv)
check_statfs(sdp);
/* Free up our system inodes */
- inode_put(&sdp->md.inum);
+ if (!sdp->gfs1)
+ inode_put(&sdp->md.inum);
inode_put(&sdp->md.statfs);
for (j = 0; j < sdp->md.journals; j++)
inode_put(&sdp->md.journal[j]);
inode_put(&sdp->md.jiinode);
inode_put(&sdp->md.riinode);
inode_put(&sdp->md.qinode);
- inode_put(&sdp->md.pinode);
+ if (!sdp->gfs1)
+ inode_put(&sdp->md.pinode);
inode_put(&sdp->md.rooti);
- inode_put(&sdp->master_dir);
+ if (!sdp->gfs1)
+ inode_put(&sdp->master_dir);
if (lf_dip)
inode_put(&lf_dip);
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index b25b40d..2ddf7dd 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -40,17 +40,19 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk,
(unsigned long long)blk, (unsigned long long)blk);
return -1;
}
- new_bitmap_state = blockmap_to_bitmap(new_blockmap_state);
+ new_bitmap_state = blockmap_to_bitmap(new_blockmap_state, sdp->gfs1);
if (old_bitmap_state != new_bitmap_state) {
- const char *allocdesc[] = {"free space", "data", "unlinked",
- "inode", "reserved"};
+ const char *allocdesc[2][5] = { /* gfs2 descriptions */
+ {"free", "data", "unlinked", "inode", "reserved"},
+ /* gfs1 descriptions: */
+ {"free", "data", "free meta", "metadata", "reserved"}};
/* 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[new_bitmap_state],
- allocdesc[old_bitmap_state]);
+ allocdesc[sdp->gfs1][old_bitmap_state],
+ allocdesc[sdp->gfs1][new_bitmap_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
@@ -75,10 +77,18 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk,
inodetree_delete(ii);
}
rgd->rg.rg_free++;
- gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
+ if (sdp->gfs1)
+ gfs_rgrp_out((struct gfs_rgrp *)
+ &rgd->rg, rgd->bh[0]);
+ else
+ gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
} else if (old_bitmap_state == GFS2_BLKST_FREE) {
rgd->rg.rg_free--;
- gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
+ if (sdp->gfs1)
+ gfs_rgrp_out((struct gfs_rgrp *)
+ &rgd->rg, rgd->bh[0]);
+ else
+ gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
}
log_err( _("The bitmap was fixed.\n"));
} else {
@@ -168,9 +178,28 @@ struct duptree *dupfind(uint64_t block)
struct gfs2_inode *fsck_system_inode(struct gfs2_sbd *sdp, uint64_t block)
{
+ int j;
+
if (lf_dip && lf_dip->i_di.di_num.no_addr == block)
return lf_dip;
- return is_system_inode(sdp, block);
+ if (!sdp->gfs1)
+ return is_system_inode(sdp, block);
+
+ if (sdp->md.statfs && block == sdp->md.statfs->i_di.di_num.no_addr)
+ return sdp->md.statfs;
+ if (sdp->md.jiinode && block == sdp->md.jiinode->i_di.di_num.no_addr)
+ return sdp->md.jiinode;
+ if (sdp->md.riinode && block == sdp->md.riinode->i_di.di_num.no_addr)
+ return sdp->md.riinode;
+ if (sdp->md.qinode && block == sdp->md.qinode->i_di.di_num.no_addr)
+ return sdp->md.qinode;
+ if (sdp->md.rooti && block == sdp->md.rooti->i_di.di_num.no_addr)
+ return sdp->md.rooti;
+ for (j = 0; j < sdp->md.journals; j++)
+ if (sdp->md.journal && sdp->md.journal[j] &&
+ block == sdp->md.journal[j]->i_di.di_num.no_addr)
+ return sdp->md.journal[j];
+ return NULL;
}
/* fsck_load_inode - same as gfs2_load_inode() in libgfs2 but system inodes
@@ -182,6 +211,8 @@ struct gfs2_inode *fsck_load_inode(struct gfs2_sbd *sdp, uint64_t block)
ip = fsck_system_inode(sdp, block);
if (ip)
return ip;
+ if (sdp->gfs1)
+ return gfs_inode_read(sdp, block);
return inode_read(sdp, block);
}
@@ -196,6 +227,8 @@ struct gfs2_inode *fsck_inode_get(struct gfs2_sbd *sdp,
if (sysip)
return sysip;
+ if (sdp->gfs1)
+ return gfs_inode_get(sdp, bh);
return inode_get(sdp, bh);
}
@@ -432,12 +465,13 @@ static int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
return 0;
}
-/* Process a bad leaf pointer and ask to repair the first time. */
-/* The repair process involves extending the previous leaf's entries */
-/* so that they replace the bad ones. We have to hack up the old */
-/* leaf a bit, but it's better than deleting the whole directory, */
-/* which is what used to happen before. */
-static int warn_and_patch(struct gfs2_inode *ip, uint64_t *leaf_no,
+/* warn_and_patch - Warn the user of an error and ask permission to fix it
+ * Process a bad leaf pointer and ask to repair the first time.
+ * The repair process involves extending the previous leaf's entries
+ * so that they replace the bad ones. We have to hack up the old
+ * leaf a bit, but it's better than deleting the whole directory,
+ * which is what used to happen before. */
+static int warn_and_patch(struct gfs2_inode *ip, uint64_t *leaf_no,
uint64_t *bad_leaf, uint64_t old_leaf,
uint64_t first_ok_leaf, int pindex, const char *msg)
{
@@ -539,7 +573,7 @@ static int check_leaf(struct gfs2_inode *ip, int lindex,
goto out_copy_old_leaf;
}
- if (pass->check_dentry && S_ISDIR(ip->i_di.di_mode)) {
+ if (pass->check_dentry && is_dir(&ip->i_di, sdp->gfs1)) {
error = check_entries(ip, lbh, DIR_EXHASH, &count, pass);
if (skip_this_pass || fsck_abort)
@@ -1072,7 +1106,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
because it checks everything through the hash table using
"depth" field calculations. However, we still have to check the
indirect blocks, even if the height == 1. */
- if (S_ISDIR(ip->i_di.di_mode))
+ if (is_dir(&ip->i_di, ip->i_sbd->gfs1))
height++;
/* if (<there are no indirect blocks to check>) */
@@ -1080,12 +1114,15 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
return 0;
for (h = 1; h < height; h++) {
if (h > 1) {
- if (S_ISDIR(ip->i_di.di_mode) &&
+ if (is_dir(&ip->i_di, ip->i_sbd->gfs1) &&
h == ip->i_di.di_height + 1)
iblk_type = GFS2_METATYPE_JD;
else
iblk_type = GFS2_METATYPE_IN;
- head_size = sizeof(struct gfs2_meta_header);
+ if (ip->i_sbd->gfs1)
+ head_size = sizeof(struct gfs_indirect);
+ else
+ head_size = sizeof(struct gfs2_meta_header);
} else {
iblk_type = GFS2_METATYPE_DI;
head_size = sizeof(struct gfs2_dinode);
@@ -1176,7 +1213,7 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
if (skip_this_pass || fsck_abort)
return error;
block = be64_to_cpu(*ptr);
- /* It's important that we don't call !valid_block and
+ /* 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
pass1. Therefore the individual check_data functions
@@ -1207,7 +1244,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
uint64_t blks_checked = 0;
int error, rc;
- if (!height && !S_ISDIR(ip->i_di.di_mode))
+ if (!height && !is_dir(&ip->i_di, ip->i_sbd->gfs1))
return 0;
for (i = 0; i < GFS2_MAX_META_HEIGHT; i++)
@@ -1223,7 +1260,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
/* For directories, we've already checked the "data" blocks which
* comprise the directory hash table, so we perform the directory
* checks and exit. */
- if (S_ISDIR(ip->i_di.di_mode)) {
+ if (is_dir(&ip->i_di, ip->i_sbd->gfs1)) {
free_metalist(ip, &metalist[0]);
if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH))
return 0;
@@ -1266,7 +1303,10 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
brelse(bh);
continue;
}
- head_size = sizeof(struct gfs2_meta_header);
+ if (ip->i_sbd->gfs1)
+ head_size = sizeof(struct gfs_indirect);
+ else
+ head_size = sizeof(struct gfs2_meta_header);
} else {
/* if this isn't really a dinode, skip it */
if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
@@ -1437,7 +1477,7 @@ static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
after the bitmap has been set but before the blockmap has. */
*bh = bread(ip->i_sbd, block);
q = block_type(block);
- if (blockmap_to_bitmap(q) == GFS2_BLKST_FREE) { /* If not marked yet */
+ if (blockmap_to_bitmap(q, ip->i_sbd->gfs1) == GFS2_BLKST_FREE) {
log_debug(_("%s reference to new metadata block "
"%lld (0x%llx) is now marked as indirect.\n"),
desc, (unsigned long long)block,
@@ -1456,7 +1496,7 @@ static int alloc_data(struct gfs2_inode *ip, uint64_t block, void *private)
/* We can't check the bitmap here because this function is called
after the bitmap has been set but before the blockmap has. */
q = block_type(block);
- if (blockmap_to_bitmap(q) == GFS2_BLKST_FREE) { /* If not marked yet */
+ if (blockmap_to_bitmap(q, ip->i_sbd->gfs1) == GFS2_BLKST_FREE) {
log_debug(_("%s reference to new data block "
"%lld (0x%llx) is now marked as data.\n"),
desc, (unsigned long long)block,
@@ -1474,7 +1514,7 @@ static int alloc_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
/* We can't check the bitmap here because this function is called
after the bitmap has been set but before the blockmap has. */
q = block_type(block);
- if (blockmap_to_bitmap(q) == GFS2_BLKST_FREE) /* If not marked yet */
+ if (blockmap_to_bitmap(q, ip->i_sbd->gfs1) == GFS2_BLKST_FREE)
fsck_blockmap_set(ip, block, _("newly allocated leaf"),
gfs2_leaf_blk);
return 0;
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index c0b7420..876078e 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -26,6 +26,8 @@
#include "link.h"
#include "metawalk.h"
+struct special_blocks gfs1_rindex_blks;
+
struct block_count {
uint64_t indir_count;
uint64_t data_count;
@@ -174,9 +176,10 @@ static int resuscitate_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
(unsigned long long)ip->i_di.di_num.no_addr);
return 0;
}
- if (block == sdp->md.jiinode->i_di.di_num.no_addr ||
- block == sdp->md.pinode->i_di.di_num.no_addr ||
- block == sdp->master_dir->i_di.di_num.no_addr)
+ if (block == sdp->md.jiinode->i_di.di_num.no_addr)
+ dinode_type = gfs2_inode_dir;
+ else if (!sdp->gfs1 && (block == sdp->md.pinode->i_di.di_num.no_addr ||
+ block == sdp->master_dir->i_di.di_num.no_addr))
dinode_type = gfs2_inode_dir;
else
dinode_type = gfs2_inode_file;
@@ -239,8 +242,12 @@ static int fix_leaf_pointers(struct gfs2_inode *dip, int *lindex,
the last 8 of them. If we have 7, write the last 4, etc.
We need to write these starting at the current lindex and adjust
lindex accordingly. */
- count = gfs2_writei(dip, ptrbuf + (off_by * sizeof(uint64_t)),
- start_lindex * sizeof(uint64_t), bufsize);
+ if (dip->i_sbd->gfs1)
+ count = gfs1_writei(dip, ptrbuf + (off_by * sizeof(uint64_t)),
+ start_lindex * sizeof(uint64_t), bufsize);
+ else
+ count = gfs2_writei(dip, ptrbuf + (off_by * sizeof(uint64_t)),
+ start_lindex * sizeof(uint64_t), bufsize);
if (count != bufsize) {
log_err( _("Error: bad read while fixing leaf pointers.\n"));
free(ptrbuf);
@@ -248,8 +255,12 @@ static int fix_leaf_pointers(struct gfs2_inode *dip, int *lindex,
}
/* Now zero out the hole left at the end */
memset(ptrbuf, 0, off_by * sizeof(uint64_t));
- gfs2_writei(dip, ptrbuf, (start_lindex * sizeof(uint64_t)) +
- bufsize, off_by * sizeof(uint64_t));
+ if (dip->i_sbd->gfs1)
+ gfs1_writei(dip, ptrbuf, (start_lindex * sizeof(uint64_t)) +
+ bufsize, off_by * sizeof(uint64_t));
+ else
+ gfs2_writei(dip, ptrbuf, (start_lindex * sizeof(uint64_t)) +
+ bufsize, off_by * sizeof(uint64_t));
free(ptrbuf);
*lindex -= off_by; /* adjust leaf index to account for the change */
return 0;
@@ -381,7 +392,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height) {
+ if (is_dir(&ip->i_di, ip->i_sbd->gfs1) && h == ip->i_di.di_height) {
iblk_type = GFS2_METATYPE_JD;
blktypedesc = _("a directory hash table block");
} else {
@@ -449,7 +460,7 @@ static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
_("itself"), gfs2_block_free);
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height)
+ if (is_dir(&ip->i_di, ip->i_sbd->gfs1) && h == ip->i_di.di_height)
iblk_type = GFS2_METATYPE_JD;
else
iblk_type = GFS2_METATYPE_IN;
@@ -526,7 +537,22 @@ static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
bc->data_count++;
return 1;
}
- fsck_blockmap_set(ip, block, _("data"), gfs2_block_used);
+ /* In gfs1, rgrp indirect blocks are marked in the bitmap as "meta".
+ In gfs2, "meta" is only for dinodes. So here we dummy up the
+ blocks so that the bitmap isn't changed improperly. */
+ if (ip->i_sbd->gfs1 && ip == ip->i_sbd->md.riinode) {
+ log_info(_("Block %lld (0x%llx) is a GFS1 rindex block\n"),
+ (unsigned long long)block, (unsigned long long)block);
+ gfs2_special_set(&gfs1_rindex_blks, block);
+ fsck_blockmap_set(ip, block, _("rgrp"), gfs2_indir_blk);
+ /*gfs2_meta_rgrp);*/
+ } else if (ip->i_sbd->gfs1 && ip->i_di.di_flags & GFS2_DIF_JDATA) {
+ log_info(_("Block %lld (0x%llx) is a GFS1 journaled data "
+ "block\n"),
+ (unsigned long long)block, (unsigned long long)block);
+ fsck_blockmap_set(ip, block, _("jdata"), gfs2_jdata);
+ } else
+ fsck_blockmap_set(ip, block, _("data"), gfs2_block_used);
bc->data_count++;
return 0;
}
@@ -1020,6 +1046,7 @@ static int invalidate_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
* messing with them because we don't want to mark a block as a
* duplicate (for example) until we know if the pointers in general can
* be trusted. Thus it needs to be in a separate loop.
+ * Returns: 0 if good range, otherwise != 0
*/
static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh,
@@ -1112,6 +1139,7 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
struct block_count bc = {0};
long bad_pointers;
uint64_t block = ip->i_bh->b_blocknr;
+ uint32_t mode;
bad_pointers = 0L;
@@ -1132,8 +1160,12 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
return 0;
}
- switch(ip->i_di.di_mode & S_IFMT) {
+ if (sdp->gfs1)
+ mode = gfs_to_gfs2_mode(ip->i_di.__pad1);
+ else
+ mode = ip->i_di.di_mode & S_IFMT;
+ switch (mode) {
case S_IFDIR:
if (fsck_blockmap_set(ip, block, _("directory"),
gfs2_inode_dir))
@@ -1142,8 +1174,7 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
goto bad_dinode;
break;
case S_IFREG:
- if (fsck_blockmap_set(ip, block, _("file"),
- gfs2_inode_file))
+ if (fsck_blockmap_set(ip, block, _("file"), gfs2_inode_file))
goto bad_dinode;
break;
case S_IFLNK:
@@ -1196,8 +1227,7 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
if (set_di_nlink(ip))
goto bad_dinode;
- if (S_ISDIR(ip->i_di.di_mode) &&
- (ip->i_di.di_flags & GFS2_DIF_EXHASH)) {
+ if (is_dir(&ip->i_di, sdp->gfs1) && (ip->i_di.di_flags & GFS2_DIF_EXHASH)) {
if (((1 << ip->i_di.di_depth) * sizeof(uint64_t)) != ip->i_di.di_size){
log_warn( _("Directory dinode block #%llu (0x%llx"
") has bad depth. Found %u, Expected %u\n"),
@@ -1396,7 +1426,7 @@ static int check_system_inode(struct gfs2_sbd *sdp,
return -1;
}
}
- if (S_ISDIR((*sysinode)->i_di.di_mode)) {
+ if (is_dir(&(*sysinode)->i_di, sdp->gfs1)) {
struct block_count bc = {0};
sysdir_fxns.private = &bc;
@@ -1413,12 +1443,17 @@ static int check_system_inode(struct gfs2_sbd *sdp,
static int build_a_journal(struct gfs2_sbd *sdp)
{
char name[256];
+ int err = 0;
/* First, try to delete the journal if it's in jindex */
sprintf(name, "journal%u", sdp->md.journals);
gfs2_dirent_del(sdp->md.jiinode, name, strlen(name));
/* Now rebuild it */
- build_journal(sdp, sdp->md.journals, sdp->md.jiinode);
+ err = build_journal(sdp, sdp->md.journals, sdp->md.jiinode);
+ if (err) {
+ log_crit(_("Error %d building journal\n"), err);
+ exit(FSCK_ERROR);
+ }
return 0;
}
@@ -1432,13 +1467,15 @@ static int check_system_inodes(struct gfs2_sbd *sdp)
/* Mark the master system dinode as a "dinode" in the block map.
All other system dinodes in master will be taken care of by function
resuscitate_metalist. But master won't since it has no parent.*/
- fsck_blockmap_set(sdp->master_dir,
- sdp->master_dir->i_di.di_num.no_addr,
- "master", gfs2_inode_dir);
- if (check_system_inode(sdp, &sdp->master_dir, "master", build_master,
- gfs2_inode_dir)) {
- stack;
- return -1;
+ if (!sdp->gfs1) {
+ fsck_blockmap_set(sdp->master_dir,
+ sdp->master_dir->i_di.di_num.no_addr,
+ "master", gfs2_inode_dir);
+ if (check_system_inode(sdp, &sdp->master_dir, "master",
+ build_master, gfs2_inode_dir)) {
+ stack;
+ return -1;
+ }
}
/* Mark the root dinode as a "dinode" in the block map as we did
for master, since it has no parent. */
@@ -1449,7 +1486,8 @@ static int check_system_inodes(struct gfs2_sbd *sdp)
stack;
return -1;
}
- if (check_system_inode(sdp, &sdp->md.inum, "inum", build_inum,
+ if (!sdp->gfs1 &&
+ check_system_inode(sdp, &sdp->md.inum, "inum", build_inum,
gfs2_inode_file)) {
stack;
return -1;
@@ -1460,7 +1498,7 @@ static int check_system_inodes(struct gfs2_sbd *sdp)
return -1;
}
if (check_system_inode(sdp, &sdp->md.jiinode, "jindex", build_jindex,
- gfs2_inode_dir)) {
+ (sdp->gfs1 ? gfs2_inode_file : gfs2_inode_dir))) {
stack;
return -1;
}
@@ -1474,7 +1512,8 @@ static int check_system_inodes(struct gfs2_sbd *sdp)
stack;
return -1;
}
- if (check_system_inode(sdp, &sdp->md.pinode, "per_node",
+ if (!sdp->gfs1 &&
+ check_system_inode(sdp, &sdp->md.pinode, "per_node",
build_per_node, gfs2_inode_dir)) {
stack;
return -1;
@@ -1482,6 +1521,21 @@ static int check_system_inodes(struct gfs2_sbd *sdp)
/* We have to play a trick on build_journal: We swap md.journals
in order to keep a count of which journal we need to build. */
journal_count = sdp->md.journals;
+ /* gfs1's journals aren't dinode, they're just a bunch of blocks. */
+ if (sdp->gfs1) {
+ /* gfs1 has four dinodes that are set in the superblock and
+ therefore not linked to anything else. We need to adjust
+ the link counts so pass4 doesn't get confused. */
+ incr_link_count(sdp->md.statfs->i_di.di_num.no_addr, 0,
+ _("gfs1 statfs inode"));
+ incr_link_count(sdp->md.jiinode->i_di.di_num.no_addr, 0,
+ _("gfs1 jindex inode"));
+ incr_link_count(sdp->md.riinode->i_di.di_num.no_addr, 0,
+ _("gfs1 rindex inode"));
+ incr_link_count(sdp->md.qinode->i_di.di_num.no_addr, 0,
+ _("gfs1 quota inode"));
+ return 0;
+ }
for (sdp->md.journals = 0; sdp->md.journals < journal_count;
sdp->md.journals++) {
char jname[16];
@@ -1523,6 +1577,8 @@ int pass1(struct gfs2_sbd *sdp)
uint64_t offset;
uint64_t rg_count = 0;
+ osi_list_init(&gfs1_rindex_blks.list);
+
/* FIXME: In the gfs fsck, we had to mark things like the
* journals and indices and such as 'other_meta' - in gfs2,
* the journals are files and are found in the normal file
@@ -1553,6 +1609,7 @@ int pass1(struct gfs2_sbd *sdp)
if (gfs2_blockmap_set(bl, rgd->ri.ri_addr + i,
gfs2_indir_blk)) {
stack;
+ gfs2_special_free(&gfs1_rindex_blks);
return FSCK_ERROR;
}
/* rgrps and bitmaps don't have bits to represent
@@ -1568,13 +1625,25 @@ int pass1(struct gfs2_sbd *sdp)
while (1) {
/* "block" is relative to the entire file system */
/* Get the next dinode in the file system, according
- to the bitmap. This should ONLY be dinodes. */
+ to the bitmap. This should ONLY be dinodes unless
+ it's GFS1, in which case it can be any metadata. */
if (gfs2_next_rg_meta(rgd, &block, first))
break;
+ /* skip gfs1 rindex indirect blocks */
+ if (sdp->gfs1 && blockfind(&gfs1_rindex_blks, block)) {
+ log_debug(_("Skipping rindex indir block "
+ "%lld (0x%llx)\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ first = 0;
+ continue;
+ }
warm_fuzzy_stuff(block);
- if (fsck_abort) /* if asked to abort */
+ if (fsck_abort) { /* if asked to abort */
+ gfs2_special_free(&gfs1_rindex_blks);
return FSCK_OK;
+ }
if (skip_this_pass) {
printf( _("Skipping pass 1 is not a good idea.\n"));
skip_this_pass = FALSE;
@@ -1594,6 +1663,31 @@ int pass1(struct gfs2_sbd *sdp)
" (0x%" PRIx64 ")\n"), block, block);*/
if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
+ /* In gfs2, a bitmap mark of 2 means an inode,
+ but in gfs1 it means any metadata. So if
+ this is gfs1 and not an inode, it may be
+ okay. If it's non-dinode metadata, it will
+ be referenced by an inode, so we need to
+ skip it here and it will be sorted out
+ when the referencing inode is checked. */
+ if (sdp->gfs1) {
+ uint32_t check_magic;
+
+ check_magic = ((struct
+ gfs2_meta_header *)
+ (bh->b_data))->mh_magic;
+ if (be32_to_cpu(check_magic) ==
+ GFS2_MAGIC) {
+ log_debug( _("Deferring GFS1 "
+ "metadata block #"
+ "%" PRIu64" (0x%"
+ PRIx64 ")\n"),
+ block, block);
+ brelse(bh);
+ first = 0;
+ continue;
+ }
+ }
log_err( _("Found invalid inode at block #"
"%llu (0x%llx)\n"),
(unsigned long long)block,
@@ -1602,6 +1696,7 @@ int pass1(struct gfs2_sbd *sdp)
gfs2_block_free)) {
stack;
brelse(bh);
+ gfs2_special_free(&gfs1_rindex_blks);
return FSCK_ERROR;
}
check_n_fix_bitmap(sdp, block,
@@ -1609,6 +1704,7 @@ int pass1(struct gfs2_sbd *sdp)
} else if (handle_di(sdp, bh) < 0) {
stack;
brelse(bh);
+ gfs2_special_free(&gfs1_rindex_blks);
return FSCK_ERROR;
}
/* Ignore everything else - they should be hit by the
@@ -1621,6 +1717,19 @@ int pass1(struct gfs2_sbd *sdp)
brelse(bh);
first = 0;
}
+ /*
+ For GFS1, we have to count the "free meta" blocks in the
+ resource group and mark them specially so we can count them
+ properly in pass5.
+ */
+ if (!sdp->gfs1)
+ continue;
+ first = 1;
+ while (gfs2_next_rg_freemeta(rgd, &block, first) == 0) {
+ gfs2_blockmap_set(bl, block, gfs2_freemeta);
+ first = 0;
+ }
}
+ gfs2_special_free(&gfs1_rindex_blks);
return FSCK_OK;
}
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index a66bd8b..003d696 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -357,7 +357,8 @@ static int find_block_ref(struct gfs2_sbd *sdp, uint64_t inode)
/* Exhash dir leafs will be checked by check_metatree (right after
the "end:" label.) But if this is a linear directory we need to
check the dir with check_linear_dir. */
- if (S_ISDIR(ip->i_di.di_mode) && !(ip->i_di.di_flags & GFS2_DIF_EXHASH))
+ if (is_dir(&ip->i_di, sdp->gfs1) &&
+ !(ip->i_di.di_flags & GFS2_DIF_EXHASH))
error = check_linear_dir(ip, ip->i_bh, &find_dirents);
/* Check for ea references in the inode */
@@ -693,7 +694,7 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
_("reference-repaired data"),
gfs2_block_used);
} else if (id->reftypecount[ref_as_meta]) {
- if (S_ISDIR(ip->i_di.di_mode))
+ if (is_dir(&ip->i_di, sdp->gfs1))
fsck_blockmap_set(ip, b->block,
_("reference-repaired leaf"),
gfs2_leaf_blk);
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index a4e8dca..7e20315 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -119,31 +119,32 @@ static const char *de_type_string(uint8_t de_type)
return de_types[3]; /* invalid */
}
-static int check_file_type(uint8_t de_type, uint8_t blk_type)
+static int check_file_type(uint8_t de_type, uint8_t blk_type, int gfs1)
{
switch(blk_type) {
case gfs2_inode_dir:
- if (de_type != DT_DIR)
+ if (de_type != (gfs1 ? GFS_FILE_DIR : DT_DIR))
return 1;
break;
case gfs2_inode_file:
- if (de_type != DT_REG)
+ if (de_type != (gfs1 ? GFS_FILE_REG : DT_REG))
return 1;
break;
case gfs2_inode_lnk:
- if (de_type != DT_LNK)
+ if (de_type != (gfs1 ? GFS_FILE_LNK : DT_LNK))
return 1;
break;
case gfs2_inode_device:
- if (de_type != DT_BLK && de_type != DT_CHR)
+ if ((de_type != (gfs1 ? GFS_FILE_BLK : DT_BLK)) &&
+ (de_type != (gfs1 ? GFS_FILE_CHR : DT_CHR)))
return 1;
break;
case gfs2_inode_fifo:
- if (de_type != DT_FIFO)
+ if (de_type != (gfs1 ? GFS_FILE_FIFO : DT_FIFO))
return 1;
break;
case gfs2_inode_sock:
- if (de_type != DT_SOCK)
+ if (de_type != (gfs1 ? GFS_FILE_SOCK : DT_SOCK))
return 1;
break;
default:
@@ -391,7 +392,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
goto nuke_dentry;
}
- error = check_file_type(de->de_type, q);
+ error = check_file_type(de->de_type, q, sdp->gfs1);
if (error < 0) {
log_err( _("Error: directory entry type is "
"incompatible with block type at block %lld "
@@ -664,7 +665,9 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
memcpy(filename, tmp_name, filename_len);
log_warn( _("Adding '.' entry\n"));
dir_add(sysinode, filename, filename_len,
- &(sysinode->i_di.di_num), DT_DIR);
+ &(sysinode->i_di.di_num),
+ (sysinode->i_sbd->gfs1 ?
+ GFS_FILE_DIR : DT_DIR));
if (cur_blks != sysinode->i_di.di_blocks)
reprocess_inode(sysinode, dirname);
/* This system inode is linked to itself via '.' */
@@ -706,8 +709,11 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
*/
static inline int is_system_dir(struct gfs2_sbd *sdp, uint64_t block)
{
- if (block == sdp->md.rooti->i_di.di_num.no_addr ||
- block == sdp->md.jiinode->i_di.di_num.no_addr ||
+ if (block == sdp->md.rooti->i_di.di_num.no_addr)
+ return TRUE;
+ if (sdp->gfs1)
+ return FALSE;
+ if (block == sdp->md.jiinode->i_di.di_num.no_addr ||
block == sdp->md.pinode->i_di.di_num.no_addr ||
block == sdp->master_dir->i_di.di_num.no_addr)
return TRUE;
@@ -737,19 +743,22 @@ int pass2(struct gfs2_sbd *sdp)
int error = 0;
/* Check all the system directory inodes. */
- if (check_system_dir(sdp->md.jiinode, "jindex", build_jindex)) {
+ if (!sdp->gfs1 &&
+ check_system_dir(sdp->md.jiinode, "jindex", build_jindex)) {
stack;
return FSCK_ERROR;
}
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
return FSCK_OK;
- if (check_system_dir(sdp->md.pinode, "per_node", build_per_node)) {
+ if (!sdp->gfs1 &&
+ check_system_dir(sdp->md.pinode, "per_node", build_per_node)) {
stack;
return FSCK_ERROR;
}
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
return FSCK_OK;
- if (check_system_dir(sdp->master_dir, "master", build_master)) {
+ if (!sdp->gfs1 &&
+ check_system_dir(sdp->master_dir, "master", build_master)) {
stack;
return FSCK_ERROR;
}
@@ -870,7 +879,8 @@ int pass2(struct gfs2_sbd *sdp)
cur_blks = ip->i_di.di_blocks;
dir_add(ip, filename, filename_len,
- &(ip->i_di.di_num), DT_DIR);
+ &(ip->i_di.di_num),
+ (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
if (cur_blks != ip->i_di.di_blocks) {
char dirname[80];
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index 51104b5..e1accc9 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -52,7 +52,8 @@ static int attach_dotdot_to(struct gfs2_sbd *sdp, uint64_t newdotdot,
else
decr_link_count(olddotdot, block, _("old \"..\""));
cur_blks = ip->i_di.di_blocks;
- dir_add(ip, filename, filename_len, &pip->i_di.di_num, DT_DIR);
+ dir_add(ip, filename, filename_len, &pip->i_di.di_num,
+ (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
if (cur_blks != ip->i_di.di_blocks) {
char dirname[80];
@@ -188,10 +189,38 @@ int pass3(struct gfs2_sbd *sdp)
log_info( _("Marking root inode connected\n"));
di->checked = 1;
}
- di = dirtree_find(sdp->master_dir->i_di.di_num.no_addr);
- if (di) {
- log_info( _("Marking master directory inode connected\n"));
- di->checked = 1;
+ if (sdp->gfs1) {
+ di = dirtree_find(sdp->md.statfs->i_di.di_num.no_addr);
+ if (di) {
+ log_info( _("Marking GFS1 statfs file inode "
+ "connected\n"));
+ di->checked = 1;
+ }
+ di = dirtree_find(sdp->md.jiinode->i_di.di_num.no_addr);
+ if (di) {
+ log_info( _("Marking GFS1 jindex file inode "
+ "connected\n"));
+ di->checked = 1;
+ }
+ di = dirtree_find(sdp->md.riinode->i_di.di_num.no_addr);
+ if (di) {
+ log_info( _("Marking GFS1 rindex file inode "
+ "connected\n"));
+ di->checked = 1;
+ }
+ di = dirtree_find(sdp->md.qinode->i_di.di_num.no_addr);
+ if (di) {
+ log_info( _("Marking GFS1 quota file inode "
+ "connected\n"));
+ di->checked = 1;
+ }
+ } else {
+ di = dirtree_find(sdp->master_dir->i_di.di_num.no_addr);
+ if (di) {
+ log_info( _("Marking master directory inode "
+ "connected\n"));
+ di->checked = 1;
+ }
}
/* Go through the directory list, working up through the parents
diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c
index 32dbb72..6d933e9 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -56,6 +56,13 @@ static int scan_inode_list(struct gfs2_sbd *sdp) {
log_crit( _("osi_tree broken in scan_info_list!!\n"));
exit(FSCK_ERROR);
}
+ /* Don't check reference counts on the special gfs files */
+ if (sdp->gfs1 &&
+ ((ii->inode == sdp->md.riinode->i_di.di_num.no_addr) ||
+ (ii->inode == sdp->md.jiinode->i_di.di_num.no_addr) ||
+ (ii->inode == sdp->md.qinode->i_di.di_num.no_addr) ||
+ (ii->inode == sdp->md.statfs->i_di.di_num.no_addr)))
+ continue;
if (ii->counted_links == 0) {
log_err( _("Found unlinked inode at %llu (0x%llx)\n"),
(unsigned long long)ii->inode,
diff --git a/gfs2/fsck/pass5.c b/gfs2/fsck/pass5.c
index 29b5965..3cf420b 100644
--- a/gfs2/fsck/pass5.c
+++ b/gfs2/fsck/pass5.c
@@ -9,7 +9,7 @@
#include "fsck.h"
#include "util.h"
-static int convert_mark(uint8_t q, uint32_t *count)
+static int gfs1_convert_mark(uint8_t q, uint32_t *count)
{
switch(q) {
@@ -35,10 +35,62 @@ static int convert_mark(uint8_t q, uint32_t *count)
case gfs2_indir_blk:
case gfs2_leaf_blk:
+ /*case gfs2_meta_rgrp:*/
+ case gfs2_jdata: /* gfs1 jdata blocks count as "metadata" and gfs1
+ metadata is marked the same as gfs2 inode in the
+ bitmap. */
+ case gfs2_meta_eattr:
+ count[3]++;
+ return GFS2_BLKST_DINODE;
+
+ case gfs2_freemeta:
+ count[4]++;
+ return GFS2_BLKST_UNLINKED;
+
+ default:
+ log_err( _("Invalid block type %d found\n"), q);
+ }
+ return -1;
+}
+
+static int gfs2_convert_mark(uint8_t q, uint32_t *count)
+{
+ switch(q) {
+
+ case gfs2_meta_inval:
+ case gfs2_inode_invalid:
+ /* Convert invalid metadata to free blocks */
+ case gfs2_block_free:
+ count[0]++;
+ return GFS2_BLKST_FREE;
+
+ case gfs2_block_used:
+ count[2]++;
+ return GFS2_BLKST_USED;
+
+ case gfs2_inode_dir:
+ case gfs2_inode_file:
+ case gfs2_inode_lnk:
+ case gfs2_inode_device:
+ case gfs2_jdata: /* gfs1 jdata blocks count as "metadata" and gfs1
+ metadata is marked the same as gfs2 inode in the
+ bitmap. */
+ case gfs2_inode_fifo:
+ case gfs2_inode_sock:
+ count[1]++;
+ return GFS2_BLKST_DINODE;
+
+ case gfs2_indir_blk:
+ case gfs2_leaf_blk:
case gfs2_meta_eattr:
count[2]++;
return GFS2_BLKST_USED;
+ case gfs2_freemeta:
+ log_err( _("Invalid freemeta type %d found\n"), q);
+ count[4]++;
+ return -1;
+
default:
log_err( _("Invalid block type %d found\n"), q);
}
@@ -69,7 +121,10 @@ static int check_block_status(struct gfs2_sbd *sdp, char *buffer,
return 0;
q = block_type(block);
- block_status = convert_mark(q, count);
+ if (sdp->gfs1)
+ block_status = gfs1_convert_mark(q, count);
+ else
+ block_status = gfs2_convert_mark(q, count);
/* If one node opens a file and another node deletes it, we
may be left with a block that appears to be "unlinked" in
@@ -143,6 +198,7 @@ static void update_rgrp(struct gfs2_sbd *sdp, struct rgrp_list *rgp,
struct gfs2_bitmap *bits;
uint64_t rg_block = 0;
int update = 0;
+ struct gfs_rgrp *gfs1rg = (struct gfs_rgrp *)&rgp->rg;
for(i = 0; i < rgp->ri.ri_length; i++) {
bits = &rgp->bits[i];
@@ -174,7 +230,25 @@ static void update_rgrp(struct gfs2_sbd *sdp, struct rgrp_list *rgp,
rgp->rg.rg_dinodes = count[1];
update = 1;
}
- if ((rgp->ri.ri_data - count[0] - count[1]) != count[2]) {
+ if (sdp->gfs1 && gfs1rg->rg_usedmeta != count[3]) {
+ log_err( _("RG #%llu (0x%llx) Used metadata count "
+ "inconsistent: is %u should be %u\n"),
+ (unsigned long long)rgp->ri.ri_addr,
+ (unsigned long long)rgp->ri.ri_addr,
+ gfs1rg->rg_usedmeta, count[3]);
+ gfs1rg->rg_usedmeta = count[3];
+ update = 1;
+ }
+ if (sdp->gfs1 && gfs1rg->rg_freemeta != count[4]) {
+ log_err( _("RG #%llu (0x%llx) Free metadata count "
+ "inconsistent: is %u should be %u\n"),
+ (unsigned long long)rgp->ri.ri_addr,
+ (unsigned long long)rgp->ri.ri_addr,
+ gfs1rg->rg_freemeta, count[4]);
+ gfs1rg->rg_freemeta = count[4];
+ update = 1;
+ }
+ if (!sdp->gfs1 && (rgp->ri.ri_data - count[0] - count[1]) != count[2]) {
/* FIXME not sure how to handle this case ATM - it
* means that the total number of blocks we've counted
* exceeds the blocks in the rg */
@@ -185,7 +259,10 @@ static void update_rgrp(struct gfs2_sbd *sdp, struct rgrp_list *rgp,
if (query( _("Update resource group counts? (y/n) "))) {
log_warn( _("Resource group counts updated\n"));
/* write out the rgrp */
- gfs2_rgrp_out(&rgp->rg, rgp->bh[0]);
+ if (sdp->gfs1)
+ gfs_rgrp_out(gfs1rg, rgp->bh[0]);
+ else
+ gfs2_rgrp_out(&rgp->rg, rgp->bh[0]);
} else
log_err( _("Resource group counts left inconsistent\n"));
}
@@ -201,7 +278,7 @@ int pass5(struct gfs2_sbd *sdp)
{
osi_list_t *tmp;
struct rgrp_list *rgp = NULL;
- uint32_t count[3];
+ uint32_t count[5];
uint64_t rg_count = 0;
/* Reconcile RG bitmaps with fsck bitmap */
diff --git a/gfs2/fsck/rgrepair.c b/gfs2/fsck/rgrepair.c
index c01aaa6..28ed451 100644
--- a/gfs2/fsck/rgrepair.c
+++ b/gfs2/fsck/rgrepair.c
@@ -184,8 +184,13 @@ static uint64_t count_usedspace(struct gfs2_sbd *sdp, int first,
unsigned int state;
/* Count up the free blocks in the bitmap */
- off = (first) ? sizeof(struct gfs2_rgrp) :
- sizeof(struct gfs2_meta_header);
+ if (first) {
+ if (sdp->gfs1)
+ off = sizeof(struct gfs_rgrp);
+ else
+ off = sizeof(struct gfs2_rgrp);
+ } else
+ off = sizeof(struct gfs2_meta_header);
bytes_to_check = sdp->bsize - off;
for (x = 0; x < bytes_to_check; x++) {
unsigned char *byte;
@@ -681,12 +686,19 @@ static int rewrite_rg_block(struct gfs2_sbd *sdp, struct rgrp_list *rg,
mh.mh_format = GFS2_FORMAT_RB;
gfs2_meta_header_out(&mh, rg->bh[x]);
} else {
- memset(&rg->rg, 0, sizeof(struct gfs2_rgrp));
+ if (sdp->gfs1)
+ memset(&rg->rg, 0, sizeof(struct gfs_rgrp));
+ else
+ memset(&rg->rg, 0, sizeof(struct gfs2_rgrp));
rg->rg.rg_header.mh_magic = GFS2_MAGIC;
rg->rg.rg_header.mh_type = GFS2_METATYPE_RG;
rg->rg.rg_header.mh_format = GFS2_FORMAT_RG;
rg->rg.rg_free = rg->ri.ri_data;
- gfs2_rgrp_out(&rg->rg, rg->bh[x]);
+ if (sdp->gfs1)
+ gfs_rgrp_out((struct gfs_rgrp *)&rg->rg,
+ rg->bh[x]);
+ else
+ gfs2_rgrp_out(&rg->rg, rg->bh[x]);
}
brelse(rg->bh[x]);
rg->bh[x] = NULL;
diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h
index 106cca8..9b2de61 100644
--- a/gfs2/fsck/util.h
+++ b/gfs2/fsck/util.h
@@ -1,6 +1,8 @@
#ifndef __UTIL_H__
#define __UTIL_H__
+#include <sys/stat.h>
+
#include "fsck.h"
#include "libgfs2.h"
@@ -42,15 +44,15 @@ enum gfs2_mark_block {
gfs2_inode_file = (0x4),
gfs2_inode_lnk = (0x5),
- gfs2_inode_device = (0x6),
-
+ gfs2_inode_device = (0x6), /* char or block device */
+ gfs2_jdata = (0x7), /* gfs journaled data blocks */
gfs2_inode_fifo = (0x8),
gfs2_inode_sock = (0x9),
gfs2_inode_invalid = (0xa),
gfs2_meta_inval = (0xb),
gfs2_leaf_blk = (0xc),
-
+ gfs2_freemeta = (0xd), /* was: gfs2_meta_rgrp */
gfs2_meta_eattr = (0xe),
gfs2_bad_block = (0xf), /* Contains at least one bad block */
@@ -67,14 +69,14 @@ static const inline char *block_type_string(uint8_t q)
"symlink",
"device",
- "",
+ "journaled data",
"fifo",
"socket",
"invalid inode",
"invalid meta",
"dir leaf",
- "",
+ "free metadata",
"eattribute",
"bad"};
@@ -85,30 +87,82 @@ static const inline char *block_type_string(uint8_t q)
/* Must be kept in sync with gfs2_mark_block enum above. Blocks marked as
invalid or bad are considered metadata until actually freed. */
-static inline int blockmap_to_bitmap(enum gfs2_mark_block m)
+static inline int blockmap_to_bitmap(enum gfs2_mark_block m, int gfs1)
{
- static int bitmap_states[16] = {
- GFS2_BLKST_FREE, /* free */
- GFS2_BLKST_USED, /* data */
- GFS2_BLKST_USED, /* indirect data or rgrp meta*/
- GFS2_BLKST_DINODE, /* directory */
- GFS2_BLKST_DINODE, /* file */
-
- GFS2_BLKST_DINODE, /* symlink */
- GFS2_BLKST_DINODE, /* block or char device */
- GFS2_BLKST_USED, /* reserved */
- GFS2_BLKST_DINODE, /* fifo */
- GFS2_BLKST_DINODE, /* socket */
-
- GFS2_BLKST_FREE, /* invalid inode */
- GFS2_BLKST_FREE, /* invalid meta */
- GFS2_BLKST_USED, /* dir leaf */
- GFS2_BLKST_UNLINKED, /* unused */
- GFS2_BLKST_USED, /* eattribute */
-
- GFS2_BLKST_USED, /* bad */
- };
- return bitmap_states[m];
+ static int bitmap_states[2][16] = {
+ /* ---------------------- gfs2 ------------------------------*/
+ {GFS2_BLKST_FREE, /* free */
+ GFS2_BLKST_USED, /* data */
+ GFS2_BLKST_USED, /* indirect data or rgrp meta */
+ GFS2_BLKST_DINODE, /* directory */
+ GFS2_BLKST_DINODE, /* file */
+
+ GFS2_BLKST_DINODE, /* symlink */
+ GFS2_BLKST_DINODE, /* block or char device */
+ GFS2_BLKST_USED, /* journaled data */
+ GFS2_BLKST_DINODE, /* fifo */
+ GFS2_BLKST_DINODE, /* socket */
+
+ GFS2_BLKST_FREE, /* invalid inode */
+ GFS2_BLKST_FREE, /* invalid meta */
+ GFS2_BLKST_USED, /* dir leaf */
+ GFS2_BLKST_UNLINKED, /* GFS unlinked metadata */
+ GFS2_BLKST_USED, /* eattribute */
+
+ GFS2_BLKST_USED}, /* bad */
+ /* ---------------------- gfs1 ----------------------------- */
+ {GFS2_BLKST_FREE, /* free */
+ GFS2_BLKST_USED, /* data */
+ GFS2_BLKST_DINODE, /* indirect data or rgrp meta*/
+ GFS2_BLKST_DINODE, /* directory */
+ GFS2_BLKST_DINODE, /* file */
+
+ GFS2_BLKST_DINODE, /* symlink */
+ GFS2_BLKST_DINODE, /* block or char device */
+ GFS2_BLKST_DINODE, /* journaled data */
+ GFS2_BLKST_DINODE, /* fifo */
+ GFS2_BLKST_DINODE, /* socket */
+
+ GFS2_BLKST_FREE, /* invalid inode */
+ GFS2_BLKST_FREE, /* invalid meta */
+ GFS2_BLKST_DINODE, /* dir leaf */
+ GFS2_BLKST_UNLINKED, /* GFS unlinked metadata */
+ GFS2_BLKST_DINODE, /* eattribute */
+
+ GFS2_BLKST_USED}}; /* bad */
+ return bitmap_states[gfs1][m];
+}
+
+static inline int is_dir(struct gfs2_dinode *dinode, int gfs1)
+{
+ if (gfs1 && is_gfs_dir(dinode))
+ return 1;
+ if (S_ISDIR(dinode->di_mode))
+ return 1;
+
+ return 0;
+}
+
+static inline uint32_t gfs_to_gfs2_mode(uint32_t gfs1mode)
+{
+ switch (gfs1mode) {
+ case GFS_FILE_DIR:
+ return S_IFDIR;
+ case GFS_FILE_REG:
+ return S_IFREG;
+ case GFS_FILE_LNK:
+ return S_IFLNK;
+ case GFS_FILE_BLK:
+ return S_IFBLK;
+ case GFS_FILE_CHR:
+ return S_IFCHR;
+ case GFS_FILE_FIFO:
+ return S_IFIFO;
+ case GFS_FILE_SOCK:
+ return S_IFSOCK;
+ default:
+ return S_IFREG;
+ }
}
extern struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size,
@@ -116,5 +170,4 @@ extern struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size,
extern void *gfs2_bmap_destroy(struct gfs2_sbd *sdp, struct gfs2_bmap *il);
extern int gfs2_blockmap_set(struct gfs2_bmap *il, uint64_t block,
enum gfs2_mark_block mark);
-
#endif /* __UTIL_H__ */
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 58442e8..b1574fb 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -723,6 +723,9 @@ extern int gfs2_next_rg_meta(struct rgrp_list *rgd, uint64_t *block,
int first);
extern int gfs2_next_rg_metatype(struct gfs2_sbd *sdp, struct rgrp_list *rgd,
uint64_t *block, uint32_t type, int first);
+extern int gfs2_next_rg_freemeta(struct rgrp_list *rgd, uint64_t *block,
+ int first);
+
/* super.c */
extern int check_sb(struct gfs2_sb *sb, int allow_gfs);
extern int read_sb(struct gfs2_sbd *sdp, int allow_gfs);
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index 7dabd80..f53b4af 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -459,39 +459,50 @@ int gfs2_check_meta(struct gfs2_buffer_head *bh, int type)
*
* Returns: 0 on success, -1 when finished
*/
-int gfs2_next_rg_meta(struct rgrp_list *rgd, uint64_t *block, int first)
+static int __gfs2_next_rg_meta(struct rgrp_list *rgd, uint64_t *block,
+ int first, unsigned char state)
{
struct gfs2_bitmap *bits = NULL;
uint32_t length = rgd->ri.ri_length;
- uint32_t blk = (first)? 0: (uint32_t)((*block+1)-rgd->ri.ri_data0);
+ uint32_t blk = (first)? 0: (uint32_t)((*block + 1) - rgd->ri.ri_data0);
int i;
if(!first && (*block < rgd->ri.ri_data0)) {
log_err("next_rg_meta: Start block is outside rgrp bounds.\n");
exit(1);
}
- for(i=0; i < length; i++){
+ for(i = 0; i < length; i++){
bits = &rgd->bits[i];
- if(blk < bits->bi_len*GFS2_NBBY)
+ if (blk < bits->bi_len * GFS2_NBBY)
break;
- blk -= bits->bi_len*GFS2_NBBY;
+ blk -= bits->bi_len * GFS2_NBBY;
}
for(; i < length; i++){
bits = &rgd->bits[i];
blk = gfs2_bitfit((unsigned char *)rgd->bh[i]->b_data +
- bits->bi_offset, bits->bi_len, blk,
- GFS2_BLKST_DINODE);
+ bits->bi_offset, bits->bi_len, blk, state);
if(blk != BFITNOENT){
- *block = blk + (bits->bi_start * GFS2_NBBY) + rgd->ri.ri_data0;
+ *block = blk + (bits->bi_start * GFS2_NBBY) +
+ rgd->ri.ri_data0;
break;
}
- blk=0;
+ blk = 0;
}
if(i == length)
return -1;
return 0;
}
+int gfs2_next_rg_meta(struct rgrp_list *rgd, uint64_t *block, int first)
+{
+ return __gfs2_next_rg_meta(rgd, block, first, GFS2_BLKST_DINODE);
+}
+
+int gfs2_next_rg_freemeta(struct rgrp_list *rgd, uint64_t *block, int first)
+{
+ return __gfs2_next_rg_meta(rgd, block, first, GFS2_BLKST_UNLINKED);
+}
+
/**
* next_rg_metatype
* @rgd:
12 years, 3 months
cluster: RHEL6 - fsck.gfs2: Remove bad inodes from duplicate tree
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: a07ef06fdd7048154aee94e24a3972b582d4d85a
Parent: 94ada9a53b0c5bdf273c9801e2ffe1877356478d
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Aug 17 10:33:07 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Jan 20 08:26:27 2012 -0600
fsck.gfs2: Remove bad inodes from duplicate tree
The problem was that if an inode was determined to be "bad" (lots of
corruption) and its metadata blocks were invalidated in pass1, the
"bad" block for the inode was set as "data" in the bitmap. Later,
that caused duplicate reference processing (pass1b) to not remove the
block from the inode tree inside function check_n_fix_bitmap when the
bad block was freed. Later still, in pass4, that caused the now
deleted inode to be processed again, at which time it would reprocess
the inode's metadata and free all blocks, including blocks that were
duplicate-referenced by other inodes. In other words, pass4 freed
blocks out from under valid references when it should not have. This
patch changes the bitmap type for "bad" blocks from "data" to
"inode". That causes function check_n_fix_bitmap to try to remove the
bad block from the inode tree, so pass4 never processes it by mistake.
This patch also changes a few debug messages to make them shorter so
that the output files aren't as big to search through.
rhbz#675723
---
gfs2/fsck/metawalk.c | 20 ++++++--------------
gfs2/fsck/pass1.c | 8 ++++++--
gfs2/fsck/util.h | 4 ++--
3 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 2ddf7dd..94b0148 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -113,36 +113,28 @@ int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
output easier to debug. */
if (ip->i_di.di_num.no_addr == bblock) {
print_fsck_log(MSG_DEBUG, caller, fline,
- _("%s inode found at block %lld "
- "(0x%llx): marking as '%s'\n"),
+ _("%s inode found at block "
+ "0x%llx: marking as '%s'\n"),
btype, (unsigned long long)
ip->i_di.di_num.no_addr,
- (unsigned long long)
- ip->i_di.di_num.no_addr,
block_type_string(mark));
} else if (mark == gfs2_bad_block || mark == gfs2_meta_inval) {
print_fsck_log(MSG_DEBUG, caller, fline,
- _("inode %lld (0x%llx) references "
- "%s block %lld (0x%llx): "
+ _("inode 0x%llx references "
+ "%s block 0x%llx: "
"marking as '%s'\n"),
(unsigned long long)
ip->i_di.di_num.no_addr,
- (unsigned long long)
- ip->i_di.di_num.no_addr,
btype, (unsigned long long)bblock,
- (unsigned long long)bblock,
block_type_string(mark));
} else {
print_fsck_log(MSG_DEBUG, caller, fline,
- _("inode %lld (0x%llx) references "
- "%s block %lld (0x%llx): "
+ _("inode 0x%llx references "
+ "%s block 0x%llx: "
"marking as '%s'\n"),
(unsigned long long)
- ip->i_di.di_num.no_addr,
- (unsigned long long)
ip->i_di.di_num.no_addr, btype,
(unsigned long long)bblock,
- (unsigned long long)bblock,
block_type_string(mark));
}
}
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 876078e..515f50a 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -383,8 +383,12 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
*bh = NULL;
if (!valid_block(ip->i_sbd, block)) { /* blk outside of FS */
+ /* The bad dinode should be invalidated later due to
+ "unrecoverable" errors. The inode itself should be
+ set "free" and removed from the inodetree by
+ undo_check_metalist. */
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
- _("itself"), gfs2_bad_block);
+ _("bad block referencing"), gfs2_bad_block);
log_debug( _("Bad indirect block (invalid/out of range) "
"found in inode %lld (0x%llx).\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
@@ -457,7 +461,7 @@ static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
if (!valid_block(ip->i_sbd, block)) { /* blk outside of FS */
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
- _("itself"), gfs2_block_free);
+ _("bad block referencing"), gfs2_block_free);
return 1;
}
if (is_dir(&ip->i_di, ip->i_sbd->gfs1) && h == ip->i_di.di_height)
diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h
index 9b2de61..fd75212 100644
--- a/gfs2/fsck/util.h
+++ b/gfs2/fsck/util.h
@@ -109,7 +109,7 @@ static inline int blockmap_to_bitmap(enum gfs2_mark_block m, int gfs1)
GFS2_BLKST_UNLINKED, /* GFS unlinked metadata */
GFS2_BLKST_USED, /* eattribute */
- GFS2_BLKST_USED}, /* bad */
+ GFS2_BLKST_DINODE}, /* bad */
/* ---------------------- gfs1 ----------------------------- */
{GFS2_BLKST_FREE, /* free */
GFS2_BLKST_USED, /* data */
@@ -129,7 +129,7 @@ static inline int blockmap_to_bitmap(enum gfs2_mark_block m, int gfs1)
GFS2_BLKST_UNLINKED, /* GFS unlinked metadata */
GFS2_BLKST_DINODE, /* eattribute */
- GFS2_BLKST_USED}}; /* bad */
+ GFS2_BLKST_DINODE}}; /* bad */
return bitmap_states[gfs1][m];
}
12 years, 3 months