gfs2-utils: master - fsck.gfs2: Increment link count reporting wrong dinode
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 60140c2ba6be8bf7836c5b1baae7c7a9ea3a71e7
Parent: c31c7932cf9e90ded90ea2d9108a751433272954
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 23 09:28:22 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:55:37 2011 -0500
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 2579480..625de0d 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -282,7 +282,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, 8 months
gfs2-utils: master - fsck.gfs2: Shorten debug output
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: c31c7932cf9e90ded90ea2d9108a751433272954
Parent: c692e1915869f17dc77d6b7de9982f0544604c7d
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 23 09:16:10 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:55:37 2011 -0500
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 | 34 +++++++++++++---------------------
gfs2/fsck/metawalk.c | 39 ++++++++++++++++++++++++++++++++-------
gfs2/fsck/pass2.c | 6 +++---
3 files changed, 48 insertions(+), 31 deletions(-)
diff --git a/gfs2/fsck/link.c b/gfs2/fsck/link.c
index e49f3af..5dc1a1e 100644
--- a/gfs2/fsck/link.c
+++ b/gfs2/fsck/link.c
@@ -37,23 +37,19 @@ 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 %llu (0x%llx) via %s\n"),
- (unsigned long long)referenced_from,
+ log_debug( _("Dir (0x%llx) incremented counted "
+ "links to %u for (0x%llx) via %s\n"),
(unsigned long long)referenced_from,
ii->counted_links, (unsigned long long)inode_no,
- (unsigned long long)inode_no, why);
+ why);
return 0;
}
- log_debug( _("Ref: %llu (0x%llx) No match found when incrementing "
- "link for %llu (0x%llx)!\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,
- (unsigned long long)inode_no,
(unsigned long long)inode_no);
/* If no match was found, add a new entry and set its
* counted links to 1 */
@@ -75,26 +71,22 @@ int decr_link_count(uint64_t inode_no, uint64_t referenced_from,
* inode_no */
if (ii) {
if (!ii->counted_links) {
- log_debug( _("Directory %llu (0x%llx)'s link to "
- " %llu (0x%llx) 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,
- (unsigned long long)inode_no,
(unsigned long long)inode_no, why);
return 0;
}
ii->counted_links--;
- log_debug( _("Directory %llu (0x%llx) decremented counted "
- "links to %u for %llu (0x%llx) 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, (unsigned long long)inode_no,
- (unsigned long long)inode_no, why);
+ why);
return 0;
}
- log_debug( _("No match found when decrementing link for %llu"
- " (0x%llx)!\n"), (unsigned long long)inode_no,
- (unsigned long long)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 9feaa8a..590f7ec 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -109,36 +109,61 @@ 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) {
+ } else if (ip->i_di.di_num.no_addr == bblock) {
+ if (prevcount) {
+ log_info("\n");
+ prevcount = 0;
+ }
print_fsck_log(MSG_DEBUG, caller, fline,
_("%s inode found at block "
- "0x%llx: marking as '%s'\n"),
+ "(0x%llx): marking as '%s'\n"),
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) {
+ if (prevcount) {
+ log_info("\n");
+ prevcount = 0;
+ }
print_fsck_log(MSG_DEBUG, caller, fline,
- _("inode 0x%llx references "
- "%s block 0x%llx: "
+ _("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));
} else {
+ if (prevcount) {
+ log_info("\n");
+ prevcount = 0;
+ }
print_fsck_log(MSG_DEBUG, caller, fline,
- _("inode 0x%llx references "
- "%s block 0x%llx: "
+ _("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));
}
+ 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.
@@ -698,7 +723,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 e017448..d89dd4f 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -73,7 +73,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;
@@ -90,8 +90,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, 8 months
gfs2-utils: master - libgfs2: Make rebuild functions not re-read ip
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: c692e1915869f17dc77d6b7de9982f0544604c7d
Parent: 7b21b2ceb7716e8c746f4ae4eb10dc7bcf6768a3
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Aug 19 15:57:03 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:55:37 2011 -0500
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 | 7 ++++++-
gfs2/libgfs2/fs_ops.c | 10 +++++-----
gfs2/libgfs2/structures.c | 4 ++--
gfs2/mkfs/main_mkfs.c | 2 ++
5 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index c255874..bef2ccd 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -2246,6 +2246,7 @@ int main(int argc, char **argv)
strerror(error));
exit(-1);
}
+ gfs2_lookupi(sb2.master_dir, "inum", 4, &sb2.md.inum);
/* Create the statfs file */
error = build_statfs(&sb2); /* Does not do inode_put */
if (error) {
@@ -2253,6 +2254,8 @@ int main(int argc, char **argv)
strerror(error));
exit(-1);
}
+ gfs2_lookupi(sb2.master_dir, "statfs", 6, &sb2.md.statfs);
+ do_init_statfs(&sb2);
/* Create the resource group index file */
error = build_rindex(&sb2);
diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c
index e2b1e63..8910103 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -422,13 +422,14 @@ static int rebuild_master(struct gfs2_sbd *sdp)
strerror(err));
exit(-1);
}
+ gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
}
if (fix_md.statfs) {
inum.no_formal_ino = sdp->md.next_inum++;
inum.no_addr = fix_md.statfs->i_di.di_num.no_addr;
err = dir_add(sdp->master_dir, "statfs", 6, &inum,
- IF2DT(S_IFREG | 0600));
+ IF2DT(S_IFREG | 0600));
if (err) {
log_crit(_("Error adding statfs inode: %s\n"), strerror(err));
exit(-1);
@@ -440,6 +441,7 @@ static int rebuild_master(struct gfs2_sbd *sdp)
strerror(err));
exit(-1);
}
+ gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
}
if (fix_md.riinode) {
@@ -479,6 +481,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;
}
@@ -704,6 +708,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 629729d..84cd895 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -1246,6 +1246,7 @@ static int 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);
return err;
}
@@ -1448,10 +1449,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);
@@ -1464,7 +1464,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 e8a8c65..7f21ad6 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -318,7 +318,7 @@ int build_inum(struct gfs2_sbd *sdp)
gfs2_dinode_print(&ip->i_di);
}
- sdp->md.inum = ip;
+ inode_put(&ip);
return 0;
}
@@ -337,7 +337,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 0da3bc5..d841daa 100644
--- a/gfs2/mkfs/main_mkfs.c
+++ b/gfs2/mkfs/main_mkfs.c
@@ -652,11 +652,13 @@ void main_mkfs(int argc, char *argv[])
fprintf(stderr, _("Error building inum inode: %s\n"), strerror(error));
exit(-1);
}
+ gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
error = build_statfs(sdp);
if (error) {
fprintf(stderr, _("Error building statfs inode: %s\n"), strerror(error));
exit(-1);
}
+ gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
error = build_rindex(sdp);
if (error) {
fprintf(stderr, _("Error building rindex inode: %s\n"), strerror(error));
12 years, 8 months
gfs2-utils: master - fsck.gfs2: Bad extended attributes not deleted properly
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 7b21b2ceb7716e8c746f4ae4eb10dc7bcf6768a3
Parent: d87cae562082f880678866df795e6fef5daf465a
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Aug 19 08:50:48 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:55:37 2011 -0500
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 | 57 +++++++++++++++++++++++++++++++++++++++----------
gfs2/fsck/pass1.c | 4 +--
gfs2/fsck/pass1c.c | 7 +++--
gfs2/fsck/pass2.c | 9 +++++--
4 files changed, 56 insertions(+), 21 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 3fc9e70..9feaa8a 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -754,6 +754,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;
@@ -806,13 +813,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 #%llu (0x%llx).\n"),
- (unsigned long long)block,
- (unsigned long long)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 +894,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;
}
@@ -1447,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 56f003b..8db8579 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 209c32d..26d47d5 100644
--- a/gfs2/fsck/pass1c.c
+++ b/gfs2/fsck/pass1c.c
@@ -65,9 +65,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 52763a2..e017448 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -207,9 +207,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 = {
@@ -347,7 +347,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, 8 months
gfs2-utils: master - fsck.gfs2: Handle duplicate reference to dinode blocks
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: d87cae562082f880678866df795e6fef5daf465a
Parent: 094731a8cd1d1d7bd436e0a604837bce81f6e6ff
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Aug 19 08:50:07 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:55:37 2011 -0500
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 9760279..56f003b 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 38f2aed..67e878c 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -15,10 +15,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;
@@ -350,6 +346,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;
@@ -377,19 +377,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)
@@ -399,9 +405,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]);
@@ -487,8 +494,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") : ""),
@@ -514,7 +520,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);
@@ -580,7 +586,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;
@@ -692,6 +703,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 f6dd292..ae9213f 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -12,9 +12,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)
{
@@ -455,3 +458,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, 8 months
gfs2-utils: master - fsck.gfs2: Remove bad inodes from duplicate tree
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 094731a8cd1d1d7bd436e0a604837bce81f6e6ff
Parent: 00788afba42a76c37d09c1bc35db92b0148863b9
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Aug 19 08:48:29 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:55:37 2011 -0500
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 dac51cf..3fc9e70 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -115,36 +115,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 c275b54..9760279 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, 8 months
gfs2-utils: master - fsck.gfs2: Add ability to check gfs1 file systems
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 00788afba42a76c37d09c1bc35db92b0148863b9
Parent: 75583f07f6a73bf36a4bfc29644f5ace912d95a9
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Thu Aug 11 14:51:08 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:55:37 2011 -0500
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 | 303 ++++++++++++++++++++++++++++++++++-----------
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 | 41 ++++---
gfs2/fsck/pass3.c | 41 +++++-
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, 825 insertions(+), 229 deletions(-)
diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c
index c6901d0..67aa441 100644
--- a/gfs2/fsck/fs_recovery.c
+++ b/gfs2/fsck/fs_recovery.c
@@ -631,7 +631,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");
@@ -642,24 +644,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 2d667fc..e2b1e63 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -11,6 +11,7 @@
#include <unistd.h>
#include <libintl.h>
#include <errno.h>
+#include <time.h>
#define _(String) gettext(String)
@@ -194,12 +195,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++){
@@ -247,8 +250,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]);
@@ -270,7 +275,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
@@ -539,7 +566,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) "))) {
@@ -558,7 +588,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) "))) {
@@ -582,7 +615,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]);
@@ -616,38 +649,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) "))) {
+ 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));
+ 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) "))) {
- err = build_statfs(sdp);
- if (err) {
- log_crit(_("Error rebuilding statfs inode: %s\n"),
- strerror(err));
- exit(-1);
- }
- } 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);
@@ -657,22 +712,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) "))) {
- err = build_quota(sdp);
- if (err) {
- log_crit(_("Error rebuilding quota inode: %s\n"),
- strerror(err));
- exit(-1);
- }
+ 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 *************
*******************************************************************/
@@ -785,13 +854,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);
@@ -827,7 +898,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;
@@ -869,7 +940,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) {
@@ -1004,7 +1075,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. */
@@ -1015,18 +1085,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
@@ -1153,6 +1211,8 @@ static int sb_repair(struct gfs2_sbd *sdp)
*/
static int fill_super_block(struct gfs2_sbd *sdp)
{
+ int ret;
+
sync();
/********************************************************************
@@ -1177,19 +1237,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;
}
@@ -1261,10 +1411,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,
@@ -1274,11 +1429,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 dbb2b58..2579480 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -31,7 +31,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 "
@@ -78,14 +78,54 @@ static void add_dotdot(struct gfs2_inode *ip)
log_warn( _("add_inode_to_lf: Unable to remove "
"\"..\" directory entry.\n"));
- err = dir_add(ip, "..", 2, &(lf_dip->i_di.di_num), DT_DIR);
+ err = dir_add(ip, "..", 2, &(lf_dip->i_di.di_num),
+ (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
if (err) {
log_crit(_("Error adding .. directory: %s\n"),
strerror(errno));
- exit(-1);
+ exit(FSCK_ERROR);
}
}
+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
* @ip: inode to add to lost + found
*
@@ -102,22 +142,33 @@ int add_inode_to_lf(struct gfs2_inode *ip){
struct gfs2_sbd *sdp = ip->i_sbd;
struct dir_info *di;
int err = 0;
+ 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(-1);
+ 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);
@@ -144,7 +195,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,
@@ -162,47 +215,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;
}
@@ -211,7 +269,7 @@ int add_inode_to_lf(struct gfs2_inode *ip){
if (err) {
log_crit(_("Error adding directory %s: %s\n"),
tmp_name, strerror(errno));
- exit(-1);
+ exit(FSCK_ERROR);
}
/* If the lf directory had new blocks added we have to mark them
properly in the bitmap so they're not freed. */
@@ -222,7 +280,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 52bc9a0..448f3b3 100644
--- a/gfs2/fsck/main.c
+++ b/gfs2/fsck/main.c
@@ -35,6 +35,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, ...)
@@ -155,6 +156,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);
@@ -340,16 +345,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 34e6192..dac51cf 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -42,17 +42,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
@@ -77,10 +79,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 {
@@ -170,9 +180,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
@@ -184,6 +213,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);
}
@@ -198,6 +229,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);
}
@@ -431,12 +464,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)
{
@@ -538,7 +572,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)
@@ -1073,7 +1107,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>) */
@@ -1081,12 +1115,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);
@@ -1177,7 +1214,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
@@ -1208,7 +1245,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++)
@@ -1224,7 +1261,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;
@@ -1267,7 +1304,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)) {
@@ -1438,7 +1478,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,
@@ -1457,7 +1497,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,
@@ -1475,7 +1515,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 e6a0235..c275b54 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1,5 +1,3 @@
-#include "clusterautoconfig.h"
-
/* pass1 checks inodes for format & type, duplicate blocks, & incorrect
* block count.
*
@@ -28,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;
@@ -176,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;
@@ -241,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);
@@ -250,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;
@@ -383,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 {
@@ -451,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;
@@ -528,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;
}
@@ -1022,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,
@@ -1114,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;
@@ -1134,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))
@@ -1144,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:
@@ -1198,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"),
@@ -1401,7 +1429,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;
@@ -1427,7 +1455,7 @@ static int build_a_journal(struct gfs2_sbd *sdp)
err = build_journal(sdp, sdp->md.journals, sdp->md.jiinode);
if (err) {
log_crit(_("Error building journal: %s\n"), strerror(err));
- exit(-1);
+ exit(FSCK_ERROR);
}
return 0;
}
@@ -1442,13 +1470,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. */
@@ -1459,7 +1489,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;
@@ -1470,7 +1501,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;
}
@@ -1484,7 +1515,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;
@@ -1492,6 +1524,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];
@@ -1531,6 +1578,8 @@ int pass1(struct gfs2_sbd *sdp)
uint64_t i;
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
@@ -1561,6 +1610,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
@@ -1574,13 +1624,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;
@@ -1596,7 +1658,35 @@ int pass1(struct gfs2_sbd *sdp)
}
bh = bread(sdp, block);
+ /*log_debug( _("Checking metadata block #%" PRIu64
+ " (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,
@@ -1605,6 +1695,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,
@@ -1612,6 +1703,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
@@ -1624,6 +1716,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 54e2d61..38f2aed 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -360,7 +360,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 */
@@ -696,7 +697,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 e2c6697..52763a2 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -123,31 +123,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:
@@ -395,7 +396,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 "
@@ -668,7 +669,9 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
memcpy(filename, tmp_name, filename_len);
log_warn( _("Adding '.' entry\n"));
error = 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 (error) {
log_err(_("Error adding directory %s: %s\n"),
filename, strerror(error));
@@ -715,8 +718,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;
@@ -746,19 +752,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;
}
@@ -880,7 +889,9 @@ int pass2(struct gfs2_sbd *sdp)
cur_blks = ip->i_di.di_blocks;
error = 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 (error) {
log_err(_("Error adding directory %s: %s\n"),
filename, strerror(error));
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index 1363606..f0b35e2 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -54,11 +54,12 @@ 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;
- err = dir_add(ip, filename, filename_len, &pip->i_di.di_num, DT_DIR);
+ err = dir_add(ip, filename, filename_len, &pip->i_di.di_num,
+ (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
if (err) {
log_err(_("Error adding directory %s: %s\n"),
filename, strerror(err));
- exit(-1);
+ exit(FSCK_ERROR);
}
if (cur_blks != ip->i_di.di_blocks) {
char dirname[80];
@@ -195,10 +196,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 556719a..80ecb38 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -58,6 +58,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 9cd4804..2a4ffbc 100644
--- a/gfs2/fsck/pass5.c
+++ b/gfs2/fsck/pass5.c
@@ -11,7 +11,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) {
@@ -37,10 +37,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);
}
@@ -71,7 +123,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
@@ -147,6 +202,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];
@@ -178,7 +234,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 */
@@ -189,7 +263,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"));
}
@@ -205,7 +282,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 864b880..cba1f7d 100644
--- a/gfs2/fsck/rgrepair.c
+++ b/gfs2/fsck/rgrepair.c
@@ -187,8 +187,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;
@@ -685,12 +690,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 7f529d6..b0c722f 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -724,6 +724,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 8b2c9d9..e8a8c65 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -502,39 +502,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, 8 months
gfs2-utils: master - fsck.gfs2: four-step duplicate elimination process
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 75583f07f6a73bf36a4bfc29644f5ace912d95a9
Parent: b012196c1ce46563d3377eef0701afae3d75260a
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Thu Aug 11 12:25:38 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:55:36 2011 -0500
fsck.gfs2: four-step duplicate elimination process
This patch reforms the duplicate block reference processing by
introducing a new four-step duplicate elimination process.
Step 1. Delete inodes that reference the block and were previously
marked invalid.
Step 2. Delete inodes that reference the block as the wrong block
type. (Data block referenced as metadata, or vise versa)
Step 3. Delete inodes until we're down to a single reference.
Step 4. Fix the block type to be according to the remaining reference.
rhbz#675723
---
gfs2/fsck/pass1b.c | 280 ++++++++++++++++++++++++++++++++++++----------------
1 files changed, 196 insertions(+), 84 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index cabf641..54e2d61 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -15,6 +15,10 @@
#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;
@@ -368,25 +372,38 @@ static int find_block_ref(struct gfs2_sbd *sdp, uint64_t inode)
return error;
}
+/* get_ref_type - figure out if all duplicate references from this 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 */
+}
+
static void log_inode_reference(struct duptree *b, osi_list_t *tmp, int inval)
{
char reftypestring[32];
struct inode_with_dups *id;
id = osi_list_entry(tmp, struct inode_with_dups, list);
- if (id->dup_count == 1) {
- if (id->reftypecount[ref_as_data])
- strcpy(reftypestring, "as data");
- else if (id->reftypecount[ref_as_meta])
- strcpy(reftypestring, "as metadata");
- else
- strcpy(reftypestring, "as extended attribute");
- } else {
+ if (id->dup_count == 1)
+ sprintf(reftypestring, "as %s", reftype_str[get_ref_type(id)]);
+ else
sprintf(reftypestring, "%d/%d/%d",
id->reftypecount[ref_as_data],
id->reftypecount[ref_as_meta],
id->reftypecount[ref_as_ea]);
- }
if (inval)
log_warn( _("Invalid "));
log_warn( _("Inode %s (%lld/0x%llx) has %d reference(s) to "
@@ -396,10 +413,22 @@ static void log_inode_reference(struct duptree *b, osi_list_t *tmp, int inval)
(unsigned long long)b->block,
(unsigned long long)b->block, reftypestring);
}
-
-static int clear_a_reference(struct gfs2_sbd *sdp, struct duptree *b,
- osi_list_t *ref_list, struct dup_handler *dh,
- int inval)
+/*
+ * resolve_dup_references - resolve all but the last dinode that has a
+ * duplicate reference to a given block.
+ *
+ * @sdp - pointer to the superblock structure
+ * @b - pointer to the duplicate reference rbtree to use
+ * @ref_list - list of duplicate references to be resolved (invalid or valid)
+ * @dh - duplicate handler
+ * inval - The references on this ref_list are invalid. We prefer to delete
+ * these first before resorting to deleting valid dinodes.
+ * acceptable_ref - Delete dinodes that reference the given block as anything
+ * _but_ this type. Try to save references as this type.
+ */
+static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
+ osi_list_t *ref_list, struct dup_handler *dh,
+ int inval, int acceptable_ref)
{
struct gfs2_inode *ip;
struct inode_with_dups *id;
@@ -415,26 +444,74 @@ static int clear_a_reference(struct gfs2_sbd *sdp, struct duptree *b,
.check_eattr_entry = clear_eattr_entry,
.check_eattr_extentry = clear_eattr_extentry,
};
+ enum dup_ref_type this_ref;
+ struct inode_info *ii;
+ int found_good_ref = 0;
osi_list_foreach_safe(tmp, ref_list, x) {
id = osi_list_entry(tmp, struct inode_with_dups, list);
dh->b = b;
dh->id = id;
+
if (dh->ref_inode_count == 1) /* down to the last reference */
return 1;
- if (!(query( _("Okay to clear %s inode %lld (0x%llx)? (y/n) "),
+
+ this_ref = get_ref_type(id);
+ if (inval)
+ log_warn( _("Invalid "));
+ /* FIXME: If we already found an acceptable reference to this
+ * block, we should really duplicate the block and fix all
+ * references to it in this inode. Unfortunately, we would
+ * have to traverse the entire metadata tree to do that. */
+ if (acceptable_ref != ref_types && /* If we're nuking all but
+ an acceptable reference
+ type and */
+ this_ref == acceptable_ref && /* this ref is acceptable */
+ !found_good_ref) { /* We haven't found a good reference */
+ uint8_t q;
+
+ /* If this is an invalid inode, but not on the invalid
+ list, it's better to delete it. */
+ q = block_type(id->block_no);
+ if (q != gfs2_inode_invalid) {
+ 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"),
+ id->name, (unsigned long long)id->block_no,
+ (unsigned long long)id->block_no,
+ (unsigned long long)b->block,
+ (unsigned long long)b->block,
+ reftype_str[this_ref],
+ reftype_str[acceptable_ref]);
+ if (!(query( _("Okay to delete %s inode %lld (0x%llx)? "
+ "(y/n) "),
(inval ? _("invalidated") : ""),
(unsigned long long)id->block_no,
(unsigned long long)id->block_no))) {
- log_warn( _("The bad inode was not cleared...\n"));
+ log_warn( _("The bad inode was not cleared."));
+ /* delete the list entry so we don't leak memory but
+ leave the reference count. If the decrement the
+ ref count, we could get down to 1 and the dinode
+ would be changed without a 'Yes' answer. */
+ /* (dh->ref_inode_count)--;*/
+ dup_listent_delete(id);
continue;
}
log_warn( _("Clearing inode %lld (0x%llx)...\n"),
(unsigned long long)id->block_no,
(unsigned long long)id->block_no);
+
+ ip = fsck_load_inode(sdp, id->block_no);
+ ii = inodetree_find(ip->i_di.di_num.no_addr);
+ if (ii)
+ inodetree_delete(ii);
clear_dup_fxns.private = (void *) dh;
/* Clear the EAs for the inode first */
- ip = fsck_load_inode(sdp, id->block_no);
check_inode_eattr(ip, &clear_dup_fxns);
/* If the dup wasn't only in the EA, clear the inode */
if (id->reftypecount[ref_as_data] ||
@@ -442,13 +519,14 @@ static int clear_a_reference(struct gfs2_sbd *sdp, struct duptree *b,
check_metatree(ip, &clear_dup_fxns);
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
- _("bad"), gfs2_inode_invalid);
+ _("duplicate referencing bad"),
+ gfs2_inode_invalid);
fsck_inode_put(&ip); /* out, brelse, free */
(dh->ref_inode_count)--;
- /* Inode is marked invalid and is removed in pass2 */
/* FIXME: other option should be to duplicate the
* block for each duplicate and point the metadata at
* the cloned blocks */
+ dup_listent_delete(id);
}
if (dh->ref_inode_count == 1) /* down to the last reference */
return 1;
@@ -461,19 +539,56 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
osi_list_t *tmp;
struct inode_with_dups *id;
struct dup_handler dh = {0};
- int last_reference, ref_in_invalid_inode = 0;
+ int last_reference = 0;
+ struct gfs2_buffer_head *bh;
+ uint32_t cmagic, ctype;
+ enum dup_ref_type acceptable_ref;
+ /* Count the duplicate references, both valid and invalid */
osi_list_foreach(tmp, &b->ref_invinode_list) {
id = osi_list_entry(tmp, struct inode_with_dups, list);
dh.ref_inode_count++;
dh.ref_count += id->dup_count;
- ref_in_invalid_inode = 1;
}
osi_list_foreach(tmp, &b->ref_inode_list) {
id = osi_list_entry(tmp, struct inode_with_dups, list);
dh.ref_inode_count++;
dh.ref_count += id->dup_count;
}
+
+ /* Log the duplicate references */
+ log_notice( _("Block %llu (0x%llx) has %d inodes referencing it"
+ " for a total of %d duplicate references:\n"),
+ (unsigned long long)b->block, (unsigned long long)b->block,
+ dh.ref_inode_count, dh.ref_count);
+
+ osi_list_foreach(tmp, &b->ref_invinode_list)
+ log_inode_reference(b, tmp, 1);
+ osi_list_foreach(tmp, &b->ref_inode_list)
+ log_inode_reference(b, tmp, 0);
+
+ /* Figure out the block type to see if we can eliminate references
+ to a different type. In other words, if the duplicate block looks
+ like metadata, we can delete dinodes that reference it as data.
+ If the block doesn't look like metadata, we can eliminate any
+ references to it as metadata. Dinodes with such references are
+ clearly corrupt and need to be deleted.
+ And if we're left with a single reference, problem solved. */
+ bh = bread(sdp, b->block);
+ cmagic = ((struct gfs2_meta_header *)(bh->b_data))->mh_magic;
+ ctype = ((struct gfs2_meta_header *)(bh->b_data))->mh_type;
+ brelse(bh);
+
+ 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;
+ else if (be32_to_cpu(cmagic) == GFS2_MAGIC &&
+ be32_to_cpu(ctype) <= GFS2_METATYPE_QC)
+ acceptable_ref = ref_as_meta;
+ else
+ acceptable_ref = ref_as_data;
+
/* A single reference to the block implies a possible situation where
a data pointer points to a metadata block. In other words, the
duplicate reference in the file system is (1) Metadata block X and
@@ -487,75 +602,71 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
invalidated for other reasons, such as bad pointers. So we need to
make sure at this point that any inode deletes reverse out any
duplicate reference before we get to this point. */
- if (dh.ref_count == 1) {
- struct gfs2_buffer_head *bh;
- uint32_t cmagic;
-
- bh = bread(sdp, b->block);
- cmagic = ((struct gfs2_meta_header *)(bh->b_data))->mh_magic;
- brelse(bh);
- if (be32_to_cpu(cmagic) == GFS2_MAGIC) {
- if (ref_in_invalid_inode)
- tmp = b->ref_invinode_list.next;
- else
- tmp = b->ref_inode_list.next;
- id = osi_list_entry(tmp, struct inode_with_dups, list);
- log_warn( _("Inode %s (%lld/0x%llx) has a reference to"
- " data block %llu (0x%llx), "
- "but the block is really metadata.\n"),
- id->name, (unsigned long long)id->block_no,
- (unsigned long long)id->block_no,
- (unsigned long long)b->block,
- (unsigned long long)b->block);
- if (query( _("Clear the inode? (y/n) "))) {
- struct inode_info *ii;
-
- log_warn( _("Clearing inode %lld (0x%llx)...\n"),
- (unsigned long long)id->block_no,
- (unsigned long long)id->block_no);
- ip = fsck_load_inode(sdp, id->block_no);
- ii = inodetree_find(ip->i_di.di_num.no_addr);
- if (ii)
- inodetree_delete(ii);
- /* Setting the block to invalid means the inode
- is cleared in pass2 */
- fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
- _("inode with bad duplicate"),
- gfs2_inode_invalid);
- fsck_inode_put(&ip);
- } else {
- log_warn( _("The bad inode was not cleared."));
- }
- return 0;
- }
- /* The other references may have been discredited due to
- invalid metadata or something. Use the last remaining. */
- log_notice( _("Block %llu (0x%llx) has only one remaining "
- "reference.\n"),
+ if (dh.ref_count == 1)
+ last_reference = 1;
+
+ /* Step 1 - eliminate references from inodes that are not valid.
+ * This may be because they were deleted due to corruption.
+ * All block types are unacceptable, so we use ref_types.
+ */
+ if (!last_reference) {
+ log_debug( _("----------------------------------------------\n"
+ "Step 1: Eliminate references to block %llu "
+ "(0x%llx) that were previously marked "
+ "invalid.\n"),
+ (unsigned long long)b->block,
+ (unsigned long long)b->block);
+ last_reference = resolve_dup_references(sdp, b,
+ &b->ref_invinode_list,
+ &dh, 1, ref_types);
+ }
+ /* Step 2 - eliminate reference from inodes that reference it as the
+ * wrong type. For example, a data file referencing it as
+ * a data block, but it's really a metadata block. Or a
+ * 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);
+ }
+ /* Step 3 - We have multiple dinodes referencing it as the correct
+ * type. Just blast one of them.
+ * All block types are fair game, so we use ref_types.
+ */
+ if (!last_reference) {
+ log_debug( _("----------------------------------------------\n"
+ "Step 3: Choose one reference to block %llu "
+ "(0x%llx) to keep.\n"),
+ (unsigned long long)b->block,
+ (unsigned long long)b->block);
+ last_reference = resolve_dup_references(sdp, b,
+ &b->ref_inode_list,
+ &dh, 0, ref_types);
+ }
+ /* Now fix the block type of the block in question. */
+ if (osi_list_empty(&b->ref_inode_list)) {
+ log_notice( _("Block %llu (0x%llx) has no more references; "
+ "Marking as 'free'.\n"),
(unsigned long long)b->block,
(unsigned long long)b->block);
+ gfs2_blockmap_set(bl, b->block, gfs2_block_free);
+ check_n_fix_bitmap(sdp, b->block, gfs2_block_free);
return 0;
}
-
- log_notice( _("Block %llu (0x%llx) has %d inodes referencing it"
- " for a total of %d duplicate references\n"),
- (unsigned long long)b->block, (unsigned long long)b->block,
- dh.ref_inode_count, dh.ref_count);
-
- osi_list_foreach(tmp, &b->ref_invinode_list)
- log_inode_reference(b, tmp, 1);
- osi_list_foreach(tmp, &b->ref_inode_list)
- log_inode_reference(b, tmp, 0);
-
- last_reference = clear_a_reference(sdp, b, &b->ref_invinode_list,
- &dh, 1);
- if (!last_reference)
- last_reference = clear_a_reference(sdp, b, &b->ref_inode_list,
- &dh, 0);
-
- if (last_reference && !osi_list_empty(&b->ref_inode_list)) {
+ if (last_reference) {
uint8_t q;
+ log_notice( _("Block %llu (0x%llx) has only one remaining "
+ "reference.\n"),
+ (unsigned long long)b->block,
+ (unsigned long long)b->block);
/* If we're down to a single reference (and not all references
deleted, which may be the case of an inode that has only
itself and a reference), we need to reset the block type
@@ -563,7 +674,8 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
in the list, not the structure's place holder. */
tmp = (&b->ref_inode_list)->next;
id = osi_list_entry(tmp, struct inode_with_dups, list);
- log_debug( _("Resetting the type based on the remaining "
+ log_debug( _("----------------------------------------------\n"
+ "Step 4. Set block type based on the remaining "
"reference in inode %lld (0x%llx).\n"),
(unsigned long long)id->block_no,
(unsigned long long)id->block_no);
12 years, 8 months
gfs2-utils: master - fsck.gfs2: Combine block and char device inode types
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: b012196c1ce46563d3377eef0701afae3d75260a
Parent: 69e10fb140f531c3c9f5208522e09638b7e09d3d
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Thu Aug 11 09:16:33 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:55:36 2011 -0500
fsck.gfs2: Combine block and char device inode types
This patch combines the block and character device block designations.
Devices are now treated equally as one block type, which is fine.
This buys back a block type in the block map which may be used later
for gfs1 support. It also eliminates the rgrp block designation,
which is not needed: We only need to know whether rgrp blocks are
"in use" or not. In fact, the rgrp blocks have special processing
anyway and special code (function valid_block) to check for overlaps.
rhbz#675723
---
gfs2/fsck/pass1.c | 6 +++---
gfs2/fsck/pass2.c | 8 ++------
gfs2/fsck/pass3.c | 5 ++---
gfs2/fsck/pass4.c | 3 +--
gfs2/fsck/pass5.c | 4 +---
gfs2/fsck/util.h | 50 +++++++++++++++++++++++++-------------------------
6 files changed, 34 insertions(+), 42 deletions(-)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 8cbda72..e6a0235 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1155,12 +1155,12 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
break;
case S_IFBLK:
if (fsck_blockmap_set(ip, block, _("block device"),
- gfs2_inode_blk))
+ gfs2_inode_device))
goto bad_dinode;
break;
case S_IFCHR:
if (fsck_blockmap_set(ip, block, _("character device"),
- gfs2_inode_chr))
+ gfs2_inode_device))
goto bad_dinode;
break;
case S_IFIFO:
@@ -1559,7 +1559,7 @@ int pass1(struct gfs2_sbd *sdp)
"is now marked as 'rgrp data'\n"),
rgd->ri.ri_addr + i, rgd->ri.ri_addr + i);
if (gfs2_blockmap_set(bl, rgd->ri.ri_addr + i,
- gfs2_meta_rgrp)) {
+ gfs2_indir_blk)) {
stack;
return FSCK_ERROR;
}
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 83172af..e2c6697 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -138,12 +138,8 @@ static int check_file_type(uint8_t de_type, uint8_t blk_type)
if (de_type != DT_LNK)
return 1;
break;
- case gfs2_inode_blk:
- if (de_type != DT_BLK)
- return 1;
- break;
- case gfs2_inode_chr:
- if (de_type != DT_CHR)
+ case gfs2_inode_device:
+ if (de_type != DT_BLK && de_type != DT_CHR)
return 1;
break;
case gfs2_inode_fifo:
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index a34dd36..1363606 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -247,9 +247,8 @@ int pass3(struct gfs2_sbd *sdp)
log_err( _("Unlinked directory with bad block remains\n"));
}
if (q != gfs2_inode_dir && q != gfs2_inode_file &&
- q != gfs2_inode_lnk && q != gfs2_inode_blk &&
- q != gfs2_inode_chr && q != gfs2_inode_fifo &&
- q != gfs2_inode_sock) {
+ q != gfs2_inode_lnk && q != gfs2_inode_device &&
+ q != gfs2_inode_fifo && q != gfs2_inode_sock) {
log_err( _("Unlinked block marked as an inode "
"is not an inode\n"));
if (!query(_("Clear the unlinked block?"
diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c
index 0614372..556719a 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -85,8 +85,7 @@ static int scan_inode_list(struct gfs2_sbd *sdp) {
if (q != gfs2_inode_dir &&
q != gfs2_inode_file &&
q != gfs2_inode_lnk &&
- q != gfs2_inode_blk &&
- q != gfs2_inode_chr &&
+ q != gfs2_inode_device &&
q != gfs2_inode_fifo &&
q != gfs2_inode_sock) {
log_err( _("Unlinked block %lld (0x%llx) "
diff --git a/gfs2/fsck/pass5.c b/gfs2/fsck/pass5.c
index 191935f..9cd4804 100644
--- a/gfs2/fsck/pass5.c
+++ b/gfs2/fsck/pass5.c
@@ -29,8 +29,7 @@ static int convert_mark(uint8_t q, uint32_t *count)
case gfs2_inode_dir:
case gfs2_inode_file:
case gfs2_inode_lnk:
- case gfs2_inode_blk:
- case gfs2_inode_chr:
+ case gfs2_inode_device:
case gfs2_inode_fifo:
case gfs2_inode_sock:
count[1]++;
@@ -38,7 +37,6 @@ static int convert_mark(uint8_t q, uint32_t *count)
case gfs2_indir_blk:
case gfs2_leaf_blk:
- case gfs2_meta_rgrp:
case gfs2_meta_eattr:
count[2]++;
return GFS2_BLKST_USED;
diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h
index b26c123..106cca8 100644
--- a/gfs2/fsck/util.h
+++ b/gfs2/fsck/util.h
@@ -42,15 +42,15 @@ enum gfs2_mark_block {
gfs2_inode_file = (0x4),
gfs2_inode_lnk = (0x5),
- gfs2_inode_blk = (0x6),
- gfs2_inode_chr = (0x7),
+ gfs2_inode_device = (0x6),
+
gfs2_inode_fifo = (0x8),
gfs2_inode_sock = (0x9),
gfs2_inode_invalid = (0xa),
gfs2_meta_inval = (0xb),
gfs2_leaf_blk = (0xc),
- gfs2_meta_rgrp = (0xd),
+
gfs2_meta_eattr = (0xe),
gfs2_bad_block = (0xf), /* Contains at least one bad block */
@@ -66,15 +66,15 @@ static const inline char *block_type_string(uint8_t q)
"file",
"symlink",
- "block device",
- "char device",
+ "device",
+ "",
"fifo",
"socket",
"invalid inode",
"invalid meta",
"dir leaf",
- "rgrp meta",
+ "",
"eattribute",
"bad"};
@@ -88,25 +88,25 @@ static const inline char *block_type_string(uint8_t q)
static inline int blockmap_to_bitmap(enum gfs2_mark_block m)
{
static int bitmap_states[16] = {
- GFS2_BLKST_FREE,
- GFS2_BLKST_USED,
- GFS2_BLKST_USED,
- GFS2_BLKST_DINODE,
- GFS2_BLKST_DINODE,
-
- GFS2_BLKST_DINODE,
- GFS2_BLKST_DINODE,
- GFS2_BLKST_DINODE,
- GFS2_BLKST_DINODE,
- GFS2_BLKST_DINODE,
-
- GFS2_BLKST_FREE,
- GFS2_BLKST_FREE,
- GFS2_BLKST_USED,
- GFS2_BLKST_USED,
- GFS2_BLKST_USED,
-
- GFS2_BLKST_USED
+ 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];
}
12 years, 8 months
gfs2-utils: master - libgfs2: expand capabilities to operate on gfs1
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 69e10fb140f531c3c9f5208522e09638b7e09d3d
Parent: 3acf36d2b12572711ba83fea6fde7f7b7ffe8242
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Aug 10 16:28:02 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:55:36 2011 -0500
libgfs2: expand capabilities to operate on gfs1
This patch expands many of the libgfs2 functions so that they may
operate on gfs1 file systems, depending on the sdp->gfs1 variable.
rhbz#675723
---
gfs2/libgfs2/fs_ops.c | 113 +++++++++++++++++++++++++++++++++++--------
gfs2/libgfs2/gfs1.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++
gfs2/libgfs2/libgfs2.h | 19 +++++++-
gfs2/libgfs2/ondisk.c | 10 +++-
gfs2/libgfs2/rgrp.c | 9 ++-
5 files changed, 250 insertions(+), 27 deletions(-)
diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c
index 4c8d31e..629729d 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -179,7 +179,10 @@ found:
rg->rg_free--;
bmodified(bh);
- gfs2_rgrp_out(rg, rl->bh[0]);
+ if (sdp->gfs1)
+ gfs_rgrp_out((struct gfs_rgrp *)rg, rl->bh[0]);
+ else
+ gfs2_rgrp_out(rg, rl->bh[0]);
sdp->blks_alloced++;
return ri->ri_data0 + bn;
@@ -233,7 +236,7 @@ void unstuff_dinode(struct gfs2_inode *ip)
struct gfs2_sbd *sdp = ip->i_sbd;
struct gfs2_buffer_head *bh;
uint64_t block = 0;
- int isdir = !!(S_ISDIR(ip->i_di.di_mode));
+ int isdir = S_ISDIR(ip->i_di.di_mode) || is_gfs_dir(&ip->i_di);
if (ip->i_di.di_size) {
if (isdir) {
@@ -830,6 +833,8 @@ void gfs2_get_leaf_nr(struct gfs2_inode *dip, uint32_t lindex,
uint64_t leaf_no;
int count;
+ if (dip->i_sbd->gfs1)
+ return gfs_get_leaf_nr(dip, lindex, leaf_out);
count = gfs2_readi(dip, (char *)&leaf_no, lindex * sizeof(uint64_t),
sizeof(uint64_t));
if (count != sizeof(uint64_t))
@@ -843,6 +848,10 @@ void gfs2_put_leaf_nr(struct gfs2_inode *dip, uint32_t inx, uint64_t leaf_out)
uint64_t leaf_no;
int count;
+ if (dip->i_sbd->gfs1) {
+ gfs_put_leaf_nr(dip, inx, leaf_out);
+ return;
+ }
leaf_no = cpu_to_be64(leaf_out);
count = gfs2_writei(dip, (char *)&leaf_no, inx * sizeof(uint64_t),
sizeof(uint64_t));
@@ -893,8 +902,12 @@ static void dir_split_leaf(struct gfs2_inode *dip, uint32_t lindex,
for (x = 0; x < half_len; x++)
lp[x] = cpu_to_be64(bn);
- count = gfs2_writei(dip, (char *)lp, start * sizeof(uint64_t),
- half_len * sizeof(uint64_t));
+ if (dip->i_sbd->gfs1)
+ count = gfs1_writei(dip, (char *)lp, start * sizeof(uint64_t),
+ half_len * sizeof(uint64_t));
+ else
+ count = gfs2_writei(dip, (char *)lp, start * sizeof(uint64_t),
+ half_len * sizeof(uint64_t));
if (count != half_len * sizeof(uint64_t))
die("dir_split_leaf (2)\n");
@@ -985,8 +998,14 @@ static void dir_double_exhash(struct gfs2_inode *dip)
*to++ = *from;
}
- count = gfs2_writei(dip, (char *)buf + sdp->sd_hash_bsize,
- block * sdp->bsize, sdp->bsize);
+ if (sdp->gfs1)
+ count = gfs1_writei(dip, (char *)buf +
+ sdp->sd_hash_bsize,
+ block * sdp->bsize, sdp->bsize);
+ else
+ count = gfs2_writei(dip, (char *)buf +
+ sdp->sd_hash_bsize,
+ block * sdp->bsize, sdp->bsize);
if (count != sdp->bsize)
die("dir_double_exhash (2)\n");
@@ -1241,13 +1260,21 @@ int dir_add(struct gfs2_inode *dip, const char *filename, int len,
return err;
}
-struct gfs2_buffer_head *init_dinode(struct gfs2_sbd *sdp,
- struct gfs2_inum *inum, unsigned int mode,
- uint32_t flags, struct gfs2_inum *parent)
+static struct gfs2_buffer_head *__init_dinode(struct gfs2_sbd *sdp,
+ struct gfs2_inum *inum,
+ unsigned int mode,
+ uint32_t flags,
+ struct gfs2_inum *parent,
+ int gfs1)
{
struct gfs2_buffer_head *bh;
struct gfs2_dinode di;
+ int is_dir;
+ if (gfs1)
+ is_dir = (IF2DT(mode) == GFS_FILE_DIR);
+ else
+ is_dir = S_ISDIR(mode);
bh = bget(sdp, inum->no_addr);
memset(&di, 0, sizeof(struct gfs2_dinode));
@@ -1262,7 +1289,7 @@ struct gfs2_buffer_head *init_dinode(struct gfs2_sbd *sdp,
di.di_goal_meta = di.di_goal_data = bh->b_blocknr;
di.di_flags = flags;
- if (S_ISDIR(mode)) {
+ if (is_dir) {
struct gfs2_dirent de1, de2;
memset(&de1, 0, sizeof(struct gfs2_dirent));
@@ -1270,14 +1297,14 @@ struct gfs2_buffer_head *init_dinode(struct gfs2_sbd *sdp,
de1.de_hash = gfs2_disk_hash(".", 1);
de1.de_rec_len = GFS2_DIRENT_SIZE(1);
de1.de_name_len = 1;
- de1.de_type = IF2DT(S_IFDIR);
+ de1.de_type = (gfs1 ? GFS_FILE_DIR : IF2DT(S_IFDIR));
memset(&de2, 0, sizeof(struct gfs2_dirent));
de2.de_inum = *parent;
de2.de_hash = gfs2_disk_hash("..", 2);
de2.de_rec_len = sdp->bsize - sizeof(struct gfs2_dinode) - de1.de_rec_len;
de2.de_name_len = 2;
- de2.de_type = IF2DT(S_IFDIR);
+ de2.de_type = (gfs1 ? GFS_FILE_DIR : IF2DT(S_IFDIR));
gfs2_dirent_out(&de1, bh->b_data + sizeof(struct gfs2_dinode));
memcpy(bh->b_data +
@@ -1303,8 +1330,25 @@ struct gfs2_buffer_head *init_dinode(struct gfs2_sbd *sdp,
return bh;
}
-struct gfs2_inode *createi(struct gfs2_inode *dip, const char *filename,
- unsigned int mode, uint32_t flags)
+struct gfs2_buffer_head *init_dinode(struct gfs2_sbd *sdp,
+ struct gfs2_inum *inum,
+ unsigned int mode, uint32_t flags,
+ struct gfs2_inum *parent)
+{
+ return __init_dinode(sdp, inum, mode, flags, parent, 0);
+}
+
+struct gfs2_buffer_head *init_gfs_dinode(struct gfs2_sbd *sdp,
+ struct gfs2_inum *inum,
+ unsigned int mode, uint32_t flags,
+ struct gfs2_inum *parent)
+{
+ return __init_dinode(sdp, inum, mode, flags, parent, 1);
+}
+
+static struct gfs2_inode *__createi(struct gfs2_inode *dip,
+ const char *filename, unsigned int mode,
+ uint32_t flags, int if_gfs1)
{
struct gfs2_sbd *sdp = dip->i_sbd;
uint64_t bn;
@@ -1312,12 +1356,16 @@ struct gfs2_inode *createi(struct gfs2_inode *dip, const char *filename,
struct gfs2_buffer_head *bh;
struct gfs2_inode *ip;
int err = 0;
+ int is_dir;
gfs2_lookupi(dip, filename, strlen(filename), &ip);
if (!ip) {
bn = dinode_alloc(sdp);
- inum.no_formal_ino = sdp->md.next_inum++;
+ if (if_gfs1)
+ inum.no_formal_ino = bn;
+ else
+ inum.no_formal_ino = sdp->md.next_inum++;
inum.no_addr = bn;
err = dir_add(dip, filename, strlen(filename), &inum, IF2DT(mode));
@@ -1326,12 +1374,17 @@ struct gfs2_inode *createi(struct gfs2_inode *dip, const char *filename,
return NULL;
}
- if(S_ISDIR(mode)) {
+ if (if_gfs1)
+ is_dir = (IF2DT(mode) == GFS_FILE_DIR);
+ else
+ is_dir = S_ISDIR(mode);
+ if (is_dir) {
bmodified(dip->i_bh);
dip->i_di.di_nlink++;
}
- bh = init_dinode(sdp, &inum, mode, flags, &dip->i_di.di_num);
+ bh = __init_dinode(sdp, &inum, mode, flags, &dip->i_di.di_num,
+ if_gfs1);
ip = inode_get(sdp, bh);
bmodified(bh);
}
@@ -1339,6 +1392,18 @@ struct gfs2_inode *createi(struct gfs2_inode *dip, const char *filename,
return ip;
}
+struct gfs2_inode *createi(struct gfs2_inode *dip, const char *filename,
+ unsigned int mode, uint32_t flags)
+{
+ return __createi(dip, filename, mode, flags, 0);
+}
+
+struct gfs2_inode *gfs_createi(struct gfs2_inode *dip, const char *filename,
+ unsigned int mode, uint32_t flags)
+{
+ return __createi(dip, filename, mode, flags, 1);
+}
+
/**
* gfs2_filecmp - Compare two filenames
* @file1: The first filename
@@ -1552,7 +1617,7 @@ int dir_search(struct gfs2_inode *dip, const char *filename, int len,
{
int error;
- if(!S_ISDIR(dip->i_di.di_mode))
+ if(!S_ISDIR(dip->i_di.di_mode) && !is_gfs_dir(&dip->i_di))
return -1;
if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
@@ -1638,7 +1703,7 @@ int gfs2_dirent_del(struct gfs2_inode *dip, const char *filename, int len)
{
int error;
- if(!S_ISDIR(dip->i_di.di_mode))
+ if(!S_ISDIR(dip->i_di.di_mode) && !is_gfs_dir(&dip->i_di))
return -1;
if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
@@ -1695,7 +1760,10 @@ void gfs2_free_block(struct gfs2_sbd *sdp, uint64_t block)
if (rgd) {
gfs2_set_bitmap(sdp, block, GFS2_BLKST_FREE);
rgd->rg.rg_free++; /* adjust the free count */
- gfs2_rgrp_out(&rgd->rg, rgd->bh[0]); /* back to the buffer */
+ if (sdp->gfs1)
+ gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bh[0]);
+ else
+ gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
sdp->blks_alloced--;
}
}
@@ -1759,7 +1827,10 @@ int gfs2_freedi(struct gfs2_sbd *sdp, uint64_t diblock)
rgd = gfs2_blk2rgrpd(sdp, diblock);
rgd->rg.rg_free++;
rgd->rg.rg_dinodes--; /* one less inode in use */
- 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]);
sdp->dinodes_alloced--;
return 0;
}
diff --git a/gfs2/libgfs2/gfs1.c b/gfs2/libgfs2/gfs1.c
index 394cc47..2bd5282 100644
--- a/gfs2/libgfs2/gfs1.c
+++ b/gfs2/libgfs2/gfs1.c
@@ -6,6 +6,7 @@
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
+#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -33,6 +34,13 @@ gfs1_metapointer(struct gfs2_buffer_head *bh, unsigned int height,
return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height];
}
+int is_gfs_dir(struct gfs2_dinode *dinode)
+{
+ if (dinode->__pad1 == GFS_FILE_DIR)
+ return 1;
+ return 0;
+}
+
void gfs1_lookup_block(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
unsigned int height, struct metapath *mp,
int create, int *new, uint64_t *block)
@@ -161,6 +169,98 @@ void gfs1_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
free(mp);
}
+int gfs1_writei(struct gfs2_inode *ip, char *buf, uint64_t offset,
+ unsigned int size)
+{
+ struct gfs2_sbd *sdp = ip->i_sbd;
+ struct gfs2_buffer_head *bh;
+ uint64_t lblock, dblock;
+ uint32_t extlen = 0;
+ unsigned int amount;
+ int new;
+ int journaled = fs_is_jdata(ip);
+ const uint64_t start = offset;
+ int copied = 0;
+ int error = 0;
+
+ if (!size)
+ goto fail; /* Not really an error */
+
+
+ if (!ip->i_di.di_height && /* stuffed */
+ ((start + size) > (sdp->bsize - sizeof(struct gfs_dinode))))
+ unstuff_dinode(ip);
+
+ if (journaled) {
+ lblock = offset / sdp->sd_jbsize;
+ offset %= sdp->sd_jbsize;
+ } else {
+ lblock = offset >> sdp->sd_sb.sb_bsize_shift;
+ offset &= sdp->bsize - 1;
+ }
+
+ if (!ip->i_di.di_height) /* stuffed */
+ offset += sizeof(struct gfs_dinode);
+ else if (journaled)
+ offset += sizeof(struct gfs2_meta_header);
+
+ while (copied < size) {
+ amount = size - copied;
+ if (amount > sdp->bsize - offset)
+ amount = sdp->bsize - offset;
+
+ if (!extlen){
+ new = TRUE;
+ gfs1_block_map(ip, lblock, &new, &dblock, &extlen, 0);
+ if (!dblock)
+ return -1;
+ }
+
+ if (dblock == ip->i_di.di_num.no_addr)
+ bh = ip->i_bh;
+ else
+ bh = bread(sdp, dblock);
+
+ if (journaled && dblock != ip->i_di.di_num.no_addr ) {
+ struct gfs2_meta_header mh;
+
+ mh.mh_magic = GFS2_MAGIC;
+ mh.mh_type = GFS2_METATYPE_JD;
+ mh.mh_format = GFS2_FORMAT_JD;
+ gfs2_meta_header_out(&mh, bh);
+ }
+
+ memcpy(bh->b_data + offset, buf + copied, amount);
+ bmodified(bh);
+ if (bh != ip->i_bh)
+ brelse(bh);
+
+ copied += amount;
+ lblock++;
+ dblock++;
+ extlen--;
+
+ offset = (journaled) ? sizeof(struct gfs2_meta_header) : 0;
+ }
+
+ out:
+ if (ip->i_di.di_size < start + copied) {
+ bmodified(ip->i_bh);
+ ip->i_di.di_size = start + copied;
+ }
+ ip->i_di.di_mtime = ip->i_di.di_ctime = time(NULL);
+
+ gfs2_dinode_out(&ip->i_di, ip->i_bh);
+
+ return copied;
+
+ fail:
+ if (copied)
+ goto out;
+
+ return error;
+}
+
/* ------------------------------------------------------------------------ */
/* gfs_dinode_in */
/* ------------------------------------------------------------------------ */
@@ -303,3 +403,29 @@ void gfs_rgrp_out(struct gfs_rgrp *rgrp, struct gfs2_buffer_head *rbh)
memcpy(str->rg_reserved, rgrp->rg_reserved, 64);
bmodified(rbh);
}
+
+void gfs_get_leaf_nr(struct gfs2_inode *dip, uint32_t lindex,
+ uint64_t *leaf_out)
+{
+ uint64_t leaf_no;
+ int count;
+
+ count = gfs2_readi(dip, (char *)&leaf_no, lindex * sizeof(uint64_t),
+ sizeof(uint64_t));
+ if (count != sizeof(uint64_t))
+ die("gfs_get_leaf_nr: Bad internal read.\n");
+
+ *leaf_out = be64_to_cpu(leaf_no);
+}
+
+void gfs_put_leaf_nr(struct gfs2_inode *dip, uint32_t inx, uint64_t leaf_out)
+{
+ uint64_t leaf_no;
+ int count;
+
+ leaf_no = cpu_to_be64(leaf_out);
+ count = gfs1_writei(dip, (char *)&leaf_no, inx * sizeof(uint64_t),
+ sizeof(uint64_t));
+ if (count != sizeof(uint64_t))
+ die("gfs_put_leaf_nr: Bad internal write.\n");
+}
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index c92781a..7f529d6 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -176,6 +176,7 @@ struct gfs2_sbd {
unsigned int bsize; /* The block size of the FS (in bytes) */
unsigned int jsize; /* Size of journals (in MB) */
unsigned int rgsize; /* Size of resource groups (in MB) */
+ unsigned int utsize; /* Size of unlinked tag files (in MB) */
unsigned int qcsize; /* Size of quota change files (in MB) */
int debug;
@@ -254,6 +255,7 @@ struct metapath {
#define GFS2_DEFAULT_BSIZE (4096)
#define GFS2_DEFAULT_JSIZE (128)
#define GFS2_DEFAULT_RGSIZE (256)
+#define GFS2_DEFAULT_UTSIZE (1)
#define GFS2_DEFAULT_QCSIZE (1)
#define GFS2_DEFAULT_LOCKPROTO "lock_dlm"
#define GFS2_MIN_GROW_SIZE (10)
@@ -370,8 +372,16 @@ extern struct gfs2_buffer_head *init_dinode(struct gfs2_sbd *sdp,
struct gfs2_inum *inum,
unsigned int mode, uint32_t flags,
struct gfs2_inum *parent);
+extern struct gfs2_buffer_head *init_gfs_dinode(struct gfs2_sbd *sdp,
+ struct gfs2_inum *inum,
+ unsigned int mode,
+ uint32_t flags,
+ struct gfs2_inum *parent);
extern struct gfs2_inode *createi(struct gfs2_inode *dip, const char *filename,
unsigned int mode, uint32_t flags);
+extern struct gfs2_inode *gfs_createi(struct gfs2_inode *dip,
+ const char *filename, unsigned int mode,
+ uint32_t flags);
extern void dirent2_del(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
struct gfs2_dirent *prev, struct gfs2_dirent *cur);
extern int dir_search(struct gfs2_inode *dip, const char *filename, int len,
@@ -581,13 +591,15 @@ struct gfs_log_descriptor {
char ld_reserved[64];
};
+extern int is_gfs_dir(struct gfs2_dinode *dinode);
extern void gfs1_lookup_block(struct gfs2_inode *ip,
struct gfs2_buffer_head *bh,
unsigned int height, struct metapath *mp,
int create, int *new, uint64_t *block);
extern void gfs1_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
uint64_t *dblock, uint32_t *extlen, int prealloc);
-extern int gfs1_rindex_read(struct gfs2_sbd *sdp, int fd, int *count1);
+extern int gfs1_writei(struct gfs2_inode *ip, char *buf, uint64_t offset,
+ unsigned int size);
extern int gfs1_ri_update(struct gfs2_sbd *sdp, int fd, int *rgcount, int quiet);
extern struct gfs2_inode *gfs_inode_get(struct gfs2_sbd *sdp,
struct gfs2_buffer_head *bh);
@@ -596,6 +608,10 @@ extern struct gfs2_inode *gfs_inode_read(struct gfs2_sbd *sdp,
extern void gfs_jindex_in(struct gfs_jindex *jindex, char *buf);
extern void gfs_rgrp_in(struct gfs_rgrp *rg, struct gfs2_buffer_head *bh);
extern void gfs_rgrp_out(struct gfs_rgrp *rg, struct gfs2_buffer_head *bh);
+extern void gfs_get_leaf_nr(struct gfs2_inode *dip, uint32_t lindex,
+ uint64_t *leaf_out);
+extern void gfs_put_leaf_nr(struct gfs2_inode *dip, uint32_t inx,
+ uint64_t leaf_out);
/* gfs2_log.c */
struct gfs2_options {
@@ -684,6 +700,7 @@ extern int clean_journal(struct gfs2_inode *ip, struct gfs2_log_header *head);
/* rgrp.c */
extern int gfs2_compute_bitstructs(struct gfs2_sbd *sdp, struct rgrp_list *rgd);
extern struct rgrp_list *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, uint64_t blk);
+extern uint64_t __gfs2_rgrp_read(struct gfs2_sbd *sdp, struct rgrp_list *rgd);
extern uint64_t gfs2_rgrp_read(struct gfs2_sbd *sdp, struct rgrp_list *rgd);
extern void gfs2_rgrp_relse(struct rgrp_list *rgd);
extern void gfs2_rgrp_free(osi_list_t *rglist);
diff --git a/gfs2/libgfs2/ondisk.c b/gfs2/libgfs2/ondisk.c
index d889e2b..adbf4e9 100644
--- a/gfs2/libgfs2/ondisk.c
+++ b/gfs2/libgfs2/ondisk.c
@@ -100,15 +100,20 @@ void gfs2_sb_in(struct gfs2_sb *sb, struct gfs2_buffer_head *bh)
CPIN_32(sb, str, sb_fs_format);
CPIN_32(sb, str, sb_multihost_format);
+ CPIN_32(sb, str, __pad0); /* gfs sb_flags */
CPIN_32(sb, str, sb_bsize);
CPIN_32(sb, str, sb_bsize_shift);
+ CPIN_32(sb, str, __pad1); /* gfs sb_seg_size */
gfs2_inum_in(&sb->sb_master_dir, (char *)&str->sb_master_dir);
gfs2_inum_in(&sb->sb_root_dir, (char *)&str->sb_root_dir);
CPIN_08(sb, str, sb_lockproto, GFS2_LOCKNAME_LEN);
CPIN_08(sb, str, sb_locktable, GFS2_LOCKNAME_LEN);
+ gfs2_inum_in(&sb->__pad2, (char *)&str->__pad2); /* gfs rindex */
+ gfs2_inum_in(&sb->__pad3, (char *)&str->__pad3); /* gfs quota */
+ gfs2_inum_in(&sb->__pad4, (char *)&str->__pad4); /* gfs license */
#ifdef GFS2_HAS_UUID
CPIN_08(sb, str, sb_uuid, sizeof(sb->sb_uuid));
#endif
@@ -235,7 +240,7 @@ void gfs2_rgrp_in(struct gfs2_rgrp *rg, struct gfs2_buffer_head *bh)
CPIN_32(rg, str, rg_free);
CPIN_32(rg, str, rg_dinodes);
- CPIN_08(rg, str, rg_reserved, 36);
+ CPIN_08(rg, str, rg_reserved, 80);
}
void gfs2_rgrp_out(struct gfs2_rgrp *rg, struct gfs2_buffer_head *bh)
@@ -247,7 +252,7 @@ void gfs2_rgrp_out(struct gfs2_rgrp *rg, struct gfs2_buffer_head *bh)
CPOUT_32(rg, str, rg_free);
CPOUT_32(rg, str, rg_dinodes);
- CPOUT_08(rg, str, rg_reserved, 36);
+ CPOUT_08(rg, str, rg_reserved, 80);
bmodified(bh);
}
@@ -345,6 +350,7 @@ void gfs2_dinode_out(struct gfs2_dinode *di, struct gfs2_buffer_head *bh)
CPOUT_32(di, str, di_flags);
CPOUT_32(di, str, di_payload_format);
+ CPOUT_16(di, str, __pad1);
CPOUT_16(di, str, di_height);
CPOUT_16(di, str, di_depth);
diff --git a/gfs2/libgfs2/rgrp.c b/gfs2/libgfs2/rgrp.c
index 2ec55b5..97f22bb 100644
--- a/gfs2/libgfs2/rgrp.c
+++ b/gfs2/libgfs2/rgrp.c
@@ -158,9 +158,12 @@ uint64_t gfs2_rgrp_read(struct gfs2_sbd *sdp, struct rgrp_list *rgd)
return error;
}
}
-
- if (rgd->bh && rgd->bh[0])
- gfs2_rgrp_in(&rgd->rg, rgd->bh[0]);
+ if (rgd->bh && rgd->bh[0]) {
+ if (sdp->gfs1)
+ gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg, rgd->bh[0]);
+ else
+ gfs2_rgrp_in(&rgd->rg, rgd->bh[0]);
+ }
return 0;
}
12 years, 8 months