From mboxrd@z Thu Jan 1 00:00:00 1970 From: Bob Peterson Date: Thu, 11 Aug 2011 17:19:25 -0400 (EDT) Subject: [Cluster-devel] [Patch 44/44] fsck.gfs2: Add ability to check gfs1 file systems Message-ID: <311698914.545028.1313097565320.JavaMail.root@zmail06.collab.prod.int.phx2.redhat.com> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit >From e6dd8021b94ad3a4b1dcf9764a2909b9a29bf953 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 11 Aug 2011 14:51:08 -0500 Subject: [PATCH 44/44] 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 | 13 ++ gfs2/fsck/initialize.c | 300 +++++++++++++++++++++++++++++++++----------- gfs2/fsck/lost_n_found.c | 118 +++++++++++++----- gfs2/fsck/main.c | 14 ++- gfs2/fsck/metawalk.c | 88 ++++++++++---- gfs2/fsck/pass1.c | 197 ++++++++++++++++++++++------- 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 | 25 +++- gfs2/fsck/util.h | 77 +++++++----- gfs2/libgfs2/libgfs2.h | 3 + gfs2/libgfs2/structures.c | 29 +++-- 16 files changed, 817 insertions(+), 265 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..260c42c 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,16 @@ 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; + +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; +} + #endif /* _FSCK_H */ diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c index 2d667fc..033ede0 100644 --- a/gfs2/fsck/initialize.c +++ b/gfs2/fsck/initialize.c @@ -194,12 +194,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 +249,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 +274,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 +565,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 +587,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) "))) { @@ -616,38 +648,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 +711,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 +853,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 +897,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 +939,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 +1074,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 +1084,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 @@ -1177,19 +1234,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 */ + sdp->gfs1 = read_sb(sdp, 1); + if (sdp->gfs1 < 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) + sdp->gfs1 = read_sb(sdp, 1); + if (sdp->gfs1 < 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,24 +1408,27 @@ 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, sdp->sd_sb.sb_master_dir.no_addr); } - /* 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); - /* 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..0a5c32d 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 " @@ -82,10 +82,49 @@ static void add_dotdot(struct gfs2_inode *ip) 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 * @@ -105,19 +144,30 @@ int add_inode_to_lf(struct gfs2_inode *ip){ if (!lf_dip) { uint8_t q; + unsigned int mode; 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 +194,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,48 +214,46 @@ 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){ - case S_IFDIR: + if ((ip->i_di.di_mode & S_IFMT) == S_IFDIR || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_DIR)) { add_dotdot(ip); sprintf(tmp_name, "lost_dir_%llu", (unsigned long long)ip->i_di.di_num.no_addr); - inode_type = DT_DIR; - break; - case S_IFREG: + inode_type = (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR); + } else if ((ip->i_di.di_mode & S_IFMT) == S_IFREG || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_REG)) { sprintf(tmp_name, "lost_file_%llu", (unsigned long long)ip->i_di.di_num.no_addr); - inode_type = DT_REG; - break; - case S_IFLNK: + inode_type = (sdp->gfs1 ? GFS_FILE_REG : DT_REG); + } else if ((ip->i_di.di_mode & S_IFMT) == S_IFLNK || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_LNK)) { sprintf(tmp_name, "lost_link_%llu", (unsigned long long)ip->i_di.di_num.no_addr); - inode_type = DT_LNK; - break; - case S_IFBLK: + inode_type = (sdp->gfs1 ? GFS_FILE_LNK : DT_LNK); + } else if ((ip->i_di.di_mode & S_IFMT) == S_IFBLK || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_BLK)) { sprintf(tmp_name, "lost_blkdev_%llu", (unsigned long long)ip->i_di.di_num.no_addr); - inode_type = DT_BLK; - break; - case S_IFCHR: + inode_type = (sdp->gfs1 ? GFS_FILE_BLK : DT_BLK); + } else if ((ip->i_di.di_mode & S_IFMT) == S_IFCHR || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_CHR)) { sprintf(tmp_name, "lost_chrdev_%llu", (unsigned long long)ip->i_di.di_num.no_addr); - inode_type = DT_CHR; - break; - case S_IFIFO: + inode_type = (sdp->gfs1 ? GFS_FILE_CHR : DT_CHR); + } else if ((ip->i_di.di_mode & S_IFMT) == S_IFIFO || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_FIFO)) { sprintf(tmp_name, "lost_fifo_%llu", (unsigned long long)ip->i_di.di_num.no_addr); - inode_type = DT_FIFO; - break; - case S_IFSOCK: + inode_type = (sdp->gfs1 ? GFS_FILE_FIFO : DT_FIFO); + } else if ((ip->i_di.di_mode & S_IFMT) == S_IFSOCK || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_SOCK)) { sprintf(tmp_name, "lost_socket_%llu", (unsigned long long)ip->i_di.di_num.no_addr); - inode_type = DT_SOCK; - break; - default: + inode_type = (sdp->gfs1 ? GFS_FILE_SOCK : DT_SOCK); + } else { sprintf(tmp_name, "lost_%llu", (unsigned long long)ip->i_di.di_num.no_addr); - inode_type = DT_REG; - break; + inode_type = (sdp->gfs1 ? GFS_FILE_REG : DT_REG); } err = dir_add(lf_dip, tmp_name, strlen(tmp_name), &(ip->i_di.di_num), @@ -211,7 +261,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 +272,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 c6444c8..4b5f3f4 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,11 +464,12 @@ 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. */ +/* 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 () */ @@ -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 afb5925..df7ec1d 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; @@ -377,7 +386,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 { @@ -445,7 +454,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; @@ -522,7 +531,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; } @@ -1016,6 +1040,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, @@ -1128,46 +1153,43 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip) return 0; } - switch(ip->i_di.di_mode & S_IFMT) { - - case S_IFDIR: + if ((ip->i_di.di_mode & S_IFMT) == S_IFDIR || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_DIR)) { 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)) + } else if ((ip->i_di.di_mode & S_IFMT) == S_IFREG || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_REG)) { + if (fsck_blockmap_set(ip, block, _("file"), gfs2_inode_file)) goto bad_dinode; - break; - case S_IFLNK: + } else if ((ip->i_di.di_mode & S_IFMT) == S_IFLNK || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_LNK)) { if (fsck_blockmap_set(ip, block, _("symlink"), gfs2_inode_lnk)) goto bad_dinode; - break; - case S_IFBLK: + } else if ((ip->i_di.di_mode & S_IFMT) == S_IFBLK || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_BLK)) { if (fsck_blockmap_set(ip, block, _("block device"), gfs2_inode_device)) goto bad_dinode; - break; - case S_IFCHR: + } else if ((ip->i_di.di_mode & S_IFMT) == S_IFCHR || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_CHR)) { if (fsck_blockmap_set(ip, block, _("character device"), gfs2_inode_device)) goto bad_dinode; - break; - case S_IFIFO: + } else if ((ip->i_di.di_mode & S_IFMT) == S_IFIFO || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_FIFO)) { if (fsck_blockmap_set(ip, block, _("fifo"), gfs2_inode_fifo)) goto bad_dinode; - break; - case S_IFSOCK: + } else if ((ip->i_di.di_mode & S_IFMT) == S_IFSOCK || + (sdp->gfs1 && ip->i_di.__pad1 == GFS_FILE_SOCK)) { if (fsck_blockmap_set(ip, block, _("socket"), gfs2_inode_sock)) goto bad_dinode; - break; - default: + } else { /* 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 @@ -1192,8 +1214,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"), @@ -1395,7 +1416,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; @@ -1421,7 +1442,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; } @@ -1436,13 +1457,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. */ @@ -1453,7 +1476,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; @@ -1464,7 +1488,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; } @@ -1478,7 +1502,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; @@ -1486,6 +1511,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,8 +1563,12 @@ int pass1(struct gfs2_sbd *sdp) struct rgrp_list *rgd; int first; uint64_t i; + uint64_t blk_count; + 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 @@ -1555,6 +1599,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 @@ -1563,18 +1608,33 @@ int pass1(struct gfs2_sbd *sdp) gfs2_meta_rgrp);*/ } + offset = (sdp->gfs1 ? sizeof(struct gfs_rgrp) : + sizeof(struct gfs2_rgrp)); + blk_count = 1; first = 1; 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; @@ -1590,7 +1650,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, @@ -1599,6 +1687,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, @@ -1606,6 +1695,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 @@ -1618,6 +1708,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 f744eae..e514575 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 */ @@ -697,7 +698,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@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 911aad3..f452d29 100644 --- a/gfs2/fsck/rgrepair.c +++ b/gfs2/fsck/rgrepair.c @@ -152,9 +152,8 @@ static uint64_t find_shortest_rgdist(struct gfs2_sbd *sdp, if (*first_rg_dist >= shortest_dist_btwn_rgs + (shortest_dist_btwn_rgs / 4)) { /* read in the second RG index entry for this subd. */ - gfs2_readi(sdp->md.riinode, (char *)&buf, - sizeof(struct gfs2_rindex), - sizeof(struct gfs2_rindex)); + gfs2_readi(sdp->md.riinode, (char *)&buf, risize(sdp), + risize(sdp)); gfs2_rindex_in(&tmpndx, (char *)&buf); if (tmpndx.ri_addr > sdp->sb_addr + 1) { /* sanity check */ log_warn( _("rgrp 2 is damaged: getting dist from index: ")); @@ -187,8 +186,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 +689,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..add97b4 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_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 +67,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 +85,50 @@ 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]; } extern struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size, @@ -116,5 +136,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 7ec38a5..04de28f 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: -- 1.7.4.4