|
Packit Service |
360c39 |
#include "clusterautoconfig.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include <stdio.h>
|
|
Packit Service |
360c39 |
#include <string.h>
|
|
Packit Service |
360c39 |
#include <inttypes.h>
|
|
Packit Service |
360c39 |
#include <stdlib.h>
|
|
Packit Service |
360c39 |
#include <libintl.h>
|
|
Packit Service |
360c39 |
#define _(String) gettext(String)
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include <logging.h>
|
|
Packit Service |
360c39 |
#include "libgfs2.h"
|
|
Packit Service |
360c39 |
#include "fsck.h"
|
|
Packit Service |
360c39 |
#include "util.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#define GFS1_BLKST_USEDMETA 4
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int check_block_status(struct gfs2_sbd *sdp, struct gfs2_bmap *bl,
|
|
Packit Service |
360c39 |
char *buffer, unsigned int buflen,
|
|
Packit Service |
360c39 |
uint64_t *rg_block, uint64_t rg_data,
|
|
Packit Service |
360c39 |
uint32_t *count)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
unsigned char *byte, *end;
|
|
Packit Service |
360c39 |
unsigned int bit;
|
|
Packit Service |
360c39 |
unsigned char rg_status;
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
uint64_t block;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* FIXME verify cast */
|
|
Packit Service |
360c39 |
byte = (unsigned char *) buffer;
|
|
Packit Service |
360c39 |
bit = 0;
|
|
Packit Service |
360c39 |
end = (unsigned char *) buffer + buflen;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (byte < end) {
|
|
Packit Service |
360c39 |
rg_status = ((*byte >> bit) & GFS2_BIT_MASK);
|
|
Packit Service |
360c39 |
block = rg_data + *rg_block;
|
|
Packit Service |
360c39 |
warm_fuzzy_stuff(block);
|
|
Packit Service |
360c39 |
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
q = block_type(bl, block);
|
|
Packit Service |
360c39 |
/* GFS1 file systems will have to suffer from slower fsck run
|
|
Packit Service |
360c39 |
* times because in GFS, there's no 1:1 relationship between
|
|
Packit Service |
360c39 |
* bits and counts. If a bit is marked "dinode" in GFS1, it
|
|
Packit Service |
360c39 |
* may be dinode -OR- any kind of metadata. I consider GFS1 to
|
|
Packit Service |
360c39 |
* be a rare exception, so acceptable loss at this point. So
|
|
Packit Service |
360c39 |
* we must determine whether it's really a dinode or other
|
|
Packit Service |
360c39 |
* metadata by reading it in. */
|
|
Packit Service |
360c39 |
if (sdp->gfs1 && q == GFS2_BLKST_DINODE) {
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bh = bread(sdp, block);
|
|
Packit Service |
360c39 |
if (gfs2_check_meta(bh, GFS2_METATYPE_DI) == 0)
|
|
Packit Service |
360c39 |
count[GFS2_BLKST_DINODE]++;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
count[GFS1_BLKST_USEDMETA]++;
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
count[q]++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* If one node opens a file and another node deletes it, we
|
|
Packit Service |
360c39 |
may be left with a block that appears to be "unlinked" in
|
|
Packit Service |
360c39 |
the bitmap, but nothing links to it. This is a valid case
|
|
Packit Service |
360c39 |
and should be cleaned up by the file system eventually.
|
|
Packit Service |
360c39 |
So we ignore it. */
|
|
Packit Service |
360c39 |
if (q == GFS2_BLKST_UNLINKED) {
|
|
Packit Service |
360c39 |
log_err( _("Unlinked inode found at block %llu "
|
|
Packit Service |
360c39 |
"(0x%llx).\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
if (query(_("Do you want to reclaim the block? "
|
|
Packit Service |
360c39 |
"(y/n) "))) {
|
|
Packit Service |
360c39 |
lgfs2_rgrp_t rg = gfs2_blk2rgrpd(sdp, block);
|
|
Packit Service |
360c39 |
if (gfs2_set_bitmap(rg, block, GFS2_BLKST_FREE))
|
|
Packit Service |
360c39 |
log_err(_("Unlinked block %llu "
|
|
Packit Service |
360c39 |
"(0x%llx) bitmap not fixed."
|
|
Packit Service |
360c39 |
"\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
else {
|
|
Packit Service |
360c39 |
log_err(_("Unlinked block %llu "
|
|
Packit Service |
360c39 |
"(0x%llx) bitmap fixed.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
count[GFS2_BLKST_UNLINKED]--;
|
|
Packit Service |
360c39 |
count[GFS2_BLKST_FREE]++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
log_info( _("Unlinked block found at block %llu"
|
|
Packit Service |
360c39 |
" (0x%llx), left unchanged.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
} else if (rg_status != q) {
|
|
Packit Service |
360c39 |
log_err( _("Block %llu (0x%llx) bitmap says %u (%s) "
|
|
Packit Service |
360c39 |
"but FSCK saw %u (%s)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block, rg_status,
|
|
Packit Service |
360c39 |
block_type_string(rg_status), q,
|
|
Packit Service |
360c39 |
block_type_string(q));
|
|
Packit Service |
360c39 |
if (q) /* Don't print redundant "free" */
|
|
Packit Service |
360c39 |
log_err( _("Metadata type is %u (%s)\n"), q,
|
|
Packit Service |
360c39 |
block_type_string(q));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (query(_("Fix bitmap for block %llu (0x%llx) ? (y/n) "),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block)) {
|
|
Packit Service |
360c39 |
lgfs2_rgrp_t rg = gfs2_blk2rgrpd(sdp, block);
|
|
Packit Service |
360c39 |
if (gfs2_set_bitmap(rg, block, q))
|
|
Packit Service |
360c39 |
log_err( _("Repair failed.\n"));
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
log_err( _("Fixed.\n"));
|
|
Packit Service |
360c39 |
} else
|
|
Packit Service |
360c39 |
log_err( _("Bitmap at block %llu (0x%llx) left inconsistent\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
(*rg_block)++;
|
|
Packit Service |
360c39 |
bit += GFS2_BIT_SIZE;
|
|
Packit Service |
360c39 |
if (bit >= 8){
|
|
Packit Service |
360c39 |
bit = 0;
|
|
Packit Service |
360c39 |
byte++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void update_rgrp(struct gfs2_sbd *sdp, struct rgrp_tree *rgp,
|
|
Packit Service |
360c39 |
struct gfs2_bmap *bl, uint32_t *count)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint32_t i;
|
|
Packit Service |
360c39 |
struct gfs2_bitmap *bits;
|
|
Packit Service |
360c39 |
uint64_t rg_block = 0;
|
|
Packit Service |
360c39 |
int update = 0;
|
|
Packit Service |
360c39 |
struct gfs_rgrp *gfs1rg = (struct gfs_rgrp *)&rgp->rg;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for(i = 0; i < rgp->ri.ri_length; i++) {
|
|
Packit Service |
360c39 |
bits = &rgp->bits[i];
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* update the bitmaps */
|
|
Packit Service |
360c39 |
if (check_block_status(sdp, bl, bits->bi_bh->b_data + bits->bi_offset,
|
|
Packit Service |
360c39 |
bits->bi_len, &rg_block, rgp->ri.ri_data0, count))
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* actually adjust counters and write out to disk */
|
|
Packit Service |
360c39 |
if (rgp->rg.rg_free != count[GFS2_BLKST_FREE]) {
|
|
Packit Service |
360c39 |
log_err( _("RG #%llu (0x%llx) free count inconsistent: "
|
|
Packit Service |
360c39 |
"is %u should be %u\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)rgp->ri.ri_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)rgp->ri.ri_addr,
|
|
Packit Service |
360c39 |
rgp->rg.rg_free, count[GFS2_BLKST_FREE]);
|
|
Packit Service |
360c39 |
rgp->rg.rg_free = count[GFS2_BLKST_FREE];
|
|
Packit Service |
360c39 |
update = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (rgp->rg.rg_dinodes != count[GFS2_BLKST_DINODE]) {
|
|
Packit Service |
360c39 |
log_err( _("RG #%llu (0x%llx) Inode count inconsistent: is "
|
|
Packit Service |
360c39 |
"%u should be %u\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)rgp->ri.ri_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)rgp->ri.ri_addr,
|
|
Packit Service |
360c39 |
rgp->rg.rg_dinodes, count[GFS2_BLKST_DINODE]);
|
|
Packit Service |
360c39 |
rgp->rg.rg_dinodes = count[GFS2_BLKST_DINODE];
|
|
Packit Service |
360c39 |
update = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (sdp->gfs1 && gfs1rg->rg_usedmeta != count[GFS1_BLKST_USEDMETA]) {
|
|
Packit Service |
360c39 |
log_err( _("RG #%llu (0x%llx) Used metadata count "
|
|
Packit Service |
360c39 |
"inconsistent: is %u should be %u\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)rgp->ri.ri_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)rgp->ri.ri_addr,
|
|
Packit Service |
360c39 |
gfs1rg->rg_usedmeta, count[GFS1_BLKST_USEDMETA]);
|
|
Packit Service |
360c39 |
gfs1rg->rg_usedmeta = count[GFS1_BLKST_USEDMETA];
|
|
Packit Service |
360c39 |
update = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (sdp->gfs1 && gfs1rg->rg_freemeta != count[GFS2_BLKST_UNLINKED]) {
|
|
Packit Service |
360c39 |
log_err( _("RG #%llu (0x%llx) Free metadata count "
|
|
Packit Service |
360c39 |
"inconsistent: is %u should be %u\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)rgp->ri.ri_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)rgp->ri.ri_addr,
|
|
Packit Service |
360c39 |
gfs1rg->rg_freemeta, count[GFS2_BLKST_UNLINKED]);
|
|
Packit Service |
360c39 |
gfs1rg->rg_freemeta = count[GFS2_BLKST_UNLINKED];
|
|
Packit Service |
360c39 |
update = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!sdp->gfs1 && (rgp->ri.ri_data != count[GFS2_BLKST_FREE] +
|
|
Packit Service |
360c39 |
count[GFS2_BLKST_USED] +
|
|
Packit Service |
360c39 |
count[GFS2_BLKST_UNLINKED] +
|
|
Packit Service |
360c39 |
count[GFS2_BLKST_DINODE])) {
|
|
Packit Service |
360c39 |
/* FIXME not sure how to handle this case ATM - it
|
|
Packit Service |
360c39 |
* means that the total number of blocks we've counted
|
|
Packit Service |
360c39 |
* exceeds the blocks in the rg */
|
|
Packit Service |
360c39 |
log_err( _("Internal fsck error: %u != %u + %u + %u + %u\n"),
|
|
Packit Service |
360c39 |
rgp->ri.ri_data, count[GFS2_BLKST_FREE],
|
|
Packit Service |
360c39 |
count[GFS2_BLKST_USED], count[GFS2_BLKST_UNLINKED],
|
|
Packit Service |
360c39 |
count[GFS2_BLKST_DINODE]);
|
|
Packit Service |
360c39 |
exit(FSCK_ERROR);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (update) {
|
|
Packit Service |
360c39 |
if (query( _("Update resource group counts? (y/n) "))) {
|
|
Packit Service |
360c39 |
log_warn( _("Resource group counts updated\n"));
|
|
Packit Service |
360c39 |
/* write out the rgrp */
|
|
Packit Service |
360c39 |
if (sdp->gfs1)
|
|
Packit Service |
360c39 |
gfs_rgrp_out(gfs1rg, rgp->bits[0].bi_bh);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
gfs2_rgrp_out(&rgp->rg, rgp->bits[0].bi_bh->b_data);
|
|
Packit Service |
360c39 |
} else
|
|
Packit Service |
360c39 |
log_err( _("Resource group counts left inconsistent\n"));
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* pass5 - check resource groups
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* fix free block maps
|
|
Packit Service |
360c39 |
* fix used inode maps
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int pass5(struct gfs2_sbd *sdp, struct gfs2_bmap *bl)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct osi_node *n, *next = NULL;
|
|
Packit Service |
360c39 |
struct rgrp_tree *rgp = NULL;
|
|
Packit Service |
360c39 |
uint32_t count[5]; /* we need 5 because of GFS1 usedmeta */
|
|
Packit Service |
360c39 |
uint64_t rg_count = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Reconcile RG bitmaps with fsck bitmap */
|
|
Packit Service |
360c39 |
for (n = osi_first(&sdp->rgtree); n; n = next) {
|
|
Packit Service |
360c39 |
next = osi_next(n);
|
|
Packit Service |
360c39 |
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
|
|
Packit Service |
360c39 |
return FSCK_OK;
|
|
Packit Service |
360c39 |
log_info( _("Verifying Resource Group #%llu\n"), (unsigned long long)rg_count);
|
|
Packit Service |
360c39 |
memset(count, 0, sizeof(count));
|
|
Packit Service |
360c39 |
rgp = (struct rgrp_tree *)n;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rg_count++;
|
|
Packit Service |
360c39 |
/* Compare the bitmaps and report the differences */
|
|
Packit Service |
360c39 |
update_rgrp(sdp, rgp, bl, count);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Fix up superblock info based on this - don't think there's
|
|
Packit Service |
360c39 |
* anything to do here... */
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return FSCK_OK;
|
|
Packit Service |
360c39 |
}
|