[Cluster-devel] [PATCH 44/66] fsck.gfs2: Add ability to check gfs1 file systems
rpeterso at redhat.com
rpeterso at redhat.com
Fri Jan 20 15:10:25 UTC 2012
From: Bob Peterson <rpeterso at redhat.com>
This patch gives fsck.gfs2 the ability to check GFS1 file systems.
rhbz#675723
---
gfs2/fsck/fs_recovery.c | 37 ++++--
gfs2/fsck/fsck.h | 3 +
gfs2/fsck/initialize.c | 302 +++++++++++++++++++++++++++++++++++----------
gfs2/fsck/lost_n_found.c | 96 ++++++++++++---
gfs2/fsck/main.c | 14 ++-
gfs2/fsck/metawalk.c | 90 ++++++++++----
gfs2/fsck/pass1.c | 167 +++++++++++++++++++++-----
gfs2/fsck/pass1b.c | 5 +-
gfs2/fsck/pass2.c | 40 ++++---
gfs2/fsck/pass3.c | 39 +++++-
gfs2/fsck/pass4.c | 7 +
gfs2/fsck/pass5.c | 87 ++++++++++++-
gfs2/fsck/rgrepair.c | 20 +++-
gfs2/fsck/util.h | 111 ++++++++++++-----
gfs2/libgfs2/libgfs2.h | 3 +
gfs2/libgfs2/structures.c | 29 +++--
16 files changed, 836 insertions(+), 214 deletions(-)
diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c
index 8e29167..907e37f 100644
--- a/gfs2/fsck/fs_recovery.c
+++ b/gfs2/fsck/fs_recovery.c
@@ -629,7 +629,9 @@ int ji_update(struct gfs2_sbd *sdp)
{
struct gfs2_inode *jip, *ip = sdp->md.jiinode;
char journal_name[JOURNAL_NAME_SIZE];
- int i;
+ int i, error;
+ char buf[sizeof(struct gfs_jindex)];
+ struct gfs_jindex ji;
if (!ip) {
log_crit("Journal index inode not found.\n");
@@ -640,24 +642,41 @@ int ji_update(struct gfs2_sbd *sdp)
plus two for "." and "..". So we subtract the 2 and divide by 3.
If per_node is missing or damaged, we have to trust jindex has
the correct number of entries. */
- if (sdp->md.pinode) /* if per_node was read in properly */
+ if (sdp->gfs1)
+ sdp->md.journals = ip->i_di.di_size / sizeof(struct gfs_jindex);
+ else if (sdp->md.pinode) /* if per_node was read in properly */
sdp->md.journals = (sdp->md.pinode->i_di.di_entries - 2) / 3;
else
sdp->md.journals = ip->i_di.di_entries - 2;
if (!(sdp->md.journal = calloc(sdp->md.journals,
- sizeof(struct gfs2_inode *)))) {
+ sizeof(struct gfs2_inode *)))) {
log_err("Unable to allocate journal index\n");
return -1;
}
memset(journal_name, 0, sizeof(*journal_name));
for (i = 0; i < sdp->md.journals; i++) {
- /* FIXME check snprintf return code */
- snprintf(journal_name, JOURNAL_NAME_SIZE, "journal%u", i);
- gfs2_lookupi(sdp->md.jiinode, journal_name, strlen(journal_name),
- &jip);
- sdp->md.journal[i] = jip;
+ if (sdp->gfs1) {
+ error = gfs2_readi(ip,
+ buf, i * sizeof(struct gfs_jindex),
+ sizeof(struct gfs_jindex));
+ if (!error)
+ break;
+ if (error != sizeof(struct gfs_jindex)){
+ log_err("An error occurred while reading the"
+ " journal index file.\n");
+ return -1;
+ }
+ gfs_jindex_in(&ji, buf);
+ sdp->md.journal[i] = inode_read(sdp, ji.ji_addr);
+ } else {
+ /* FIXME check snprintf return code */
+ snprintf(journal_name, JOURNAL_NAME_SIZE,
+ "journal%u", i);
+ gfs2_lookupi(sdp->md.jiinode, journal_name,
+ strlen(journal_name), &jip);
+ sdp->md.journal[i] = jip;
+ }
}
return 0;
-
}
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index 0fed06b..e2640d8 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -113,6 +113,7 @@ extern void gfs2_dup_free(void);
extern int fsck_query(const char *format, ...)
__attribute__((format(printf,1,2)));
extern struct dir_info *dirtree_find(uint64_t block);
+extern void dup_listent_delete(struct inode_with_dups *id);
extern void dup_delete(struct duptree *b);
extern void dirtree_delete(struct dir_info *b);
@@ -135,4 +136,6 @@ extern struct osi_root inodetree;
extern int dups_found; /* How many duplicate references have we found? */
extern int dups_found_first; /* How many duplicates have we found the original
reference for? */
+extern struct gfs_sb *sbd1;
+
#endif /* _FSCK_H */
diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c
index d7586de..cee1f49 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -9,6 +9,7 @@
#include <unistd.h>
#include <libintl.h>
#include <errno.h>
+#include <time.h>
#define _(String) gettext(String)
@@ -191,12 +192,14 @@ static void check_rgrp_integrity(struct gfs2_sbd *sdp, struct rgrp_list *rgd,
int *fixit, int *this_rg_fixed,
int *this_rg_bad)
{
- uint32_t rg_free, rg_reclaimed;
+ uint32_t rg_free, rg_reclaimed, rg_unlinked;
int rgb, x, y, off, bytes_to_check, total_bytes_to_check, asked = 0;
unsigned int state;
+ struct gfs_rgrp *gfs1rg = (struct gfs_rgrp *)&rgd->rg;
- rg_free = rg_reclaimed = 0;
+ rg_free = rg_reclaimed = rg_unlinked = 0;
total_bytes_to_check = rgd->ri.ri_bitbytes;
+
*this_rg_fixed = *this_rg_bad = 0;
for (rgb = 0; rgb < rgd->ri.ri_length; rgb++){
@@ -244,8 +247,10 @@ static void check_rgrp_integrity(struct gfs2_sbd *sdp, struct rgrp_list *rgd,
if (query("%s", msg))
*fixit = 1;
}
- if (!(*fixit))
+ if (!(*fixit)) {
+ rg_unlinked++;
continue;
+ }
*byte &= ~(GFS2_BIT_MASK <<
(GFS2_BIT_SIZE * y));
bmodified(rgd->bh[rgb]);
@@ -267,7 +272,29 @@ static void check_rgrp_integrity(struct gfs2_sbd *sdp, struct rgrp_list *rgd,
rg_reclaimed);
if (query( _("Fix the rgrp free blocks count? (y/n)"))) {
rgd->rg.rg_free = rg_free;
- gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
+ if (sdp->gfs1)
+ gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg,
+ rgd->bh[0]);
+ else
+ gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
+ *this_rg_fixed = 1;
+ log_err( _("The rgrp was fixed.\n"));
+ } else
+ log_err( _("The rgrp was not fixed.\n"));
+ }
+ if (sdp->gfs1 && gfs1rg->rg_freemeta != rg_unlinked) {
+ *this_rg_bad = 1;
+ log_err( _("Error: resource group %lld (0x%llx): "
+ "free meta (%d) does not match bitmap (%d)\n"),
+ (unsigned long long)rgd->ri.ri_addr,
+ (unsigned long long)rgd->ri.ri_addr,
+ gfs1rg->rg_freemeta, rg_unlinked);
+ if (rg_reclaimed)
+ log_err( _("(%d blocks were reclaimed)\n"),
+ rg_reclaimed);
+ if (query( _("Fix the rgrp free meta blocks count? (y/n)"))) {
+ gfs1rg->rg_freemeta = rg_unlinked;
+ gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bh[0]);
*this_rg_fixed = 1;
log_err( _("The rgrp was fixed.\n"));
} else
@@ -455,7 +482,7 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
uint64_t inumbuf;
char *buf;
struct gfs2_statfs_change sc;
- int rgcount, sane = 1;
+ int rgcount, sane = 1, err = 0;
enum rgindex_trust_level trust_lvl;
uint64_t addl_mem_needed;
const char *level_desc[] = {
@@ -482,7 +509,10 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
/* Get root dinode */
sdp->md.rooti = inode_read(sdp, sdp->sd_sb.sb_root_dir.no_addr);
- gfs2_lookupi(sdp->master_dir, "rindex", 6, &sdp->md.riinode);
+ if (sdp->gfs1)
+ sdp->md.riinode = inode_read(sdp, sbd1->sb_rindex_di.no_addr);
+ else
+ gfs2_lookupi(sdp->master_dir, "rindex", 6, &sdp->md.riinode);
if (!sdp->md.riinode) {
if (query( _("The gfs2 system rindex inode is missing. "
"Okay to rebuild it? (y/n) ")))
@@ -495,7 +525,10 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
/* rgrepair requires the journals be read in in order to distinguish
"real" rgrps from rgrps that are just copies left in journals. */
- gfs2_lookupi(sdp->master_dir, "jindex", 6, &sdp->md.jiinode);
+ if (sdp->gfs1)
+ sdp->md.jiinode = inode_read(sdp, sbd1->sb_jindex_di.no_addr);
+ else
+ gfs2_lookupi(sdp->master_dir, "jindex", 6, &sdp->md.jiinode);
if (!sdp->md.jiinode) {
if (query( _("The gfs2 system jindex inode is missing. "
"Okay to rebuild it? (y/n) ")))
@@ -513,7 +546,7 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
*******************************************************************/
log_warn( _("Validating Resource Group index.\n"));
for (trust_lvl = blind_faith; trust_lvl <= indignation; trust_lvl++) {
- int ret;
+ int ret = 0;
log_warn( _("Level %d rgrp check: %s.\n"), trust_lvl + 1,
level_desc[trust_lvl]);
@@ -547,27 +580,60 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
/*******************************************************************
***************** Initialize more system inodes *****************
*******************************************************************/
- /* Look for "inum" entry in master dinode */
- gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
- if (!sdp->md.inum) {
- if (query( _("The gfs2 system inum inode is missing. "
- "Okay to rebuild it? (y/n) ")))
- build_inum(sdp);
+ if (!sdp->gfs1) {
+ /* Look for "inum" entry in master dinode */
+ gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
+ if (!sdp->md.inum) {
+ if (!query( _("The gfs2 system inum inode is missing. "
+ "Okay to rebuild it? (y/n) "))) {
+ log_err( _("fsck.gfs2 cannot continue without "
+ "a valid inum file; aborting.\n"));
+ goto fail;
+ }
+ err = build_inum(sdp);
+ if (err) {
+ log_crit(_("Error rebuilding inum inode: %s\n"),
+ strerror(err));
+ exit(-1);
+ }
+ gfs2_lookupi(sdp->master_dir, "inum", 4,
+ &sdp->md.inum);
+ if (!sdp->md.inum) {
+ log_crit("System inum inode was not rebuilt. "
+ "Aborting.\n");
+ goto fail;
+ }
+ }
+ /* Read inum entry into buffer */
+ gfs2_readi(sdp->md.inum, &inumbuf, 0,
+ sdp->md.inum->i_di.di_size);
+ /* call gfs2_inum_range_in() to retrieve range */
+ sdp->md.next_inum = be64_to_cpu(inumbuf);
}
- /* Read inum entry into buffer */
- gfs2_readi(sdp->md.inum, &inumbuf, 0, sdp->md.inum->i_di.di_size);
- /* call gfs2_inum_range_in() to retrieve range */
- sdp->md.next_inum = be64_to_cpu(inumbuf);
- gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
- if (!sdp->md.statfs) {
- if (query( _("The gfs2 system statfs inode is missing. "
- "Okay to rebuild it? (y/n) ")))
- build_statfs(sdp);
- else {
- log_err( _("fsck.gfs2 cannot continue without a "
- "valid statfs file; aborting.\n"));
- return FSCK_ERROR;
+ if (sdp->gfs1)
+ sdp->md.statfs = inode_read(sdp, sbd1->sb_license_di.no_addr);
+ else
+ gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
+ if (!sdp->gfs1 && !sdp->md.statfs) {
+ if (!query( _("The gfs2 system statfs inode is missing. "
+ "Okay to rebuild it? (y/n) "))) {
+ log_err( _("fsck.gfs2 cannot continue without a valid "
+ "statfs file; aborting.\n"));
+ goto fail;
+ }
+ err = build_statfs(sdp);
+ if (err) {
+ log_crit(_("Error rebuilding statfs inode: %s\n"),
+ strerror(err));
+ exit(-1);
+ }
+ gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
+ if (!sdp->md.statfs) {
+ log_err( _("Rebuild of statfs system file failed."));
+ log_err( _("fsck.gfs2 cannot continue without "
+ "a valid statfs file; aborting.\n"));
+ goto fail;
}
}
buf = malloc(sdp->md.statfs->i_di.di_size);
@@ -577,16 +643,36 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
gfs2_statfs_change_in(&sc, buf);
free(buf);
- gfs2_lookupi(sdp->master_dir, "quota", 5, &sdp->md.qinode);
- if (!sdp->md.qinode) {
- if (query( _("The gfs2 system quota inode is missing. "
- "Okay to rebuild it? (y/n) ")))
- build_quota(sdp);
+ if (sdp->gfs1)
+ sdp->md.qinode = inode_read(sdp, sbd1->sb_quota_di.no_addr);
+ else
+ gfs2_lookupi(sdp->master_dir, "quota", 5, &sdp->md.qinode);
+ if (!sdp->gfs1 && !sdp->md.qinode) {
+ if (!query( _("The gfs2 system quota inode is missing. "
+ "Okay to rebuild it? (y/n) "))) {
+ log_crit("System quota inode was not "
+ "rebuilt. Aborting.\n");
+ goto fail;
+ }
+ err = build_quota(sdp);
+ if (err) {
+ log_crit(_("Error rebuilding quota inode: %s\n"),
+ strerror(err));
+ exit(-1);
+ }
+ gfs2_lookupi(sdp->master_dir, "quota", 5, &sdp->md.qinode);
+ if (!sdp->md.qinode) {
+ log_crit("Unable to rebuild system quota file "
+ "inode. Aborting.\n");
+ goto fail;
+ }
}
/* Try to lookup the per_node inode. If it was missing, it is now
safe to rebuild it. */
- lookup_per_node(sdp, 1);
+ if (!sdp->gfs1)
+ lookup_per_node(sdp, 1);
+
/*******************************************************************
******* Now, set boundary fields in the super block *************
*******************************************************************/
@@ -699,13 +785,15 @@ static void peruse_system_dinode(struct gfs2_sbd *sdp, struct gfs2_dinode *di,
return;
}
ip = inode_read(sdp, di->di_num.no_addr);
- if (di->di_num.no_formal_ino == 3) {
+ if ((!sdp->gfs1 && di->di_num.no_formal_ino == 3) ||
+ (sdp->gfs1 && (di->di_flags & GFS2_DIF_JDATA) &&
+ (di->di_size % sizeof(struct gfs_jindex) == 0))) {
if (fix_md.jiinode || is_journal_copy(ip, bh))
return;
log_warn(_("Found system jindex file at: 0x%llx\n"),
di->di_num.no_addr);
fix_md.jiinode = ip;
- } else if (S_ISDIR(di->di_mode)) {
+ } else if (!sdp->gfs1 && is_dir(di, sdp->gfs1)) {
/* Check for a jindex dir entry. Only one system dir has a
jindex: master */
gfs2_lookupi(ip, "jindex", 6, &child_ip);
@@ -741,7 +829,7 @@ static void peruse_system_dinode(struct gfs2_sbd *sdp, struct gfs2_dinode *di,
log_debug(_("Unknown system directory at block 0x%llx\n"),
di->di_num.no_addr);
inode_put(&ip);
- } else if (di->di_size == 8) {
+ } else if (!sdp->gfs1 && di->di_size == 8) {
if (fix_md.inum || is_journal_copy(ip, bh))
return;
fix_md.inum = ip;
@@ -783,7 +871,7 @@ static void peruse_user_dinode(struct gfs2_sbd *sdp, struct gfs2_dinode *di,
if (sdp->sd_sb.sb_root_dir.no_addr) /* if we know the root dinode */
return; /* we don't need to find the root */
- if (!S_ISDIR(di->di_mode)) /* if this isn't a directory */
+ if (!is_dir(di, sdp->gfs1)) /* if this isn't a directory */
return; /* it can't lead us to the root anyway */
if (di->di_num.no_formal_ino == 1) {
@@ -918,7 +1006,6 @@ static int peruse_metadata(struct gfs2_sbd *sdp, uint64_t startblock)
uint64_t blk, max_rg_size;
struct gfs2_buffer_head *bh;
struct gfs2_dinode di;
- int found_gfs2_dinodes = 0, possible_gfs1_dinodes = 0;
max_rg_size = 2147483648ull / sdp->bsize;
/* Max RG size is 2GB. 2G / bsize. */
@@ -929,18 +1016,6 @@ static int peruse_metadata(struct gfs2_sbd *sdp, uint64_t startblock)
continue;
}
gfs2_dinode_in(&di, bh);
- if (!found_gfs2_dinodes &&
- di.di_num.no_addr == di.di_num.no_formal_ino) {
- possible_gfs1_dinodes++;
- if (possible_gfs1_dinodes > 5) {
- log_err(_("Found several gfs (version 1) "
- "dinodes; aborting.\n"));
- brelse(bh);
- return -1;
- }
- } else {
- found_gfs2_dinodes++;
- }
if (di.di_flags & GFS2_DIF_SYSTEM)
peruse_system_dinode(sdp, &di, bh);
else
@@ -1067,6 +1142,8 @@ static int sb_repair(struct gfs2_sbd *sdp)
*/
static int fill_super_block(struct gfs2_sbd *sdp)
{
+ int ret;
+
sync();
/********************************************************************
@@ -1091,19 +1168,109 @@ static int fill_super_block(struct gfs2_sbd *sdp)
log_crit(_("Bad constants (1)\n"));
exit(-1);
}
- if (read_sb(sdp, 0) < 0) {
- /* First, check for a gfs1 (not gfs2) file system */
- if (sdp->sd_sb.sb_header.mh_magic == GFS2_MAGIC &&
- sdp->sd_sb.sb_header.mh_type == GFS2_METATYPE_SB)
- return -1; /* This is gfs1, don't try to repair */
- /* It's not a "sane" gfs1 fs so try to repair it */
+ ret = read_sb(sdp, 1);
+ if (ret < 0) {
if (sb_repair(sdp) != 0)
return -1; /* unrepairable, so exit */
/* Now that we've tried to repair it, re-read it. */
- if (read_sb(sdp, 0) < 0)
+ ret = read_sb(sdp, 1);
+ if (ret < 0)
return -1;
}
+ if (sdp->gfs1)
+ sbd1 = (struct gfs_sb *)&sdp->sd_sb;
+ return 0;
+}
+
+static void gfs_log_header_out(struct gfs_log_header *head, char *buf)
+{
+ struct gfs_log_header *str = (struct gfs_log_header *) buf;
+
+ str->lh_header.mh_magic = cpu_to_be32(head->lh_header.mh_magic);
+ str->lh_header.mh_type = cpu_to_be32(head->lh_header.mh_type);
+ str->lh_header.mh_format = cpu_to_be32(head->lh_header.mh_format);
+ str->lh_header.__pad0 = cpu_to_be32(head->lh_header.__pad0);
+
+ str->lh_flags = cpu_to_be32(head->lh_flags);
+ str->lh_pad = cpu_to_be32(head->lh_pad);
+ str->lh_first = cpu_to_be64(head->lh_first);
+ str->lh_sequence = cpu_to_be64(head->lh_sequence);
+ str->lh_tail = cpu_to_be64(head->lh_tail);
+ str->lh_last_dump = cpu_to_be64(head->lh_last_dump);
+}
+
+/*
+ * reconstruct_single_journal - write a fresh GFS1 journal
+ * @sdp: superblock
+ * @jnum: journal number
+ *
+ * This function will write a fresh journal over the top of
+ * the previous journal. All journal information is lost. This
+ * process is basically stolen from write_journals() in the mkfs code.
+ *
+ * Returns: -1 on error, 0 otherwise
+ */
+static int reconstruct_single_journal(struct gfs2_sbd *sdp, int jnum,
+ uint32_t ji_nsegment)
+{
+ struct gfs_log_header lh;
+ uint32_t seg, sequence;
+ struct gfs2_buffer_head *bh;
+
+ srandom(time(NULL));
+ sequence = ji_nsegment / (RAND_MAX + 1.0) * random();
+
+ log_info("Clearing journal %d\n", jnum);
+
+ for (seg = 0; seg < ji_nsegment; seg++){
+ bh = bget(sdp, lh.lh_first * sdp->bsize);
+ memset(bh->b_data, 0, sdp->bsize);
+ memset(&lh, 0, sizeof(struct gfs_log_header));
+
+ lh.lh_header.mh_magic = GFS2_MAGIC;
+ lh.lh_header.mh_type = GFS2_METATYPE_LH;
+ lh.lh_header.mh_format = GFS2_FORMAT_LH;
+ lh.lh_header.__pad0 = 0x101674; /* mh_generation */
+ lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT;
+ lh.lh_first = sdp->md.journal[jnum]->i_di.di_num.no_addr +
+ (seg * sbd1->sb_seg_size);
+ lh.lh_sequence = sequence;
+
+ gfs_log_header_out(&lh, bh->b_data);
+ gfs_log_header_out(&lh, bh->b_data + GFS2_BASIC_BLOCK -
+ sizeof(struct gfs_log_header));
+ brelse(bh);
+
+ if (++sequence == ji_nsegment)
+ sequence = 0;
+ }
+ return 0;
+}
+
+/*
+ * reconstruct_journals - write fresh journals for GFS1 only
+ * sdp: the super block
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int reconstruct_journals(struct gfs2_sbd *sdp)
+{
+ int i;
+ struct gfs_jindex ji;
+ char buf[sizeof(struct gfs_jindex)];
+
+ log_err("Clearing GFS journals (this may take a while)");
+ for (i = 0; i < sdp->md.journals; i++) {
+ gfs2_readi(sdp->md.jiinode, buf, i * sizeof(struct gfs_jindex),
+ sizeof(struct gfs_jindex));
+ gfs_jindex_in(&ji, buf);
+ if ((i % 2) == 0)
+ log_err(".");
+ if (reconstruct_single_journal(sdp, i, ji.ji_nsegment))
+ return -1;
+ }
+ log_err("\nJournals cleared.\n");
return 0;
}
@@ -1175,10 +1342,15 @@ int initialize(struct gfs2_sbd *sdp, int force_check, int preen,
}
/* Get master dinode */
- sdp->master_dir = inode_read(sdp, sdp->sd_sb.sb_master_dir.no_addr);
- if (sdp->master_dir->i_di.di_header.mh_magic != GFS2_MAGIC ||
- sdp->master_dir->i_di.di_header.mh_type != GFS2_METATYPE_DI ||
- !sdp->master_dir->i_di.di_size) {
+ if (sdp->gfs1)
+ sdp->master_dir = NULL;
+ else
+ sdp->master_dir = inode_read(sdp,
+ sdp->sd_sb.sb_master_dir.no_addr);
+ if (!sdp->gfs1 &&
+ (sdp->master_dir->i_di.di_header.mh_magic != GFS2_MAGIC ||
+ sdp->master_dir->i_di.di_header.mh_type != GFS2_METATYPE_DI ||
+ !sdp->master_dir->i_di.di_size)) {
inode_put(&sdp->master_dir);
rebuild_master(sdp);
sdp->master_dir = inode_read(sdp,
@@ -1188,11 +1360,15 @@ int initialize(struct gfs2_sbd *sdp, int force_check, int preen,
/* Look up the "per_node" inode. If there are journals missing, we
need to figure out what's missing from per_node. And we need all
our journals to be there before we can replay them. */
- lookup_per_node(sdp, 0);
+ if (!sdp->gfs1)
+ lookup_per_node(sdp, 0);
/* verify various things */
- if (replay_journals(sdp, preen, force_check, &clean_journals)) {
+ if (sdp->gfs1) {
+ if (reconstruct_journals(sdp))
+ return FSCK_ERROR;
+ } else if (replay_journals(sdp, preen, force_check, &clean_journals)) {
if (!opts.no && preen_is_safe(sdp, preen, force_check))
block_mounters(sdp, 0);
stack;
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index 0de4f8e..af4189f 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -28,7 +28,7 @@ static void add_dotdot(struct gfs2_inode *ip)
/* If there's a pre-existing .. directory entry, we have to
back out the links. */
di = dirtree_find(ip->i_di.di_num.no_addr);
- if (di && !valid_block(sdp, di->dotdot_parent) == 0) {
+ if (di && valid_block(sdp, di->dotdot_parent)) {
struct gfs2_inode *dip;
log_debug(_("Directory %lld (0x%llx) already had a "
@@ -75,7 +75,47 @@ static void add_dotdot(struct gfs2_inode *ip)
log_warn( _("add_inode_to_lf: Unable to remove "
"\"..\" directory entry.\n"));
- dir_add(ip, "..", 2, &(lf_dip->i_di.di_num), DT_DIR);
+ dir_add(ip, "..", 2, &(lf_dip->i_di.di_num),
+ (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
+}
+
+static uint64_t find_free_blk(struct gfs2_sbd *sdp)
+{
+ osi_list_t *tmp, *head;
+ struct rgrp_list *rl = NULL;
+ struct gfs2_rindex *ri;
+ struct gfs2_rgrp *rg;
+ unsigned int block, bn = 0, x = 0, y = 0;
+ unsigned int state;
+ struct gfs2_buffer_head *bh;
+
+ memset(&rg, 0, sizeof(rg));
+ for (head = &sdp->rglist, tmp = head->next; tmp != head;
+ tmp = tmp->next) {
+ rl = osi_list_entry(tmp, struct rgrp_list, list);
+ if (rl->rg.rg_free)
+ break;
+ }
+
+ if (tmp == head)
+ return 0;
+
+ ri = &rl->ri;
+ rg = &rl->rg;
+
+ for (block = 0; block < ri->ri_length; block++) {
+ bh = rl->bh[block];
+ x = (block) ? sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_rgrp);
+
+ for (; x < sdp->bsize; x++)
+ for (y = 0; y < GFS2_NBBY; y++) {
+ state = (bh->b_data[x] >> (GFS2_BIT_SIZE * y)) & 0x03;
+ if (state == GFS2_BLKST_FREE)
+ return ri->ri_data0 + bn;
+ bn++;
+ }
+ }
+ return 0;
}
/* add_inode_to_lf - Add dir entry to lost+found for the inode
@@ -93,16 +133,33 @@ int add_inode_to_lf(struct gfs2_inode *ip){
uint64_t lf_blocks;
struct gfs2_sbd *sdp = ip->i_sbd;
struct dir_info *di;
+ uint32_t mode;
if (!lf_dip) {
uint8_t q;
log_info( _("Locating/Creating lost+found directory\n"));
- lf_dip = createi(sdp->md.rooti, "lost+found",
- S_IFDIR | 0700, 0);
+ /* if this is gfs1, we have to trick createi into using
+ no_formal_ino = no_addr, so we set next_inum to the
+ free block we're about to allocate. */
+ if (sdp->gfs1)
+ sdp->md.next_inum = find_free_blk(sdp);
+ mode = (sdp->gfs1 ? DT2IF(GFS_FILE_DIR) : S_IFDIR) | 0700;
+ if (sdp->gfs1)
+ lf_dip = gfs_createi(sdp->md.rooti, "lost+found",
+ mode, 0);
+ else
+ lf_dip = createi(sdp->md.rooti, "lost+found",
+ S_IFDIR | 0700, 0);
+ if (lf_dip == NULL) {
+ log_crit(_("Error creating lost+found: %s\n"),
+ strerror(errno));
+ exit(FSCK_ERROR);
+ }
+
/* createi will have incremented the di_nlink link count for
- the root directory. We must increment the nlink value
+ the root directory. We must set the nlink value
in the hash table to keep them in sync so that pass4 can
detect and fix any descrepancies. */
set_di_nlink(sdp->md.rooti);
@@ -129,7 +186,9 @@ int add_inode_to_lf(struct gfs2_inode *ip){
/* lost+found link for '..' back to root */
incr_link_count(lf_dip->i_di.di_num.no_addr,
sdp->md.rooti->i_di.di_num.no_addr,
- "\"..\"");
+ "\"..\"");
+ if (sdp->gfs1)
+ lf_dip->i_di.__pad1 = GFS_FILE_DIR;
}
log_info( _("lost+found directory is dinode %lld (0x%llx)\n"),
(unsigned long long)lf_dip->i_di.di_num.no_addr,
@@ -147,47 +206,52 @@ int add_inode_to_lf(struct gfs2_inode *ip){
}
lf_blocks = lf_dip->i_di.di_blocks;
- switch(ip->i_di.di_mode & S_IFMT){
+ if (sdp->gfs1)
+ mode = gfs_to_gfs2_mode(ip->i_di.__pad1);
+ else
+ mode = ip->i_di.di_mode & S_IFMT;
+
+ switch (mode) {
case S_IFDIR:
add_dotdot(ip);
sprintf(tmp_name, "lost_dir_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_DIR;
+ inode_type = (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR);
break;
case S_IFREG:
sprintf(tmp_name, "lost_file_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_REG;
+ inode_type = (sdp->gfs1 ? GFS_FILE_REG : DT_REG);
break;
case S_IFLNK:
sprintf(tmp_name, "lost_link_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_LNK;
+ inode_type = (sdp->gfs1 ? GFS_FILE_LNK : DT_LNK);
break;
case S_IFBLK:
sprintf(tmp_name, "lost_blkdev_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_BLK;
+ inode_type = (sdp->gfs1 ? GFS_FILE_BLK : DT_BLK);
break;
case S_IFCHR:
sprintf(tmp_name, "lost_chrdev_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_CHR;
+ inode_type = (sdp->gfs1 ? GFS_FILE_CHR : DT_CHR);
break;
case S_IFIFO:
sprintf(tmp_name, "lost_fifo_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_FIFO;
+ inode_type = (sdp->gfs1 ? GFS_FILE_FIFO : DT_FIFO);
break;
case S_IFSOCK:
sprintf(tmp_name, "lost_socket_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_SOCK;
+ inode_type = (sdp->gfs1 ? GFS_FILE_SOCK : DT_SOCK);
break;
default:
sprintf(tmp_name, "lost_%llu",
(unsigned long long)ip->i_di.di_num.no_addr);
- inode_type = DT_REG;
+ inode_type = (sdp->gfs1 ? GFS_FILE_REG : DT_REG);
break;
}
@@ -202,7 +266,7 @@ int add_inode_to_lf(struct gfs2_inode *ip){
incr_link_count(ip->i_di.di_num.no_addr, lf_dip->i_di.di_num.no_addr,
_("from lost+found"));
/* If it's a directory, lost+found is back-linked to it via .. */
- if (S_ISDIR(ip->i_di.di_mode))
+ if (is_dir(&ip->i_di, sdp->gfs1))
incr_link_count(lf_dip->i_di.di_num.no_addr,
ip->i_di.di_mode, _("to lost+found"));
diff --git a/gfs2/fsck/main.c b/gfs2/fsck/main.c
index 5dae096..75ccc11 100644
--- a/gfs2/fsck/main.c
+++ b/gfs2/fsck/main.c
@@ -33,6 +33,7 @@ struct osi_root dup_blocks = (struct osi_root) { NULL, };
struct osi_root dirtree = (struct osi_root) { NULL, };
struct osi_root inodetree = (struct osi_root) { NULL, };
int dups_found = 0, dups_found_first = 0;
+struct gfs_sb *sbd1 = NULL;
/* This function is for libgfs2's sake. */
void print_it(const char *label, const char *fmt, const char *fmt2, ...)
@@ -153,6 +154,10 @@ static void check_statfs(struct gfs2_sbd *sdp)
char buf[sizeof(struct gfs2_statfs_change)];
int count;
+ if (sdp->gfs1 && !sdp->md.statfs->i_di.di_size) {
+ log_info("This GFS1 file system is not using fast_statfs.\n");
+ return;
+ }
/* Read the current statfs values */
count = gfs2_readi(sdp->md.statfs, buf, 0,
sdp->md.statfs->i_di.di_size);
@@ -338,16 +343,19 @@ int main(int argc, char **argv)
check_statfs(sdp);
/* Free up our system inodes */
- inode_put(&sdp->md.inum);
+ if (!sdp->gfs1)
+ inode_put(&sdp->md.inum);
inode_put(&sdp->md.statfs);
for (j = 0; j < sdp->md.journals; j++)
inode_put(&sdp->md.journal[j]);
inode_put(&sdp->md.jiinode);
inode_put(&sdp->md.riinode);
inode_put(&sdp->md.qinode);
- inode_put(&sdp->md.pinode);
+ if (!sdp->gfs1)
+ inode_put(&sdp->md.pinode);
inode_put(&sdp->md.rooti);
- inode_put(&sdp->master_dir);
+ if (!sdp->gfs1)
+ inode_put(&sdp->master_dir);
if (lf_dip)
inode_put(&lf_dip);
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index b25b40d..2ddf7dd 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -40,17 +40,19 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk,
(unsigned long long)blk, (unsigned long long)blk);
return -1;
}
- new_bitmap_state = blockmap_to_bitmap(new_blockmap_state);
+ new_bitmap_state = blockmap_to_bitmap(new_blockmap_state, sdp->gfs1);
if (old_bitmap_state != new_bitmap_state) {
- const char *allocdesc[] = {"free space", "data", "unlinked",
- "inode", "reserved"};
+ const char *allocdesc[2][5] = { /* gfs2 descriptions */
+ {"free", "data", "unlinked", "inode", "reserved"},
+ /* gfs1 descriptions: */
+ {"free", "data", "free meta", "metadata", "reserved"}};
/* Keep these messages as short as possible, or the output
gets to be huge and unmanageable. */
log_err( _("Block %llu (0x%llx) was '%s', should be %s.\n"),
(unsigned long long)blk, (unsigned long long)blk,
- allocdesc[new_bitmap_state],
- allocdesc[old_bitmap_state]);
+ allocdesc[sdp->gfs1][old_bitmap_state],
+ allocdesc[sdp->gfs1][new_bitmap_state]);
if (query( _("Fix the bitmap? (y/n)"))) {
/* If the new bitmap state is free (and therefore the
old state was not) we have to add to the free
@@ -75,10 +77,18 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk,
inodetree_delete(ii);
}
rgd->rg.rg_free++;
- gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
+ if (sdp->gfs1)
+ gfs_rgrp_out((struct gfs_rgrp *)
+ &rgd->rg, rgd->bh[0]);
+ else
+ gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
} else if (old_bitmap_state == GFS2_BLKST_FREE) {
rgd->rg.rg_free--;
- gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
+ if (sdp->gfs1)
+ gfs_rgrp_out((struct gfs_rgrp *)
+ &rgd->rg, rgd->bh[0]);
+ else
+ gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
}
log_err( _("The bitmap was fixed.\n"));
} else {
@@ -168,9 +178,28 @@ struct duptree *dupfind(uint64_t block)
struct gfs2_inode *fsck_system_inode(struct gfs2_sbd *sdp, uint64_t block)
{
+ int j;
+
if (lf_dip && lf_dip->i_di.di_num.no_addr == block)
return lf_dip;
- return is_system_inode(sdp, block);
+ if (!sdp->gfs1)
+ return is_system_inode(sdp, block);
+
+ if (sdp->md.statfs && block == sdp->md.statfs->i_di.di_num.no_addr)
+ return sdp->md.statfs;
+ if (sdp->md.jiinode && block == sdp->md.jiinode->i_di.di_num.no_addr)
+ return sdp->md.jiinode;
+ if (sdp->md.riinode && block == sdp->md.riinode->i_di.di_num.no_addr)
+ return sdp->md.riinode;
+ if (sdp->md.qinode && block == sdp->md.qinode->i_di.di_num.no_addr)
+ return sdp->md.qinode;
+ if (sdp->md.rooti && block == sdp->md.rooti->i_di.di_num.no_addr)
+ return sdp->md.rooti;
+ for (j = 0; j < sdp->md.journals; j++)
+ if (sdp->md.journal && sdp->md.journal[j] &&
+ block == sdp->md.journal[j]->i_di.di_num.no_addr)
+ return sdp->md.journal[j];
+ return NULL;
}
/* fsck_load_inode - same as gfs2_load_inode() in libgfs2 but system inodes
@@ -182,6 +211,8 @@ struct gfs2_inode *fsck_load_inode(struct gfs2_sbd *sdp, uint64_t block)
ip = fsck_system_inode(sdp, block);
if (ip)
return ip;
+ if (sdp->gfs1)
+ return gfs_inode_read(sdp, block);
return inode_read(sdp, block);
}
@@ -196,6 +227,8 @@ struct gfs2_inode *fsck_inode_get(struct gfs2_sbd *sdp,
if (sysip)
return sysip;
+ if (sdp->gfs1)
+ return gfs_inode_get(sdp, bh);
return inode_get(sdp, bh);
}
@@ -432,12 +465,13 @@ static int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
return 0;
}
-/* Process a bad leaf pointer and ask to repair the first time. */
-/* The repair process involves extending the previous leaf's entries */
-/* so that they replace the bad ones. We have to hack up the old */
-/* leaf a bit, but it's better than deleting the whole directory, */
-/* which is what used to happen before. */
-static int warn_and_patch(struct gfs2_inode *ip, uint64_t *leaf_no,
+/* warn_and_patch - Warn the user of an error and ask permission to fix it
+ * Process a bad leaf pointer and ask to repair the first time.
+ * The repair process involves extending the previous leaf's entries
+ * so that they replace the bad ones. We have to hack up the old
+ * leaf a bit, but it's better than deleting the whole directory,
+ * which is what used to happen before. */
+static int warn_and_patch(struct gfs2_inode *ip, uint64_t *leaf_no,
uint64_t *bad_leaf, uint64_t old_leaf,
uint64_t first_ok_leaf, int pindex, const char *msg)
{
@@ -539,7 +573,7 @@ static int check_leaf(struct gfs2_inode *ip, int lindex,
goto out_copy_old_leaf;
}
- if (pass->check_dentry && S_ISDIR(ip->i_di.di_mode)) {
+ if (pass->check_dentry && is_dir(&ip->i_di, sdp->gfs1)) {
error = check_entries(ip, lbh, DIR_EXHASH, &count, pass);
if (skip_this_pass || fsck_abort)
@@ -1072,7 +1106,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
because it checks everything through the hash table using
"depth" field calculations. However, we still have to check the
indirect blocks, even if the height == 1. */
- if (S_ISDIR(ip->i_di.di_mode))
+ if (is_dir(&ip->i_di, ip->i_sbd->gfs1))
height++;
/* if (<there are no indirect blocks to check>) */
@@ -1080,12 +1114,15 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
return 0;
for (h = 1; h < height; h++) {
if (h > 1) {
- if (S_ISDIR(ip->i_di.di_mode) &&
+ if (is_dir(&ip->i_di, ip->i_sbd->gfs1) &&
h == ip->i_di.di_height + 1)
iblk_type = GFS2_METATYPE_JD;
else
iblk_type = GFS2_METATYPE_IN;
- head_size = sizeof(struct gfs2_meta_header);
+ if (ip->i_sbd->gfs1)
+ head_size = sizeof(struct gfs_indirect);
+ else
+ head_size = sizeof(struct gfs2_meta_header);
} else {
iblk_type = GFS2_METATYPE_DI;
head_size = sizeof(struct gfs2_dinode);
@@ -1176,7 +1213,7 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
if (skip_this_pass || fsck_abort)
return error;
block = be64_to_cpu(*ptr);
- /* It's important that we don't call !valid_block and
+ /* It's important that we don't call valid_block() and
bypass calling check_data on invalid blocks because that
would defeat the rangecheck_block related functions in
pass1. Therefore the individual check_data functions
@@ -1207,7 +1244,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
uint64_t blks_checked = 0;
int error, rc;
- if (!height && !S_ISDIR(ip->i_di.di_mode))
+ if (!height && !is_dir(&ip->i_di, ip->i_sbd->gfs1))
return 0;
for (i = 0; i < GFS2_MAX_META_HEIGHT; i++)
@@ -1223,7 +1260,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
/* For directories, we've already checked the "data" blocks which
* comprise the directory hash table, so we perform the directory
* checks and exit. */
- if (S_ISDIR(ip->i_di.di_mode)) {
+ if (is_dir(&ip->i_di, ip->i_sbd->gfs1)) {
free_metalist(ip, &metalist[0]);
if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH))
return 0;
@@ -1266,7 +1303,10 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
brelse(bh);
continue;
}
- head_size = sizeof(struct gfs2_meta_header);
+ if (ip->i_sbd->gfs1)
+ head_size = sizeof(struct gfs_indirect);
+ else
+ head_size = sizeof(struct gfs2_meta_header);
} else {
/* if this isn't really a dinode, skip it */
if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
@@ -1437,7 +1477,7 @@ static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
after the bitmap has been set but before the blockmap has. */
*bh = bread(ip->i_sbd, block);
q = block_type(block);
- if (blockmap_to_bitmap(q) == GFS2_BLKST_FREE) { /* If not marked yet */
+ if (blockmap_to_bitmap(q, ip->i_sbd->gfs1) == GFS2_BLKST_FREE) {
log_debug(_("%s reference to new metadata block "
"%lld (0x%llx) is now marked as indirect.\n"),
desc, (unsigned long long)block,
@@ -1456,7 +1496,7 @@ static int alloc_data(struct gfs2_inode *ip, uint64_t block, void *private)
/* We can't check the bitmap here because this function is called
after the bitmap has been set but before the blockmap has. */
q = block_type(block);
- if (blockmap_to_bitmap(q) == GFS2_BLKST_FREE) { /* If not marked yet */
+ if (blockmap_to_bitmap(q, ip->i_sbd->gfs1) == GFS2_BLKST_FREE) {
log_debug(_("%s reference to new data block "
"%lld (0x%llx) is now marked as data.\n"),
desc, (unsigned long long)block,
@@ -1474,7 +1514,7 @@ static int alloc_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
/* We can't check the bitmap here because this function is called
after the bitmap has been set but before the blockmap has. */
q = block_type(block);
- if (blockmap_to_bitmap(q) == GFS2_BLKST_FREE) /* If not marked yet */
+ if (blockmap_to_bitmap(q, ip->i_sbd->gfs1) == GFS2_BLKST_FREE)
fsck_blockmap_set(ip, block, _("newly allocated leaf"),
gfs2_leaf_blk);
return 0;
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index c0b7420..876078e 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -26,6 +26,8 @@
#include "link.h"
#include "metawalk.h"
+struct special_blocks gfs1_rindex_blks;
+
struct block_count {
uint64_t indir_count;
uint64_t data_count;
@@ -174,9 +176,10 @@ static int resuscitate_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
(unsigned long long)ip->i_di.di_num.no_addr);
return 0;
}
- if (block == sdp->md.jiinode->i_di.di_num.no_addr ||
- block == sdp->md.pinode->i_di.di_num.no_addr ||
- block == sdp->master_dir->i_di.di_num.no_addr)
+ if (block == sdp->md.jiinode->i_di.di_num.no_addr)
+ dinode_type = gfs2_inode_dir;
+ else if (!sdp->gfs1 && (block == sdp->md.pinode->i_di.di_num.no_addr ||
+ block == sdp->master_dir->i_di.di_num.no_addr))
dinode_type = gfs2_inode_dir;
else
dinode_type = gfs2_inode_file;
@@ -239,8 +242,12 @@ static int fix_leaf_pointers(struct gfs2_inode *dip, int *lindex,
the last 8 of them. If we have 7, write the last 4, etc.
We need to write these starting at the current lindex and adjust
lindex accordingly. */
- count = gfs2_writei(dip, ptrbuf + (off_by * sizeof(uint64_t)),
- start_lindex * sizeof(uint64_t), bufsize);
+ if (dip->i_sbd->gfs1)
+ count = gfs1_writei(dip, ptrbuf + (off_by * sizeof(uint64_t)),
+ start_lindex * sizeof(uint64_t), bufsize);
+ else
+ count = gfs2_writei(dip, ptrbuf + (off_by * sizeof(uint64_t)),
+ start_lindex * sizeof(uint64_t), bufsize);
if (count != bufsize) {
log_err( _("Error: bad read while fixing leaf pointers.\n"));
free(ptrbuf);
@@ -248,8 +255,12 @@ static int fix_leaf_pointers(struct gfs2_inode *dip, int *lindex,
}
/* Now zero out the hole left at the end */
memset(ptrbuf, 0, off_by * sizeof(uint64_t));
- gfs2_writei(dip, ptrbuf, (start_lindex * sizeof(uint64_t)) +
- bufsize, off_by * sizeof(uint64_t));
+ if (dip->i_sbd->gfs1)
+ gfs1_writei(dip, ptrbuf, (start_lindex * sizeof(uint64_t)) +
+ bufsize, off_by * sizeof(uint64_t));
+ else
+ gfs2_writei(dip, ptrbuf, (start_lindex * sizeof(uint64_t)) +
+ bufsize, off_by * sizeof(uint64_t));
free(ptrbuf);
*lindex -= off_by; /* adjust leaf index to account for the change */
return 0;
@@ -381,7 +392,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height) {
+ if (is_dir(&ip->i_di, ip->i_sbd->gfs1) && h == ip->i_di.di_height) {
iblk_type = GFS2_METATYPE_JD;
blktypedesc = _("a directory hash table block");
} else {
@@ -449,7 +460,7 @@ static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
_("itself"), gfs2_block_free);
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height)
+ if (is_dir(&ip->i_di, ip->i_sbd->gfs1) && h == ip->i_di.di_height)
iblk_type = GFS2_METATYPE_JD;
else
iblk_type = GFS2_METATYPE_IN;
@@ -526,7 +537,22 @@ static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
bc->data_count++;
return 1;
}
- fsck_blockmap_set(ip, block, _("data"), gfs2_block_used);
+ /* In gfs1, rgrp indirect blocks are marked in the bitmap as "meta".
+ In gfs2, "meta" is only for dinodes. So here we dummy up the
+ blocks so that the bitmap isn't changed improperly. */
+ if (ip->i_sbd->gfs1 && ip == ip->i_sbd->md.riinode) {
+ log_info(_("Block %lld (0x%llx) is a GFS1 rindex block\n"),
+ (unsigned long long)block, (unsigned long long)block);
+ gfs2_special_set(&gfs1_rindex_blks, block);
+ fsck_blockmap_set(ip, block, _("rgrp"), gfs2_indir_blk);
+ /*gfs2_meta_rgrp);*/
+ } else if (ip->i_sbd->gfs1 && ip->i_di.di_flags & GFS2_DIF_JDATA) {
+ log_info(_("Block %lld (0x%llx) is a GFS1 journaled data "
+ "block\n"),
+ (unsigned long long)block, (unsigned long long)block);
+ fsck_blockmap_set(ip, block, _("jdata"), gfs2_jdata);
+ } else
+ fsck_blockmap_set(ip, block, _("data"), gfs2_block_used);
bc->data_count++;
return 0;
}
@@ -1020,6 +1046,7 @@ static int invalidate_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
* messing with them because we don't want to mark a block as a
* duplicate (for example) until we know if the pointers in general can
* be trusted. Thus it needs to be in a separate loop.
+ * Returns: 0 if good range, otherwise != 0
*/
static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh,
@@ -1112,6 +1139,7 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
struct block_count bc = {0};
long bad_pointers;
uint64_t block = ip->i_bh->b_blocknr;
+ uint32_t mode;
bad_pointers = 0L;
@@ -1132,8 +1160,12 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
return 0;
}
- switch(ip->i_di.di_mode & S_IFMT) {
+ if (sdp->gfs1)
+ mode = gfs_to_gfs2_mode(ip->i_di.__pad1);
+ else
+ mode = ip->i_di.di_mode & S_IFMT;
+ switch (mode) {
case S_IFDIR:
if (fsck_blockmap_set(ip, block, _("directory"),
gfs2_inode_dir))
@@ -1142,8 +1174,7 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
goto bad_dinode;
break;
case S_IFREG:
- if (fsck_blockmap_set(ip, block, _("file"),
- gfs2_inode_file))
+ if (fsck_blockmap_set(ip, block, _("file"), gfs2_inode_file))
goto bad_dinode;
break;
case S_IFLNK:
@@ -1196,8 +1227,7 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
if (set_di_nlink(ip))
goto bad_dinode;
- if (S_ISDIR(ip->i_di.di_mode) &&
- (ip->i_di.di_flags & GFS2_DIF_EXHASH)) {
+ if (is_dir(&ip->i_di, sdp->gfs1) && (ip->i_di.di_flags & GFS2_DIF_EXHASH)) {
if (((1 << ip->i_di.di_depth) * sizeof(uint64_t)) != ip->i_di.di_size){
log_warn( _("Directory dinode block #%llu (0x%llx"
") has bad depth. Found %u, Expected %u\n"),
@@ -1396,7 +1426,7 @@ static int check_system_inode(struct gfs2_sbd *sdp,
return -1;
}
}
- if (S_ISDIR((*sysinode)->i_di.di_mode)) {
+ if (is_dir(&(*sysinode)->i_di, sdp->gfs1)) {
struct block_count bc = {0};
sysdir_fxns.private = &bc;
@@ -1413,12 +1443,17 @@ static int check_system_inode(struct gfs2_sbd *sdp,
static int build_a_journal(struct gfs2_sbd *sdp)
{
char name[256];
+ int err = 0;
/* First, try to delete the journal if it's in jindex */
sprintf(name, "journal%u", sdp->md.journals);
gfs2_dirent_del(sdp->md.jiinode, name, strlen(name));
/* Now rebuild it */
- build_journal(sdp, sdp->md.journals, sdp->md.jiinode);
+ err = build_journal(sdp, sdp->md.journals, sdp->md.jiinode);
+ if (err) {
+ log_crit(_("Error %d building journal\n"), err);
+ exit(FSCK_ERROR);
+ }
return 0;
}
@@ -1432,13 +1467,15 @@ static int check_system_inodes(struct gfs2_sbd *sdp)
/* Mark the master system dinode as a "dinode" in the block map.
All other system dinodes in master will be taken care of by function
resuscitate_metalist. But master won't since it has no parent.*/
- fsck_blockmap_set(sdp->master_dir,
- sdp->master_dir->i_di.di_num.no_addr,
- "master", gfs2_inode_dir);
- if (check_system_inode(sdp, &sdp->master_dir, "master", build_master,
- gfs2_inode_dir)) {
- stack;
- return -1;
+ if (!sdp->gfs1) {
+ fsck_blockmap_set(sdp->master_dir,
+ sdp->master_dir->i_di.di_num.no_addr,
+ "master", gfs2_inode_dir);
+ if (check_system_inode(sdp, &sdp->master_dir, "master",
+ build_master, gfs2_inode_dir)) {
+ stack;
+ return -1;
+ }
}
/* Mark the root dinode as a "dinode" in the block map as we did
for master, since it has no parent. */
@@ -1449,7 +1486,8 @@ static int check_system_inodes(struct gfs2_sbd *sdp)
stack;
return -1;
}
- if (check_system_inode(sdp, &sdp->md.inum, "inum", build_inum,
+ if (!sdp->gfs1 &&
+ check_system_inode(sdp, &sdp->md.inum, "inum", build_inum,
gfs2_inode_file)) {
stack;
return -1;
@@ -1460,7 +1498,7 @@ static int check_system_inodes(struct gfs2_sbd *sdp)
return -1;
}
if (check_system_inode(sdp, &sdp->md.jiinode, "jindex", build_jindex,
- gfs2_inode_dir)) {
+ (sdp->gfs1 ? gfs2_inode_file : gfs2_inode_dir))) {
stack;
return -1;
}
@@ -1474,7 +1512,8 @@ static int check_system_inodes(struct gfs2_sbd *sdp)
stack;
return -1;
}
- if (check_system_inode(sdp, &sdp->md.pinode, "per_node",
+ if (!sdp->gfs1 &&
+ check_system_inode(sdp, &sdp->md.pinode, "per_node",
build_per_node, gfs2_inode_dir)) {
stack;
return -1;
@@ -1482,6 +1521,21 @@ static int check_system_inodes(struct gfs2_sbd *sdp)
/* We have to play a trick on build_journal: We swap md.journals
in order to keep a count of which journal we need to build. */
journal_count = sdp->md.journals;
+ /* gfs1's journals aren't dinode, they're just a bunch of blocks. */
+ if (sdp->gfs1) {
+ /* gfs1 has four dinodes that are set in the superblock and
+ therefore not linked to anything else. We need to adjust
+ the link counts so pass4 doesn't get confused. */
+ incr_link_count(sdp->md.statfs->i_di.di_num.no_addr, 0,
+ _("gfs1 statfs inode"));
+ incr_link_count(sdp->md.jiinode->i_di.di_num.no_addr, 0,
+ _("gfs1 jindex inode"));
+ incr_link_count(sdp->md.riinode->i_di.di_num.no_addr, 0,
+ _("gfs1 rindex inode"));
+ incr_link_count(sdp->md.qinode->i_di.di_num.no_addr, 0,
+ _("gfs1 quota inode"));
+ return 0;
+ }
for (sdp->md.journals = 0; sdp->md.journals < journal_count;
sdp->md.journals++) {
char jname[16];
@@ -1523,6 +1577,8 @@ int pass1(struct gfs2_sbd *sdp)
uint64_t offset;
uint64_t rg_count = 0;
+ osi_list_init(&gfs1_rindex_blks.list);
+
/* FIXME: In the gfs fsck, we had to mark things like the
* journals and indices and such as 'other_meta' - in gfs2,
* the journals are files and are found in the normal file
@@ -1553,6 +1609,7 @@ int pass1(struct gfs2_sbd *sdp)
if (gfs2_blockmap_set(bl, rgd->ri.ri_addr + i,
gfs2_indir_blk)) {
stack;
+ gfs2_special_free(&gfs1_rindex_blks);
return FSCK_ERROR;
}
/* rgrps and bitmaps don't have bits to represent
@@ -1568,13 +1625,25 @@ int pass1(struct gfs2_sbd *sdp)
while (1) {
/* "block" is relative to the entire file system */
/* Get the next dinode in the file system, according
- to the bitmap. This should ONLY be dinodes. */
+ to the bitmap. This should ONLY be dinodes unless
+ it's GFS1, in which case it can be any metadata. */
if (gfs2_next_rg_meta(rgd, &block, first))
break;
+ /* skip gfs1 rindex indirect blocks */
+ if (sdp->gfs1 && blockfind(&gfs1_rindex_blks, block)) {
+ log_debug(_("Skipping rindex indir block "
+ "%lld (0x%llx)\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ first = 0;
+ continue;
+ }
warm_fuzzy_stuff(block);
- if (fsck_abort) /* if asked to abort */
+ if (fsck_abort) { /* if asked to abort */
+ gfs2_special_free(&gfs1_rindex_blks);
return FSCK_OK;
+ }
if (skip_this_pass) {
printf( _("Skipping pass 1 is not a good idea.\n"));
skip_this_pass = FALSE;
@@ -1594,6 +1663,31 @@ int pass1(struct gfs2_sbd *sdp)
" (0x%" PRIx64 ")\n"), block, block);*/
if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
+ /* In gfs2, a bitmap mark of 2 means an inode,
+ but in gfs1 it means any metadata. So if
+ this is gfs1 and not an inode, it may be
+ okay. If it's non-dinode metadata, it will
+ be referenced by an inode, so we need to
+ skip it here and it will be sorted out
+ when the referencing inode is checked. */
+ if (sdp->gfs1) {
+ uint32_t check_magic;
+
+ check_magic = ((struct
+ gfs2_meta_header *)
+ (bh->b_data))->mh_magic;
+ if (be32_to_cpu(check_magic) ==
+ GFS2_MAGIC) {
+ log_debug( _("Deferring GFS1 "
+ "metadata block #"
+ "%" PRIu64" (0x%"
+ PRIx64 ")\n"),
+ block, block);
+ brelse(bh);
+ first = 0;
+ continue;
+ }
+ }
log_err( _("Found invalid inode at block #"
"%llu (0x%llx)\n"),
(unsigned long long)block,
@@ -1602,6 +1696,7 @@ int pass1(struct gfs2_sbd *sdp)
gfs2_block_free)) {
stack;
brelse(bh);
+ gfs2_special_free(&gfs1_rindex_blks);
return FSCK_ERROR;
}
check_n_fix_bitmap(sdp, block,
@@ -1609,6 +1704,7 @@ int pass1(struct gfs2_sbd *sdp)
} else if (handle_di(sdp, bh) < 0) {
stack;
brelse(bh);
+ gfs2_special_free(&gfs1_rindex_blks);
return FSCK_ERROR;
}
/* Ignore everything else - they should be hit by the
@@ -1621,6 +1717,19 @@ int pass1(struct gfs2_sbd *sdp)
brelse(bh);
first = 0;
}
+ /*
+ For GFS1, we have to count the "free meta" blocks in the
+ resource group and mark them specially so we can count them
+ properly in pass5.
+ */
+ if (!sdp->gfs1)
+ continue;
+ first = 1;
+ while (gfs2_next_rg_freemeta(rgd, &block, first) == 0) {
+ gfs2_blockmap_set(bl, block, gfs2_freemeta);
+ first = 0;
+ }
}
+ gfs2_special_free(&gfs1_rindex_blks);
return FSCK_OK;
}
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index a66bd8b..003d696 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -357,7 +357,8 @@ static int find_block_ref(struct gfs2_sbd *sdp, uint64_t inode)
/* Exhash dir leafs will be checked by check_metatree (right after
the "end:" label.) But if this is a linear directory we need to
check the dir with check_linear_dir. */
- if (S_ISDIR(ip->i_di.di_mode) && !(ip->i_di.di_flags & GFS2_DIF_EXHASH))
+ if (is_dir(&ip->i_di, sdp->gfs1) &&
+ !(ip->i_di.di_flags & GFS2_DIF_EXHASH))
error = check_linear_dir(ip, ip->i_bh, &find_dirents);
/* Check for ea references in the inode */
@@ -693,7 +694,7 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
_("reference-repaired data"),
gfs2_block_used);
} else if (id->reftypecount[ref_as_meta]) {
- if (S_ISDIR(ip->i_di.di_mode))
+ if (is_dir(&ip->i_di, sdp->gfs1))
fsck_blockmap_set(ip, b->block,
_("reference-repaired leaf"),
gfs2_leaf_blk);
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index a4e8dca..7e20315 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -119,31 +119,32 @@ static const char *de_type_string(uint8_t de_type)
return de_types[3]; /* invalid */
}
-static int check_file_type(uint8_t de_type, uint8_t blk_type)
+static int check_file_type(uint8_t de_type, uint8_t blk_type, int gfs1)
{
switch(blk_type) {
case gfs2_inode_dir:
- if (de_type != DT_DIR)
+ if (de_type != (gfs1 ? GFS_FILE_DIR : DT_DIR))
return 1;
break;
case gfs2_inode_file:
- if (de_type != DT_REG)
+ if (de_type != (gfs1 ? GFS_FILE_REG : DT_REG))
return 1;
break;
case gfs2_inode_lnk:
- if (de_type != DT_LNK)
+ if (de_type != (gfs1 ? GFS_FILE_LNK : DT_LNK))
return 1;
break;
case gfs2_inode_device:
- if (de_type != DT_BLK && de_type != DT_CHR)
+ if ((de_type != (gfs1 ? GFS_FILE_BLK : DT_BLK)) &&
+ (de_type != (gfs1 ? GFS_FILE_CHR : DT_CHR)))
return 1;
break;
case gfs2_inode_fifo:
- if (de_type != DT_FIFO)
+ if (de_type != (gfs1 ? GFS_FILE_FIFO : DT_FIFO))
return 1;
break;
case gfs2_inode_sock:
- if (de_type != DT_SOCK)
+ if (de_type != (gfs1 ? GFS_FILE_SOCK : DT_SOCK))
return 1;
break;
default:
@@ -391,7 +392,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
goto nuke_dentry;
}
- error = check_file_type(de->de_type, q);
+ error = check_file_type(de->de_type, q, sdp->gfs1);
if (error < 0) {
log_err( _("Error: directory entry type is "
"incompatible with block type at block %lld "
@@ -664,7 +665,9 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
memcpy(filename, tmp_name, filename_len);
log_warn( _("Adding '.' entry\n"));
dir_add(sysinode, filename, filename_len,
- &(sysinode->i_di.di_num), DT_DIR);
+ &(sysinode->i_di.di_num),
+ (sysinode->i_sbd->gfs1 ?
+ GFS_FILE_DIR : DT_DIR));
if (cur_blks != sysinode->i_di.di_blocks)
reprocess_inode(sysinode, dirname);
/* This system inode is linked to itself via '.' */
@@ -706,8 +709,11 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
*/
static inline int is_system_dir(struct gfs2_sbd *sdp, uint64_t block)
{
- if (block == sdp->md.rooti->i_di.di_num.no_addr ||
- block == sdp->md.jiinode->i_di.di_num.no_addr ||
+ if (block == sdp->md.rooti->i_di.di_num.no_addr)
+ return TRUE;
+ if (sdp->gfs1)
+ return FALSE;
+ if (block == sdp->md.jiinode->i_di.di_num.no_addr ||
block == sdp->md.pinode->i_di.di_num.no_addr ||
block == sdp->master_dir->i_di.di_num.no_addr)
return TRUE;
@@ -737,19 +743,22 @@ int pass2(struct gfs2_sbd *sdp)
int error = 0;
/* Check all the system directory inodes. */
- if (check_system_dir(sdp->md.jiinode, "jindex", build_jindex)) {
+ if (!sdp->gfs1 &&
+ check_system_dir(sdp->md.jiinode, "jindex", build_jindex)) {
stack;
return FSCK_ERROR;
}
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
return FSCK_OK;
- if (check_system_dir(sdp->md.pinode, "per_node", build_per_node)) {
+ if (!sdp->gfs1 &&
+ check_system_dir(sdp->md.pinode, "per_node", build_per_node)) {
stack;
return FSCK_ERROR;
}
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
return FSCK_OK;
- if (check_system_dir(sdp->master_dir, "master", build_master)) {
+ if (!sdp->gfs1 &&
+ check_system_dir(sdp->master_dir, "master", build_master)) {
stack;
return FSCK_ERROR;
}
@@ -870,7 +879,8 @@ int pass2(struct gfs2_sbd *sdp)
cur_blks = ip->i_di.di_blocks;
dir_add(ip, filename, filename_len,
- &(ip->i_di.di_num), DT_DIR);
+ &(ip->i_di.di_num),
+ (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
if (cur_blks != ip->i_di.di_blocks) {
char dirname[80];
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index 51104b5..e1accc9 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -52,7 +52,8 @@ static int attach_dotdot_to(struct gfs2_sbd *sdp, uint64_t newdotdot,
else
decr_link_count(olddotdot, block, _("old \"..\""));
cur_blks = ip->i_di.di_blocks;
- dir_add(ip, filename, filename_len, &pip->i_di.di_num, DT_DIR);
+ dir_add(ip, filename, filename_len, &pip->i_di.di_num,
+ (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
if (cur_blks != ip->i_di.di_blocks) {
char dirname[80];
@@ -188,10 +189,38 @@ int pass3(struct gfs2_sbd *sdp)
log_info( _("Marking root inode connected\n"));
di->checked = 1;
}
- di = dirtree_find(sdp->master_dir->i_di.di_num.no_addr);
- if (di) {
- log_info( _("Marking master directory inode connected\n"));
- di->checked = 1;
+ if (sdp->gfs1) {
+ di = dirtree_find(sdp->md.statfs->i_di.di_num.no_addr);
+ if (di) {
+ log_info( _("Marking GFS1 statfs file inode "
+ "connected\n"));
+ di->checked = 1;
+ }
+ di = dirtree_find(sdp->md.jiinode->i_di.di_num.no_addr);
+ if (di) {
+ log_info( _("Marking GFS1 jindex file inode "
+ "connected\n"));
+ di->checked = 1;
+ }
+ di = dirtree_find(sdp->md.riinode->i_di.di_num.no_addr);
+ if (di) {
+ log_info( _("Marking GFS1 rindex file inode "
+ "connected\n"));
+ di->checked = 1;
+ }
+ di = dirtree_find(sdp->md.qinode->i_di.di_num.no_addr);
+ if (di) {
+ log_info( _("Marking GFS1 quota file inode "
+ "connected\n"));
+ di->checked = 1;
+ }
+ } else {
+ di = dirtree_find(sdp->master_dir->i_di.di_num.no_addr);
+ if (di) {
+ log_info( _("Marking master directory inode "
+ "connected\n"));
+ di->checked = 1;
+ }
}
/* Go through the directory list, working up through the parents
diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c
index 32dbb72..6d933e9 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -56,6 +56,13 @@ static int scan_inode_list(struct gfs2_sbd *sdp) {
log_crit( _("osi_tree broken in scan_info_list!!\n"));
exit(FSCK_ERROR);
}
+ /* Don't check reference counts on the special gfs files */
+ if (sdp->gfs1 &&
+ ((ii->inode == sdp->md.riinode->i_di.di_num.no_addr) ||
+ (ii->inode == sdp->md.jiinode->i_di.di_num.no_addr) ||
+ (ii->inode == sdp->md.qinode->i_di.di_num.no_addr) ||
+ (ii->inode == sdp->md.statfs->i_di.di_num.no_addr)))
+ continue;
if (ii->counted_links == 0) {
log_err( _("Found unlinked inode at %llu (0x%llx)\n"),
(unsigned long long)ii->inode,
diff --git a/gfs2/fsck/pass5.c b/gfs2/fsck/pass5.c
index 29b5965..3cf420b 100644
--- a/gfs2/fsck/pass5.c
+++ b/gfs2/fsck/pass5.c
@@ -9,7 +9,7 @@
#include "fsck.h"
#include "util.h"
-static int convert_mark(uint8_t q, uint32_t *count)
+static int gfs1_convert_mark(uint8_t q, uint32_t *count)
{
switch(q) {
@@ -35,10 +35,62 @@ static int convert_mark(uint8_t q, uint32_t *count)
case gfs2_indir_blk:
case gfs2_leaf_blk:
+ /*case gfs2_meta_rgrp:*/
+ case gfs2_jdata: /* gfs1 jdata blocks count as "metadata" and gfs1
+ metadata is marked the same as gfs2 inode in the
+ bitmap. */
+ case gfs2_meta_eattr:
+ count[3]++;
+ return GFS2_BLKST_DINODE;
+
+ case gfs2_freemeta:
+ count[4]++;
+ return GFS2_BLKST_UNLINKED;
+
+ default:
+ log_err( _("Invalid block type %d found\n"), q);
+ }
+ return -1;
+}
+
+static int gfs2_convert_mark(uint8_t q, uint32_t *count)
+{
+ switch(q) {
+
+ case gfs2_meta_inval:
+ case gfs2_inode_invalid:
+ /* Convert invalid metadata to free blocks */
+ case gfs2_block_free:
+ count[0]++;
+ return GFS2_BLKST_FREE;
+
+ case gfs2_block_used:
+ count[2]++;
+ return GFS2_BLKST_USED;
+
+ case gfs2_inode_dir:
+ case gfs2_inode_file:
+ case gfs2_inode_lnk:
+ case gfs2_inode_device:
+ case gfs2_jdata: /* gfs1 jdata blocks count as "metadata" and gfs1
+ metadata is marked the same as gfs2 inode in the
+ bitmap. */
+ case gfs2_inode_fifo:
+ case gfs2_inode_sock:
+ count[1]++;
+ return GFS2_BLKST_DINODE;
+
+ case gfs2_indir_blk:
+ case gfs2_leaf_blk:
case gfs2_meta_eattr:
count[2]++;
return GFS2_BLKST_USED;
+ case gfs2_freemeta:
+ log_err( _("Invalid freemeta type %d found\n"), q);
+ count[4]++;
+ return -1;
+
default:
log_err( _("Invalid block type %d found\n"), q);
}
@@ -69,7 +121,10 @@ static int check_block_status(struct gfs2_sbd *sdp, char *buffer,
return 0;
q = block_type(block);
- block_status = convert_mark(q, count);
+ if (sdp->gfs1)
+ block_status = gfs1_convert_mark(q, count);
+ else
+ block_status = gfs2_convert_mark(q, count);
/* If one node opens a file and another node deletes it, we
may be left with a block that appears to be "unlinked" in
@@ -143,6 +198,7 @@ static void update_rgrp(struct gfs2_sbd *sdp, struct rgrp_list *rgp,
struct gfs2_bitmap *bits;
uint64_t rg_block = 0;
int update = 0;
+ struct gfs_rgrp *gfs1rg = (struct gfs_rgrp *)&rgp->rg;
for(i = 0; i < rgp->ri.ri_length; i++) {
bits = &rgp->bits[i];
@@ -174,7 +230,25 @@ static void update_rgrp(struct gfs2_sbd *sdp, struct rgrp_list *rgp,
rgp->rg.rg_dinodes = count[1];
update = 1;
}
- if ((rgp->ri.ri_data - count[0] - count[1]) != count[2]) {
+ if (sdp->gfs1 && gfs1rg->rg_usedmeta != count[3]) {
+ log_err( _("RG #%llu (0x%llx) Used metadata count "
+ "inconsistent: is %u should be %u\n"),
+ (unsigned long long)rgp->ri.ri_addr,
+ (unsigned long long)rgp->ri.ri_addr,
+ gfs1rg->rg_usedmeta, count[3]);
+ gfs1rg->rg_usedmeta = count[3];
+ update = 1;
+ }
+ if (sdp->gfs1 && gfs1rg->rg_freemeta != count[4]) {
+ log_err( _("RG #%llu (0x%llx) Free metadata count "
+ "inconsistent: is %u should be %u\n"),
+ (unsigned long long)rgp->ri.ri_addr,
+ (unsigned long long)rgp->ri.ri_addr,
+ gfs1rg->rg_freemeta, count[4]);
+ gfs1rg->rg_freemeta = count[4];
+ update = 1;
+ }
+ if (!sdp->gfs1 && (rgp->ri.ri_data - count[0] - count[1]) != count[2]) {
/* FIXME not sure how to handle this case ATM - it
* means that the total number of blocks we've counted
* exceeds the blocks in the rg */
@@ -185,7 +259,10 @@ static void update_rgrp(struct gfs2_sbd *sdp, struct rgrp_list *rgp,
if (query( _("Update resource group counts? (y/n) "))) {
log_warn( _("Resource group counts updated\n"));
/* write out the rgrp */
- gfs2_rgrp_out(&rgp->rg, rgp->bh[0]);
+ if (sdp->gfs1)
+ gfs_rgrp_out(gfs1rg, rgp->bh[0]);
+ else
+ gfs2_rgrp_out(&rgp->rg, rgp->bh[0]);
} else
log_err( _("Resource group counts left inconsistent\n"));
}
@@ -201,7 +278,7 @@ int pass5(struct gfs2_sbd *sdp)
{
osi_list_t *tmp;
struct rgrp_list *rgp = NULL;
- uint32_t count[3];
+ uint32_t count[5];
uint64_t rg_count = 0;
/* Reconcile RG bitmaps with fsck bitmap */
diff --git a/gfs2/fsck/rgrepair.c b/gfs2/fsck/rgrepair.c
index c01aaa6..28ed451 100644
--- a/gfs2/fsck/rgrepair.c
+++ b/gfs2/fsck/rgrepair.c
@@ -184,8 +184,13 @@ static uint64_t count_usedspace(struct gfs2_sbd *sdp, int first,
unsigned int state;
/* Count up the free blocks in the bitmap */
- off = (first) ? sizeof(struct gfs2_rgrp) :
- sizeof(struct gfs2_meta_header);
+ if (first) {
+ if (sdp->gfs1)
+ off = sizeof(struct gfs_rgrp);
+ else
+ off = sizeof(struct gfs2_rgrp);
+ } else
+ off = sizeof(struct gfs2_meta_header);
bytes_to_check = sdp->bsize - off;
for (x = 0; x < bytes_to_check; x++) {
unsigned char *byte;
@@ -681,12 +686,19 @@ static int rewrite_rg_block(struct gfs2_sbd *sdp, struct rgrp_list *rg,
mh.mh_format = GFS2_FORMAT_RB;
gfs2_meta_header_out(&mh, rg->bh[x]);
} else {
- memset(&rg->rg, 0, sizeof(struct gfs2_rgrp));
+ if (sdp->gfs1)
+ memset(&rg->rg, 0, sizeof(struct gfs_rgrp));
+ else
+ memset(&rg->rg, 0, sizeof(struct gfs2_rgrp));
rg->rg.rg_header.mh_magic = GFS2_MAGIC;
rg->rg.rg_header.mh_type = GFS2_METATYPE_RG;
rg->rg.rg_header.mh_format = GFS2_FORMAT_RG;
rg->rg.rg_free = rg->ri.ri_data;
- gfs2_rgrp_out(&rg->rg, rg->bh[x]);
+ if (sdp->gfs1)
+ gfs_rgrp_out((struct gfs_rgrp *)&rg->rg,
+ rg->bh[x]);
+ else
+ gfs2_rgrp_out(&rg->rg, rg->bh[x]);
}
brelse(rg->bh[x]);
rg->bh[x] = NULL;
diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h
index 106cca8..9b2de61 100644
--- a/gfs2/fsck/util.h
+++ b/gfs2/fsck/util.h
@@ -1,6 +1,8 @@
#ifndef __UTIL_H__
#define __UTIL_H__
+#include <sys/stat.h>
+
#include "fsck.h"
#include "libgfs2.h"
@@ -42,15 +44,15 @@ enum gfs2_mark_block {
gfs2_inode_file = (0x4),
gfs2_inode_lnk = (0x5),
- gfs2_inode_device = (0x6),
-
+ gfs2_inode_device = (0x6), /* char or block device */
+ gfs2_jdata = (0x7), /* gfs journaled data blocks */
gfs2_inode_fifo = (0x8),
gfs2_inode_sock = (0x9),
gfs2_inode_invalid = (0xa),
gfs2_meta_inval = (0xb),
gfs2_leaf_blk = (0xc),
-
+ gfs2_freemeta = (0xd), /* was: gfs2_meta_rgrp */
gfs2_meta_eattr = (0xe),
gfs2_bad_block = (0xf), /* Contains at least one bad block */
@@ -67,14 +69,14 @@ static const inline char *block_type_string(uint8_t q)
"symlink",
"device",
- "",
+ "journaled data",
"fifo",
"socket",
"invalid inode",
"invalid meta",
"dir leaf",
- "",
+ "free metadata",
"eattribute",
"bad"};
@@ -85,30 +87,82 @@ static const inline char *block_type_string(uint8_t q)
/* Must be kept in sync with gfs2_mark_block enum above. Blocks marked as
invalid or bad are considered metadata until actually freed. */
-static inline int blockmap_to_bitmap(enum gfs2_mark_block m)
+static inline int blockmap_to_bitmap(enum gfs2_mark_block m, int gfs1)
{
- static int bitmap_states[16] = {
- GFS2_BLKST_FREE, /* free */
- GFS2_BLKST_USED, /* data */
- GFS2_BLKST_USED, /* indirect data or rgrp meta*/
- GFS2_BLKST_DINODE, /* directory */
- GFS2_BLKST_DINODE, /* file */
-
- GFS2_BLKST_DINODE, /* symlink */
- GFS2_BLKST_DINODE, /* block or char device */
- GFS2_BLKST_USED, /* reserved */
- GFS2_BLKST_DINODE, /* fifo */
- GFS2_BLKST_DINODE, /* socket */
-
- GFS2_BLKST_FREE, /* invalid inode */
- GFS2_BLKST_FREE, /* invalid meta */
- GFS2_BLKST_USED, /* dir leaf */
- GFS2_BLKST_UNLINKED, /* unused */
- GFS2_BLKST_USED, /* eattribute */
-
- GFS2_BLKST_USED, /* bad */
- };
- return bitmap_states[m];
+ static int bitmap_states[2][16] = {
+ /* ---------------------- gfs2 ------------------------------*/
+ {GFS2_BLKST_FREE, /* free */
+ GFS2_BLKST_USED, /* data */
+ GFS2_BLKST_USED, /* indirect data or rgrp meta */
+ GFS2_BLKST_DINODE, /* directory */
+ GFS2_BLKST_DINODE, /* file */
+
+ GFS2_BLKST_DINODE, /* symlink */
+ GFS2_BLKST_DINODE, /* block or char device */
+ GFS2_BLKST_USED, /* journaled data */
+ GFS2_BLKST_DINODE, /* fifo */
+ GFS2_BLKST_DINODE, /* socket */
+
+ GFS2_BLKST_FREE, /* invalid inode */
+ GFS2_BLKST_FREE, /* invalid meta */
+ GFS2_BLKST_USED, /* dir leaf */
+ GFS2_BLKST_UNLINKED, /* GFS unlinked metadata */
+ GFS2_BLKST_USED, /* eattribute */
+
+ GFS2_BLKST_USED}, /* bad */
+ /* ---------------------- gfs1 ----------------------------- */
+ {GFS2_BLKST_FREE, /* free */
+ GFS2_BLKST_USED, /* data */
+ GFS2_BLKST_DINODE, /* indirect data or rgrp meta*/
+ GFS2_BLKST_DINODE, /* directory */
+ GFS2_BLKST_DINODE, /* file */
+
+ GFS2_BLKST_DINODE, /* symlink */
+ GFS2_BLKST_DINODE, /* block or char device */
+ GFS2_BLKST_DINODE, /* journaled data */
+ GFS2_BLKST_DINODE, /* fifo */
+ GFS2_BLKST_DINODE, /* socket */
+
+ GFS2_BLKST_FREE, /* invalid inode */
+ GFS2_BLKST_FREE, /* invalid meta */
+ GFS2_BLKST_DINODE, /* dir leaf */
+ GFS2_BLKST_UNLINKED, /* GFS unlinked metadata */
+ GFS2_BLKST_DINODE, /* eattribute */
+
+ GFS2_BLKST_USED}}; /* bad */
+ return bitmap_states[gfs1][m];
+}
+
+static inline int is_dir(struct gfs2_dinode *dinode, int gfs1)
+{
+ if (gfs1 && is_gfs_dir(dinode))
+ return 1;
+ if (S_ISDIR(dinode->di_mode))
+ return 1;
+
+ return 0;
+}
+
+static inline uint32_t gfs_to_gfs2_mode(uint32_t gfs1mode)
+{
+ switch (gfs1mode) {
+ case GFS_FILE_DIR:
+ return S_IFDIR;
+ case GFS_FILE_REG:
+ return S_IFREG;
+ case GFS_FILE_LNK:
+ return S_IFLNK;
+ case GFS_FILE_BLK:
+ return S_IFBLK;
+ case GFS_FILE_CHR:
+ return S_IFCHR;
+ case GFS_FILE_FIFO:
+ return S_IFIFO;
+ case GFS_FILE_SOCK:
+ return S_IFSOCK;
+ default:
+ return S_IFREG;
+ }
}
extern struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size,
@@ -116,5 +170,4 @@ extern struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size,
extern void *gfs2_bmap_destroy(struct gfs2_sbd *sdp, struct gfs2_bmap *il);
extern int gfs2_blockmap_set(struct gfs2_bmap *il, uint64_t block,
enum gfs2_mark_block mark);
-
#endif /* __UTIL_H__ */
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 58442e8..b1574fb 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -723,6 +723,9 @@ extern int gfs2_next_rg_meta(struct rgrp_list *rgd, uint64_t *block,
int first);
extern int gfs2_next_rg_metatype(struct gfs2_sbd *sdp, struct rgrp_list *rgd,
uint64_t *block, uint32_t type, int first);
+extern int gfs2_next_rg_freemeta(struct rgrp_list *rgd, uint64_t *block,
+ int first);
+
/* super.c */
extern int check_sb(struct gfs2_sb *sb, int allow_gfs);
extern int read_sb(struct gfs2_sbd *sdp, int allow_gfs);
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index 7dabd80..f53b4af 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -459,39 +459,50 @@ int gfs2_check_meta(struct gfs2_buffer_head *bh, int type)
*
* Returns: 0 on success, -1 when finished
*/
-int gfs2_next_rg_meta(struct rgrp_list *rgd, uint64_t *block, int first)
+static int __gfs2_next_rg_meta(struct rgrp_list *rgd, uint64_t *block,
+ int first, unsigned char state)
{
struct gfs2_bitmap *bits = NULL;
uint32_t length = rgd->ri.ri_length;
- uint32_t blk = (first)? 0: (uint32_t)((*block+1)-rgd->ri.ri_data0);
+ uint32_t blk = (first)? 0: (uint32_t)((*block + 1) - rgd->ri.ri_data0);
int i;
if(!first && (*block < rgd->ri.ri_data0)) {
log_err("next_rg_meta: Start block is outside rgrp bounds.\n");
exit(1);
}
- for(i=0; i < length; i++){
+ for(i = 0; i < length; i++){
bits = &rgd->bits[i];
- if(blk < bits->bi_len*GFS2_NBBY)
+ if (blk < bits->bi_len * GFS2_NBBY)
break;
- blk -= bits->bi_len*GFS2_NBBY;
+ blk -= bits->bi_len * GFS2_NBBY;
}
for(; i < length; i++){
bits = &rgd->bits[i];
blk = gfs2_bitfit((unsigned char *)rgd->bh[i]->b_data +
- bits->bi_offset, bits->bi_len, blk,
- GFS2_BLKST_DINODE);
+ bits->bi_offset, bits->bi_len, blk, state);
if(blk != BFITNOENT){
- *block = blk + (bits->bi_start * GFS2_NBBY) + rgd->ri.ri_data0;
+ *block = blk + (bits->bi_start * GFS2_NBBY) +
+ rgd->ri.ri_data0;
break;
}
- blk=0;
+ blk = 0;
}
if(i == length)
return -1;
return 0;
}
+int gfs2_next_rg_meta(struct rgrp_list *rgd, uint64_t *block, int first)
+{
+ return __gfs2_next_rg_meta(rgd, block, first, GFS2_BLKST_DINODE);
+}
+
+int gfs2_next_rg_freemeta(struct rgrp_list *rgd, uint64_t *block, int first)
+{
+ return __gfs2_next_rg_meta(rgd, block, first, GFS2_BLKST_UNLINKED);
+}
+
/**
* next_rg_metatype
* @rgd:
--
1.7.7.5
More information about the Cluster-devel
mailing list