|
Packit |
6ef888 |
#include "clusterautoconfig.h"
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#include <unistd.h>
|
|
Packit |
6ef888 |
#include <inttypes.h>
|
|
Packit |
6ef888 |
#include <stdio.h>
|
|
Packit |
6ef888 |
#include <stdint.h>
|
|
Packit |
6ef888 |
#include <stdlib.h>
|
|
Packit |
6ef888 |
#include <string.h>
|
|
Packit |
6ef888 |
#include <errno.h>
|
|
Packit |
6ef888 |
#include <libintl.h>
|
|
Packit |
6ef888 |
#define _(String) gettext(String)
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#include <logging.h>
|
|
Packit |
6ef888 |
#include "libgfs2.h"
|
|
Packit |
6ef888 |
#include "osi_list.h"
|
|
Packit |
6ef888 |
#include "fsck.h"
|
|
Packit |
6ef888 |
#include "fs_recovery.h"
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
int rindex_modified = FALSE;
|
|
Packit |
6ef888 |
struct special_blocks false_rgrps;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#define BAD_RG_PERCENT_TOLERANCE 11
|
|
Packit |
6ef888 |
#define AWAY_FROM_BITMAPS 0x1000
|
|
Packit |
6ef888 |
#define MAX_RGSEGMENTS 20
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#define ri_equal(ondisk, expected, field) (ondisk.field == expected.field)
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#define ri_compare(rg, ondisk, expected, field, fmt, type) \
|
|
Packit |
6ef888 |
if (ondisk.field != expected.field) { \
|
|
Packit |
6ef888 |
log_warn( _("rindex #%d " #field " discrepancy: index 0x%" \
|
|
Packit |
6ef888 |
fmt " != expected: 0x%" fmt "\n"), \
|
|
Packit |
6ef888 |
rg + 1, (type)ondisk.field, (type)expected.field); \
|
|
Packit |
6ef888 |
ondisk.field = expected.field; \
|
|
Packit |
6ef888 |
rindex_modified = TRUE; \
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* find_journal_entry_rgs - find all RG blocks within all journals
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Since Resource Groups (RGs) are journaled, it is not uncommon for them
|
|
Packit |
6ef888 |
* to appear inside a journal. But if there is severe damage to the rindex
|
|
Packit |
6ef888 |
* file or some of the RGs, we may need to hunt and peck for RGs and in that
|
|
Packit |
6ef888 |
* case, we don't want to mistake these blocks that look just a real RG
|
|
Packit |
6ef888 |
* for a real RG block. These are "fake" RGs that need to be ignored for
|
|
Packit |
6ef888 |
* the purposes of finding where things are.
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* NOTE: This function assumes that the jindex and journals have been read in,
|
|
Packit |
6ef888 |
* which isn't often the case. Normally the rindex needs to be read in
|
|
Packit |
6ef888 |
* first. If the rindex is damaged, that's not an option.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static void find_journaled_rgs(struct gfs2_sbd *sdp)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
int j, new = 0;
|
|
Packit |
6ef888 |
unsigned int jblocks;
|
|
Packit |
6ef888 |
uint64_t b, dblock;
|
|
Packit |
6ef888 |
struct gfs2_inode *ip;
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh;
|
|
Packit |
6ef888 |
int false_count;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
osi_list_init(&false_rgrps.list);
|
|
Packit |
6ef888 |
for (j = 0; j < sdp->md.journals; j++) {
|
|
Packit |
6ef888 |
ip = sdp->md.journal[j];
|
|
Packit |
6ef888 |
log_debug(_("Checking for rgrps in journal%d which starts "
|
|
Packit |
6ef888 |
"at block 0x%llx.\n"), j,
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
jblocks = ip->i_di.di_size / sdp->sd_sb.sb_bsize;
|
|
Packit |
6ef888 |
false_count = 0;
|
|
Packit |
6ef888 |
for (b = 0; b < jblocks; b++) {
|
|
Packit |
6ef888 |
block_map(ip, b, &new, &dblock, NULL, 0);
|
|
Packit |
6ef888 |
if (!dblock)
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
bh = bread(sdp, dblock);
|
|
Packit |
6ef888 |
if (!gfs2_check_meta(bh, GFS2_METATYPE_RG)) {
|
|
Packit |
6ef888 |
/* False rgrp found at block dblock */
|
|
Packit |
6ef888 |
false_count++;
|
|
Packit |
6ef888 |
gfs2_special_set(&false_rgrps, dblock);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_debug("\n%d false positives identified.\n", false_count);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
static int is_false_rg(uint64_t block)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
if (blockfind(&false_rgrps, block))
|
|
Packit |
6ef888 |
return 1;
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* find_shortest_rgdist - hunt and peck for the shortest distance between RGs.
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Sample several of them because an RG that's been blasted may
|
|
Packit |
6ef888 |
* look like twice the distance. If we can find 6 of them, that
|
|
Packit |
6ef888 |
* should be enough to figure out the correct layout.
|
|
Packit |
6ef888 |
* This also figures out first_rg_dist since that's always different.
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* This function was revised to return the number of segments, usually 2.
|
|
Packit |
6ef888 |
* The shortest distance is now returned in the highest entry in rg_dist
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int find_shortest_rgdist(struct gfs2_sbd *sdp, uint64_t *dist_array,
|
|
Packit |
6ef888 |
int *dist_cnt)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
uint64_t blk, block_last_rg, shortest_dist_btwn_rgs;
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh;
|
|
Packit |
6ef888 |
int rgs_sampled = 0;
|
|
Packit |
6ef888 |
struct gfs2_rindex buf, tmpndx;
|
|
Packit |
6ef888 |
uint64_t initial_first_rg_dist;
|
|
Packit |
6ef888 |
int gsegment = 0;
|
|
Packit |
6ef888 |
int is_rgrp;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* Figure out if there are any RG-looking blocks in the journal we
|
|
Packit |
6ef888 |
need to ignore. */
|
|
Packit |
6ef888 |
find_journaled_rgs(sdp);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
initial_first_rg_dist = dist_array[0] = block_last_rg =
|
|
Packit |
6ef888 |
LGFS2_SB_ADDR(sdp) + 1;
|
|
Packit |
6ef888 |
shortest_dist_btwn_rgs = sdp->device.length;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
for (blk = LGFS2_SB_ADDR(sdp) + 1; blk < sdp->device.length; blk++) {
|
|
Packit |
6ef888 |
uint64_t dist;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (blk == LGFS2_SB_ADDR(sdp) + 1)
|
|
Packit |
6ef888 |
is_rgrp = 1;
|
|
Packit |
6ef888 |
else if (is_false_rg(blk))
|
|
Packit |
6ef888 |
is_rgrp = 0;
|
|
Packit |
6ef888 |
else {
|
|
Packit |
6ef888 |
bh = bread(sdp, blk);
|
|
Packit |
6ef888 |
is_rgrp = (gfs2_check_meta(bh, GFS2_METATYPE_RG) == 0);
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (!is_rgrp) {
|
|
Packit |
6ef888 |
if (rgs_sampled >= 6) {
|
|
Packit |
6ef888 |
uint64_t nblk;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_info(_("rgrp not found at block 0x%llx. "
|
|
Packit |
6ef888 |
"Last found rgrp was 0x%llx. "
|
|
Packit |
6ef888 |
"Checking the next one.\n"),
|
|
Packit |
6ef888 |
(unsigned long long)blk,
|
|
Packit |
6ef888 |
(unsigned long long)block_last_rg);
|
|
Packit |
6ef888 |
/* check for just a damaged rgrp */
|
|
Packit |
6ef888 |
nblk = blk + dist_array[gsegment];
|
|
Packit |
6ef888 |
if (is_false_rg(nblk)) {
|
|
Packit |
6ef888 |
is_rgrp = 0;
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
bh = bread(sdp, nblk);
|
|
Packit |
6ef888 |
is_rgrp = (((gfs2_check_meta(bh,
|
|
Packit |
6ef888 |
GFS2_METATYPE_RG) == 0)));
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (is_rgrp) {
|
|
Packit |
6ef888 |
log_info(_("Next rgrp is intact, so "
|
|
Packit |
6ef888 |
"this one is damaged.\n"));
|
|
Packit |
6ef888 |
blk = nblk - 1;
|
|
Packit |
6ef888 |
dist_cnt[gsegment]++;
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_info(_("Looking for new segment.\n"));
|
|
Packit |
6ef888 |
blk -= 16;
|
|
Packit |
6ef888 |
rgs_sampled = 0;
|
|
Packit |
6ef888 |
shortest_dist_btwn_rgs = sdp->device.length;
|
|
Packit |
6ef888 |
/* That last one didn't pan out, so: */
|
|
Packit |
6ef888 |
dist_cnt[gsegment]--;
|
|
Packit |
6ef888 |
gsegment++;
|
|
Packit |
6ef888 |
if (gsegment >= MAX_RGSEGMENTS)
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if ((blk - block_last_rg) > (524288 * 2)) {
|
|
Packit |
6ef888 |
log_info(_("No rgrps were found within 4GB "
|
|
Packit |
6ef888 |
"of the last rgrp. Must be the "
|
|
Packit |
6ef888 |
"end of the file system.\n"));
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
dist_cnt[gsegment]++;
|
|
Packit |
6ef888 |
if (rgs_sampled >= 6) {
|
|
Packit |
6ef888 |
block_last_rg = blk;
|
|
Packit |
6ef888 |
blk += dist_array[gsegment] - 1; /* prev value in
|
|
Packit |
6ef888 |
array minus 1. */
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_info(_("segment %d: rgrp found at block 0x%llx\n"),
|
|
Packit |
6ef888 |
gsegment + 1, (unsigned long long)blk);
|
|
Packit |
6ef888 |
dist = blk - block_last_rg;
|
|
Packit |
6ef888 |
if (blk > LGFS2_SB_ADDR(sdp) + 1) { /* not the very first rgrp */
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_info("dist 0x%llx = 0x%llx - 0x%llx ",
|
|
Packit |
6ef888 |
(unsigned long long)dist,
|
|
Packit |
6ef888 |
(unsigned long long)blk,
|
|
Packit |
6ef888 |
(unsigned long long)block_last_rg);
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* We found an RG. Check to see if we need to set the
|
|
Packit |
6ef888 |
* first_rg_dist based on whether it is still at its
|
|
Packit |
6ef888 |
* initial value (i.e. the fs.) The first rg distance
|
|
Packit |
6ef888 |
* is different from the rest because of the
|
|
Packit |
6ef888 |
* superblock and 64K dead space.
|
|
Packit |
6ef888 |
**/
|
|
Packit |
6ef888 |
if (dist_array[0] == initial_first_rg_dist) {
|
|
Packit |
6ef888 |
dist_array[0] = dist;
|
|
Packit |
6ef888 |
dist_cnt[0] = 1;
|
|
Packit |
6ef888 |
rgs_sampled = 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (dist < shortest_dist_btwn_rgs) {
|
|
Packit |
6ef888 |
shortest_dist_btwn_rgs = dist;
|
|
Packit |
6ef888 |
log_info( _("(shortest so far)"));
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_info("\n");
|
|
Packit |
6ef888 |
if (++rgs_sampled == 6) {
|
|
Packit |
6ef888 |
dist_array[gsegment] = shortest_dist_btwn_rgs;
|
|
Packit |
6ef888 |
log_info(_("Settled on distance 0x%llx for "
|
|
Packit |
6ef888 |
"segment %d\n"),
|
|
Packit |
6ef888 |
(unsigned long long)
|
|
Packit |
6ef888 |
dist_array[gsegment], gsegment + 1);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
gsegment++;
|
|
Packit |
6ef888 |
if (gsegment >= MAX_RGSEGMENTS)
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
block_last_rg = blk;
|
|
Packit |
6ef888 |
if (rgs_sampled < 6)
|
|
Packit |
6ef888 |
blk += 250; /* skip ahead for performance */
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
blk += shortest_dist_btwn_rgs - 1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (gsegment >= MAX_RGSEGMENTS) {
|
|
Packit |
6ef888 |
log_err(_("Maximum number of rgrp grow segments reached.\n"));
|
|
Packit |
6ef888 |
log_err(_("This file system has more than %d resource "
|
|
Packit |
6ef888 |
"group segments.\n"), MAX_RGSEGMENTS);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* -------------------------------------------------------------- */
|
|
Packit |
6ef888 |
/* Sanity-check our first_rg_dist. If RG #2 got nuked, the */
|
|
Packit |
6ef888 |
/* first_rg_dist would measure from #1 to #3, which would be bad. */
|
|
Packit |
6ef888 |
/* We need to take remedial measures to fix it (from the index). */
|
|
Packit |
6ef888 |
/* -------------------------------------------------------------- */
|
|
Packit |
6ef888 |
if (*dist_array >= shortest_dist_btwn_rgs +
|
|
Packit |
6ef888 |
(shortest_dist_btwn_rgs / 4)) {
|
|
Packit |
6ef888 |
/* read in the second RG index entry for this subd. */
|
|
Packit |
6ef888 |
gfs2_readi(sdp->md.riinode, (char *)&buf,
|
|
Packit |
6ef888 |
sizeof(struct gfs2_rindex),
|
|
Packit |
6ef888 |
sizeof(struct gfs2_rindex));
|
|
Packit |
6ef888 |
gfs2_rindex_in(&tmpndx, (char *)&buf;;
|
|
Packit |
6ef888 |
if (tmpndx.ri_addr > LGFS2_SB_ADDR(sdp) + 1) { /* sanity check */
|
|
Packit |
6ef888 |
log_warn( _("rgrp 2 is damaged: getting dist from index: "));
|
|
Packit |
6ef888 |
*dist_array = tmpndx.ri_addr - (LGFS2_SB_ADDR(sdp) + 1);
|
|
Packit |
6ef888 |
log_warn("0x%llx\n", (unsigned long long)*dist_array);
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
log_warn( _("rgrp index 2 is damaged: extrapolating dist: "));
|
|
Packit |
6ef888 |
*dist_array = sdp->device.length - (sdp->rgrps - 1) *
|
|
Packit |
6ef888 |
(sdp->device.length / sdp->rgrps);
|
|
Packit |
6ef888 |
log_warn("0x%llx\n", (unsigned long long)*dist_array);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_debug( _("Adjusted first rgrp distance: 0x%llx\n"),
|
|
Packit |
6ef888 |
(unsigned long long)*dist_array);
|
|
Packit |
6ef888 |
} /* if first RG distance is within tolerance */
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
gfs2_special_free(&false_rgrps);
|
|
Packit |
6ef888 |
return gsegment;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* count_usedspace - count the used bits in a rgrp bitmap buffer
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static uint64_t count_usedspace(struct gfs2_sbd *sdp, int first,
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
int off, x, y, bytes_to_check;
|
|
Packit |
6ef888 |
uint32_t rg_used = 0;
|
|
Packit |
6ef888 |
unsigned int state;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* Count up the free blocks in the bitmap */
|
|
Packit |
6ef888 |
if (first) {
|
|
Packit |
6ef888 |
if (sdp->gfs1)
|
|
Packit |
6ef888 |
off = sizeof(struct gfs_rgrp);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
off = sizeof(struct gfs2_rgrp);
|
|
Packit |
6ef888 |
} else
|
|
Packit |
6ef888 |
off = sizeof(struct gfs2_meta_header);
|
|
Packit |
6ef888 |
bytes_to_check = sdp->bsize - off;
|
|
Packit |
6ef888 |
for (x = 0; x < bytes_to_check; x++) {
|
|
Packit |
6ef888 |
unsigned char *byte;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
byte = (unsigned char *)&bh->b_data[off + x];
|
|
Packit |
6ef888 |
if (*byte == 0x55) {
|
|
Packit |
6ef888 |
rg_used += GFS2_NBBY;
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (*byte == 0x00)
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
for (y = 0; y < GFS2_NBBY; y++) {
|
|
Packit |
6ef888 |
state = (*byte >> (GFS2_BIT_SIZE * y)) & GFS2_BIT_MASK;
|
|
Packit |
6ef888 |
if (state == GFS2_BLKST_FREE ||
|
|
Packit |
6ef888 |
state == GFS2_BLKST_UNLINKED)
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
rg_used++;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return rg_used;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* find_next_rgrp_dist - find the distance to the next rgrp
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* This function is only called if the rgrps are determined to be on uneven
|
|
Packit |
6ef888 |
* boundaries. In a normal gfs2 file system, after mkfs.gfs2, all the
|
|
Packit |
6ef888 |
* rgrps but the first and second one will be the same distance from the
|
|
Packit |
6ef888 |
* previous rgrp. (The first rgrp will predictably be after the superblock
|
|
Packit |
6ef888 |
* and the second one will be adjusted based on the number 64KB skipped
|
|
Packit |
6ef888 |
* at the start of the file system.) The only way we can deviate from that
|
|
Packit |
6ef888 |
* pattern is if the user did gfs_grow on a gfs1 file system, then converted
|
|
Packit |
6ef888 |
* it to gfs2 using gfs2_convert.
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* This function finds the distance to the next rgrp for these cases.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static uint64_t find_next_rgrp_dist(struct gfs2_sbd *sdp, uint64_t blk,
|
|
Packit |
6ef888 |
struct rgrp_tree *prevrgd)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct osi_node *n, *next = NULL;
|
|
Packit |
6ef888 |
uint64_t rgrp_dist = 0, used_blocks, block, next_block, twogigs;
|
|
Packit |
6ef888 |
struct rgrp_tree *rgd = NULL, *next_rgd;
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh;
|
|
Packit |
6ef888 |
struct gfs2_meta_header mh;
|
|
Packit |
6ef888 |
int first, length, b, found;
|
|
Packit |
6ef888 |
uint64_t mega_in_blocks;
|
|
Packit |
6ef888 |
uint32_t free_blocks;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
for (n = osi_first(&sdp->rgtree); n; n = next) {
|
|
Packit |
6ef888 |
next = osi_next(n);
|
|
Packit |
6ef888 |
rgd = (struct rgrp_tree *)n;
|
|
Packit |
6ef888 |
if (rgd->ri.ri_addr == blk)
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (rgd && n && osi_next(n) && rgd->ri.ri_addr == blk) {
|
|
Packit |
6ef888 |
n = osi_next(n);
|
|
Packit |
6ef888 |
next_rgd = (struct rgrp_tree *)n;
|
|
Packit |
6ef888 |
rgrp_dist = next_rgd->ri.ri_addr - rgd->ri.ri_addr;
|
|
Packit |
6ef888 |
return rgrp_dist;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
mega_in_blocks = (1024 * 1024) / sdp->bsize;
|
|
Packit |
6ef888 |
twogigs = (uint64_t)mega_in_blocks * 2048;
|
|
Packit |
6ef888 |
/* Unfortunately, if we fall through to here we can't trust the
|
|
Packit |
6ef888 |
rindex. So we have to analyze the current rgrp to figure out
|
|
Packit |
6ef888 |
the bare minimum block number where it ends. If we don't have
|
|
Packit |
6ef888 |
rindex, all we know about this rgrp is what's on disk: its
|
|
Packit |
6ef888 |
rg_free. If we analyze the rgrp's bitmap and the bitmaps that
|
|
Packit |
6ef888 |
follow, we can figure out how many bits are used. If we add
|
|
Packit |
6ef888 |
rg_free, we get the total number of blocks this rgrp
|
|
Packit |
6ef888 |
represents. After that should be the next rgrp, but it may
|
|
Packit |
6ef888 |
skip a few blocks (hopefully no more than 4). */
|
|
Packit |
6ef888 |
used_blocks = 0;
|
|
Packit |
6ef888 |
length = 0;
|
|
Packit |
6ef888 |
block = prevrgd->ri.ri_addr;
|
|
Packit |
6ef888 |
first = 1;
|
|
Packit |
6ef888 |
found = 0;
|
|
Packit |
6ef888 |
while (1) {
|
|
Packit |
6ef888 |
if (block >= sdp->device.length)
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
if (block >= prevrgd->ri.ri_addr + twogigs)
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
bh = bread(sdp, block);
|
|
Packit |
6ef888 |
gfs2_meta_header_in(&mh, bh->b_data);
|
|
Packit |
6ef888 |
if ((mh.mh_magic != GFS2_MAGIC) ||
|
|
Packit |
6ef888 |
(first && mh.mh_type != GFS2_METATYPE_RG) ||
|
|
Packit |
6ef888 |
(!first && mh.mh_type != GFS2_METATYPE_RB)) {
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (first) {
|
|
Packit |
6ef888 |
struct gfs2_rgrp *rg;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
rg = (struct gfs2_rgrp *)bh->b_data;
|
|
Packit |
6ef888 |
free_blocks = be32_to_cpu(rg->rg_free);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
used_blocks += count_usedspace(sdp, first, bh);
|
|
Packit |
6ef888 |
first = 0;
|
|
Packit |
6ef888 |
block++;
|
|
Packit |
6ef888 |
length++;
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
/* Check if this distance points to an rgrp:
|
|
Packit |
6ef888 |
We have to look for blocks that resemble rgrps and bitmaps.
|
|
Packit |
6ef888 |
If they do, we need to count blocks used and free and see
|
|
Packit |
6ef888 |
if adding that number of free blocks accounts for the
|
|
Packit |
6ef888 |
next rgrp we find. Otherwise, you could have a length of
|
|
Packit |
6ef888 |
6 with additional user blocks that just happen to look like
|
|
Packit |
6ef888 |
bitmap blocks. Count them all as bitmaps and you'll be
|
|
Packit |
6ef888 |
hopelessly lost. */
|
|
Packit |
6ef888 |
rgrp_dist = used_blocks + free_blocks + length;
|
|
Packit |
6ef888 |
next_block = prevrgd->ri.ri_addr + rgrp_dist;
|
|
Packit |
6ef888 |
/* Now we account for block rounding done by mkfs.gfs2 */
|
|
Packit |
6ef888 |
for (b = 0; b <= length + GFS2_NBBY; b++) {
|
|
Packit |
6ef888 |
if (next_block >= sdp->device.length)
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
bh = bread(sdp, next_block + b);
|
|
Packit |
6ef888 |
gfs2_meta_header_in(&mh, bh->b_data);
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
if (mh.mh_magic == GFS2_MAGIC) {
|
|
Packit |
6ef888 |
if (mh.mh_type == GFS2_METATYPE_RG) {
|
|
Packit |
6ef888 |
found = 1;
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* if the first thing we find is a bitmap,
|
|
Packit |
6ef888 |
there must be a damaged rgrp on the
|
|
Packit |
6ef888 |
previous block. */
|
|
Packit |
6ef888 |
if (mh.mh_type == GFS2_METATYPE_RB) {
|
|
Packit |
6ef888 |
found = 1;
|
|
Packit |
6ef888 |
rgrp_dist--;
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
rgrp_dist++;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (found) {
|
|
Packit |
6ef888 |
log_info( _("rgrp found at 0x%llx, length=%d, "
|
|
Packit |
6ef888 |
"used=%llu, free=%d\n"),
|
|
Packit |
6ef888 |
prevrgd->ri.ri_addr, length,
|
|
Packit |
6ef888 |
(unsigned long long)used_blocks,
|
|
Packit |
6ef888 |
free_blocks);
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return rgrp_dist;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* hunt_and_peck - find the distance to the next rgrp
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* This function is only called if the rgrps are determined to be on uneven
|
|
Packit |
6ef888 |
* boundaries, and also corrupt. So we have to go out searching for one.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static uint64_t hunt_and_peck(struct gfs2_sbd *sdp, uint64_t blk,
|
|
Packit |
6ef888 |
struct rgrp_tree *prevrgd, uint64_t last_bump)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
uint64_t rgrp_dist = 0, block, twogigs, last_block, last_meg;
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh;
|
|
Packit |
6ef888 |
struct gfs2_meta_header mh;
|
|
Packit |
6ef888 |
int b, mega_in_blocks;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* Skip ahead the previous amount: we might get lucky.
|
|
Packit |
6ef888 |
If we're close to the end of the device, take the rest. */
|
|
Packit |
6ef888 |
if (gfs2_check_range(sdp, blk + last_bump))
|
|
Packit |
6ef888 |
return sdp->fssize - blk;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
bh = bread(sdp, blk + last_bump);
|
|
Packit |
6ef888 |
gfs2_meta_header_in(&mh, bh->b_data);
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
if (mh.mh_magic == GFS2_MAGIC && mh.mh_type == GFS2_METATYPE_RG) {
|
|
Packit |
6ef888 |
log_info( _("rgrp found at 0x%llx, length=%lld\n"),
|
|
Packit |
6ef888 |
(unsigned long long)blk + last_bump,
|
|
Packit |
6ef888 |
(unsigned long long)last_bump);
|
|
Packit |
6ef888 |
return last_bump;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
rgrp_dist = AWAY_FROM_BITMAPS; /* Get away from any bitmaps
|
|
Packit |
6ef888 |
associated with the previous rgrp */
|
|
Packit |
6ef888 |
block = prevrgd->ri.ri_addr + rgrp_dist;
|
|
Packit |
6ef888 |
/* Now we account for block rounding done by mkfs.gfs2. A rgrp can
|
|
Packit |
6ef888 |
be at most 2GB in size, so that's where we call it. We do somewhat
|
|
Packit |
6ef888 |
obscure math here to avoid integer overflows. */
|
|
Packit |
6ef888 |
mega_in_blocks = (1024 * 1024) / sdp->bsize;
|
|
Packit |
6ef888 |
twogigs = 2048 * mega_in_blocks;
|
|
Packit |
6ef888 |
if (block + twogigs <= sdp->fssize) {
|
|
Packit |
6ef888 |
last_block = twogigs;
|
|
Packit |
6ef888 |
last_meg = 0;
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
/* There won't be a rgrp in the last megabyte. */
|
|
Packit |
6ef888 |
last_block = sdp->fssize - block - mega_in_blocks;
|
|
Packit |
6ef888 |
last_meg = mega_in_blocks;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
for (b = AWAY_FROM_BITMAPS; b < last_block; b++) {
|
|
Packit |
6ef888 |
bh = bread(sdp, block + b);
|
|
Packit |
6ef888 |
gfs2_meta_header_in(&mh, bh->b_data);
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
if (mh.mh_magic == GFS2_MAGIC) {
|
|
Packit |
6ef888 |
if (mh.mh_type == GFS2_METATYPE_RG)
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
/* if the first thing we find is a bitmap, there must
|
|
Packit |
6ef888 |
be a damaged rgrp on the previous block. */
|
|
Packit |
6ef888 |
if (mh.mh_type == GFS2_METATYPE_RB) {
|
|
Packit |
6ef888 |
rgrp_dist--;
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
rgrp_dist++;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return rgrp_dist + last_meg;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* gfs2_rindex_rebuild - rebuild a corrupt Resource Group (RG) index manually
|
|
Packit |
6ef888 |
* where trust_lvl == distrust
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* If this routine is called, it means we have RGs in odd/unexpected places,
|
|
Packit |
6ef888 |
* and there is a corrupt RG or RG index entry. It also means we can't trust
|
|
Packit |
6ef888 |
* the RG index to be sane, and the RGs don't agree with how mkfs would have
|
|
Packit |
6ef888 |
* built them by default. So we have no choice but to go through and count
|
|
Packit |
6ef888 |
* them by hand. We've tried twice to recover the RGs and RG index, and
|
|
Packit |
6ef888 |
* failed, so this is our last chance to remedy the situation.
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* This routine tries to minimize performance impact by:
|
|
Packit |
6ef888 |
* 1. Skipping through the filesystem at known increments when possible.
|
|
Packit |
6ef888 |
* 2. Shuffle through every block when RGs are not found at the predicted
|
|
Packit |
6ef888 |
* locations.
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Note: A GFS2 filesystem differs from a GFS1 file system in that there will
|
|
Packit |
6ef888 |
* only be ONE chunk (i.e. no artificial subdevices on either size of the
|
|
Packit |
6ef888 |
* journals). The journals and even the rindex are kept as part of the file
|
|
Packit |
6ef888 |
* system, so we need to rebuild that information by hand. Also, with GFS1,
|
|
Packit |
6ef888 |
* the different chunks ("subdevices") could have different RG sizes, which
|
|
Packit |
6ef888 |
* made for quite a mess when trying to recover RGs. GFS2 always uses the
|
|
Packit |
6ef888 |
* same RG size determined by the original mkfs, so recovery is easier.
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* If "gfs_grow" is specified the file system was most likely converted
|
|
Packit |
6ef888 |
* from gfs1 to gfs2 after a gfs_grow operation. In that case, the rgrps
|
|
Packit |
6ef888 |
* will not be on predictable boundaries.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int gfs2_rindex_rebuild(struct gfs2_sbd *sdp, int *num_rgs,
|
|
Packit |
6ef888 |
int gfs_grow)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct osi_node *n, *next = NULL;
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh;
|
|
Packit |
6ef888 |
uint64_t rg_dist[MAX_RGSEGMENTS] = {0, };
|
|
Packit |
6ef888 |
int rg_dcnt[MAX_RGSEGMENTS] = {0, };
|
|
Packit |
6ef888 |
uint64_t blk;
|
|
Packit |
6ef888 |
uint64_t fwd_block, block_bump;
|
|
Packit |
6ef888 |
struct rgrp_tree *calc_rgd, *prev_rgd;
|
|
Packit |
6ef888 |
int number_of_rgs, rgi, segment_rgs;
|
|
Packit |
6ef888 |
int rg_was_fnd = FALSE, corrupt_rgs = 0;
|
|
Packit |
6ef888 |
int error = -1, j, i;
|
|
Packit |
6ef888 |
int grow_segments, segment = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* In order to continue, we need to initialize the jindex. We need
|
|
Packit |
6ef888 |
* the journals in order to correctly eliminate false positives during
|
|
Packit |
6ef888 |
* rgrp repair. IOW, we need to properly ignore rgrps that appear in
|
|
Packit |
6ef888 |
* the journals, and we can only do that if we have the journals.
|
|
Packit |
6ef888 |
* To make matters worse, journals may span several (small) rgrps,
|
|
Packit |
6ef888 |
* so we can't go by the rgrps.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
if (init_jindex(sdp, 0) != 0) {
|
|
Packit |
6ef888 |
log_crit(_("Error: Can't read jindex required for rindex "
|
|
Packit |
6ef888 |
"repairs.\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
sdp->rgcalc.osi_node = NULL;
|
|
Packit |
6ef888 |
grow_segments = find_shortest_rgdist(sdp, &rg_dist[0], &rg_dcnt[0]);
|
|
Packit |
6ef888 |
for (i = 0; i < grow_segments; i++)
|
|
Packit |
6ef888 |
log_info(_("Segment %d: rgrp distance: 0x%llx, count: %d\n"),
|
|
Packit |
6ef888 |
i + 1, (unsigned long long)rg_dist[i], rg_dcnt[i]);
|
|
Packit |
6ef888 |
number_of_rgs = segment_rgs = 0;
|
|
Packit |
6ef888 |
/* -------------------------------------------------------------- */
|
|
Packit |
6ef888 |
/* Now go through the RGs and verify their integrity, fixing as */
|
|
Packit |
6ef888 |
/* needed when corruption is encountered. */
|
|
Packit |
6ef888 |
/* -------------------------------------------------------------- */
|
|
Packit |
6ef888 |
prev_rgd = NULL;
|
|
Packit |
6ef888 |
block_bump = rg_dist[0];
|
|
Packit |
6ef888 |
blk = LGFS2_SB_ADDR(sdp) + 1;
|
|
Packit |
6ef888 |
while (blk <= sdp->device.length) {
|
|
Packit |
6ef888 |
log_debug( _("Block 0x%llx\n"), (unsigned long long)blk);
|
|
Packit |
6ef888 |
bh = bread(sdp, blk);
|
|
Packit |
6ef888 |
rg_was_fnd = (!gfs2_check_meta(bh, GFS2_METATYPE_RG));
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
/* Allocate a new RG and index. */
|
|
Packit |
6ef888 |
calc_rgd = rgrp_insert(&sdp->rgcalc, blk);
|
|
Packit |
6ef888 |
if (!calc_rgd) {
|
|
Packit |
6ef888 |
log_crit( _("Can't allocate memory for rgrp repair.\n"));
|
|
Packit |
6ef888 |
goto out;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
calc_rgd->ri.ri_length = 1;
|
|
Packit |
6ef888 |
if (!rg_was_fnd) { /* if not an RG */
|
|
Packit |
6ef888 |
/* ------------------------------------------------- */
|
|
Packit |
6ef888 |
/* This SHOULD be an RG but isn't. */
|
|
Packit |
6ef888 |
/* ------------------------------------------------- */
|
|
Packit |
6ef888 |
corrupt_rgs++;
|
|
Packit |
6ef888 |
if (corrupt_rgs < 5)
|
|
Packit |
6ef888 |
log_debug(_("Missing or damaged rgrp at block "
|
|
Packit |
6ef888 |
"%llu (0x%llx)\n"),
|
|
Packit |
6ef888 |
(unsigned long long)blk,
|
|
Packit |
6ef888 |
(unsigned long long)blk);
|
|
Packit |
6ef888 |
else {
|
|
Packit |
6ef888 |
log_crit( _("Error: too many missing or "
|
|
Packit |
6ef888 |
"damaged rgrps using this method. "
|
|
Packit |
6ef888 |
"Time to try another method.\n"));
|
|
Packit |
6ef888 |
goto out;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* ------------------------------------------------ */
|
|
Packit |
6ef888 |
/* Now go through and count the bitmaps for this RG */
|
|
Packit |
6ef888 |
/* ------------------------------------------------ */
|
|
Packit |
6ef888 |
for (fwd_block = blk + 1; fwd_block < sdp->device.length; fwd_block++) {
|
|
Packit |
6ef888 |
int bitmap_was_fnd;
|
|
Packit |
6ef888 |
bh = bread(sdp, fwd_block);
|
|
Packit |
6ef888 |
bitmap_was_fnd = !gfs2_check_meta(bh, GFS2_METATYPE_RB);
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
if (bitmap_was_fnd) /* if a bitmap */
|
|
Packit |
6ef888 |
calc_rgd->ri.ri_length++;
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
break; /* end of bitmap, so call it quits. */
|
|
Packit |
6ef888 |
} /* for subsequent bitmaps */
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
gfs2_compute_bitstructs(sdp->sd_sb.sb_bsize, calc_rgd);
|
|
Packit |
6ef888 |
calc_rgd->ri.ri_data0 = calc_rgd->ri.ri_addr +
|
|
Packit |
6ef888 |
calc_rgd->ri.ri_length;
|
|
Packit |
6ef888 |
if (prev_rgd) {
|
|
Packit |
6ef888 |
uint32_t rgblocks;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
prev_rgd->ri.ri_length = rgblocks2bitblocks(sdp->bsize, block_bump, &rgblocks);
|
|
Packit |
6ef888 |
prev_rgd->ri.ri_data = rgblocks;
|
|
Packit |
6ef888 |
prev_rgd->ri.ri_data0 = prev_rgd->ri.ri_addr +
|
|
Packit |
6ef888 |
prev_rgd->ri.ri_length;
|
|
Packit |
6ef888 |
prev_rgd->ri.ri_data -= prev_rgd->ri.ri_data %
|
|
Packit |
6ef888 |
GFS2_NBBY;
|
|
Packit |
6ef888 |
prev_rgd->ri.ri_bitbytes = prev_rgd->ri.ri_data /
|
|
Packit |
6ef888 |
GFS2_NBBY;
|
|
Packit |
6ef888 |
log_debug( _("Prev ri_data set to: %lx.\n"),
|
|
Packit |
6ef888 |
(unsigned long)prev_rgd->ri.ri_data);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
number_of_rgs++;
|
|
Packit |
6ef888 |
segment_rgs++;
|
|
Packit |
6ef888 |
if (rg_was_fnd)
|
|
Packit |
6ef888 |
log_info( _(" rgrp %d at block 0x%llx intact\n"),
|
|
Packit |
6ef888 |
number_of_rgs, (unsigned long long)blk);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
log_warn( _("* rgrp %d at block 0x%llx *** DAMAGED ***\n"),
|
|
Packit |
6ef888 |
number_of_rgs, (unsigned long long)blk);
|
|
Packit |
6ef888 |
prev_rgd = calc_rgd;
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* Figure out where our next rgrp should be.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
if ((blk == LGFS2_SB_ADDR(sdp) + 1) || (!gfs_grow)) {
|
|
Packit |
6ef888 |
block_bump = rg_dist[segment];
|
|
Packit |
6ef888 |
if (segment_rgs >= rg_dcnt[segment]) {
|
|
Packit |
6ef888 |
log_debug(_("End of segment %d\n"), ++segment);
|
|
Packit |
6ef888 |
segment_rgs = 0;
|
|
Packit |
6ef888 |
if (segment >= grow_segments) {
|
|
Packit |
6ef888 |
log_debug(_("Last segment.\n"));
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* if we have uniformly-spaced rgrps, there may be
|
|
Packit |
6ef888 |
some wasted space at the end of the device.
|
|
Packit |
6ef888 |
Since we don't want to create a short rgrp and
|
|
Packit |
6ef888 |
break our uniformity, just quit here. */
|
|
Packit |
6ef888 |
if (blk + (2 * block_bump) > sdp->device.length)
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
} else if (rg_was_fnd)
|
|
Packit |
6ef888 |
block_bump = find_next_rgrp_dist(sdp, blk, prev_rgd);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
block_bump = hunt_and_peck(sdp, blk, prev_rgd,
|
|
Packit |
6ef888 |
block_bump);
|
|
Packit |
6ef888 |
if (block_bump != 1) {
|
|
Packit |
6ef888 |
if (rg_was_fnd)
|
|
Packit |
6ef888 |
log_info( _(" [length 0x%llx]\n"),
|
|
Packit |
6ef888 |
(unsigned long long)block_bump);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
log_warn( _(" [length 0x%llx]\n"),
|
|
Packit |
6ef888 |
(unsigned long long)block_bump);
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
log_warn("\n");
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
blk += block_bump;
|
|
Packit |
6ef888 |
} /* for each rg block */
|
|
Packit |
6ef888 |
/* ----------------------------------------------------------------- */
|
|
Packit |
6ef888 |
/* If we got to the end of the fs, we still need to fix the */
|
|
Packit |
6ef888 |
/* allocation information for the very last RG. */
|
|
Packit |
6ef888 |
/* ----------------------------------------------------------------- */
|
|
Packit |
6ef888 |
if (prev_rgd && !prev_rgd->ri.ri_data) {
|
|
Packit |
6ef888 |
uint32_t rgblocks;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
prev_rgd->ri.ri_length = rgblocks2bitblocks(sdp->bsize, block_bump, &rgblocks);
|
|
Packit |
6ef888 |
prev_rgd->ri.ri_data0 = prev_rgd->ri.ri_addr +
|
|
Packit |
6ef888 |
prev_rgd->ri.ri_length;
|
|
Packit |
6ef888 |
prev_rgd->ri.ri_data = rgblocks;
|
|
Packit |
6ef888 |
prev_rgd->ri.ri_data -= prev_rgd->ri.ri_data % GFS2_NBBY;
|
|
Packit |
6ef888 |
prev_rgd->ri.ri_bitbytes = prev_rgd->ri.ri_data / GFS2_NBBY;
|
|
Packit |
6ef888 |
log_debug( _("Prev ri_data set to: %lx.\n"),
|
|
Packit |
6ef888 |
(unsigned long)prev_rgd->ri.ri_data);
|
|
Packit |
6ef888 |
prev_rgd = NULL; /* make sure we don't use it later */
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* ---------------------------------------------- */
|
|
Packit |
6ef888 |
/* Now dump out the information (if verbose mode) */
|
|
Packit |
6ef888 |
/* ---------------------------------------------- */
|
|
Packit |
6ef888 |
log_debug( _("rindex rebuilt as follows:\n"));
|
|
Packit |
6ef888 |
for (n = osi_first(&sdp->rgcalc), rgi = 0; n; n = next, rgi++) {
|
|
Packit |
6ef888 |
next = osi_next(n);
|
|
Packit |
6ef888 |
calc_rgd = (struct rgrp_tree *)n;
|
|
Packit |
6ef888 |
log_debug("%d: 0x%llx / %x / 0x%llx"
|
|
Packit |
6ef888 |
" / 0x%x / 0x%x\n", rgi + 1,
|
|
Packit |
6ef888 |
(unsigned long long)calc_rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
calc_rgd->ri.ri_length,
|
|
Packit |
6ef888 |
calc_rgd->ri.ri_data0, calc_rgd->ri.ri_data,
|
|
Packit |
6ef888 |
calc_rgd->ri.ri_bitbytes);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
*num_rgs = number_of_rgs;
|
|
Packit |
6ef888 |
error = 0;
|
|
Packit |
6ef888 |
out:
|
|
Packit |
6ef888 |
for (j = 0; j < sdp->md.journals; j++)
|
|
Packit |
6ef888 |
inode_put(&sdp->md.journal[j]);
|
|
Packit |
6ef888 |
free(sdp->md.journal);
|
|
Packit |
6ef888 |
return error;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#define DIV_RU(x, y) (((x) + (y) - 1) / (y))
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* how_many_rgrps - figure out how many RG to put in a subdevice
|
|
Packit |
6ef888 |
* @w: the command line
|
|
Packit |
6ef888 |
* @dev: the device
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Returns: the number of RGs
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static uint64_t how_many_rgrps(struct gfs2_sbd *sdp, struct device *dev, int rgsize_specified)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
uint64_t nrgrp;
|
|
Packit |
6ef888 |
uint32_t rgblocks1, rgblocksn, bitblocks1, bitblocksn;
|
|
Packit |
6ef888 |
int bitmap_overflow = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
while (1) {
|
|
Packit |
6ef888 |
nrgrp = DIV_RU(dev->length, (sdp->rgsize << 20) / sdp->bsize);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* check to see if the rg length overflows max # bitblks */
|
|
Packit |
6ef888 |
bitblocksn = rgblocks2bitblocks(sdp->bsize, dev->length / nrgrp, &rgblocksn);
|
|
Packit |
6ef888 |
/* calculate size of the first rgrp */
|
|
Packit |
6ef888 |
bitblocks1 = rgblocks2bitblocks(sdp->bsize, dev->length - (nrgrp - 1) * (dev->length / nrgrp),
|
|
Packit |
6ef888 |
&rgblocks1);
|
|
Packit |
6ef888 |
if (bitblocks1 > 2149 || bitblocksn > 2149) {
|
|
Packit |
6ef888 |
bitmap_overflow = 1;
|
|
Packit |
6ef888 |
if (sdp->rgsize <= GFS2_DEFAULT_RGSIZE) {
|
|
Packit |
6ef888 |
fprintf(stderr, "error: It is not possible "
|
|
Packit |
6ef888 |
"to use the entire device with "
|
|
Packit |
6ef888 |
"block size %u bytes.\n",
|
|
Packit |
6ef888 |
sdp->bsize);
|
|
Packit |
6ef888 |
exit(-1);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
sdp->rgsize -= GFS2_DEFAULT_RGSIZE; /* smaller rgs */
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (bitmap_overflow ||
|
|
Packit |
6ef888 |
rgsize_specified || /* If user specified an rg size or */
|
|
Packit |
6ef888 |
nrgrp <= GFS2_EXCESSIVE_RGS || /* not an excessive # or */
|
|
Packit |
6ef888 |
sdp->rgsize >= 2048) /* we reached the max rg size */
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
sdp->rgsize += GFS2_DEFAULT_RGSIZE; /* bigger rgs */
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_debug(" rg sz = %"PRIu32"\n nrgrp = %"PRIu64"\n", sdp->rgsize,
|
|
Packit |
6ef888 |
nrgrp);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
return nrgrp;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* compute_rgrp_layout - figure out where the RG in a FS are
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static void compute_rgrp_layout(struct gfs2_sbd *sdp, struct osi_root *rgtree, int rgsize_specified)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct device *dev;
|
|
Packit |
6ef888 |
struct rgrp_tree *rl, *rlast = NULL;
|
|
Packit |
6ef888 |
struct osi_node *n, *next = NULL;
|
|
Packit |
6ef888 |
unsigned int rgrp = 0, nrgrp, rglength;
|
|
Packit |
6ef888 |
uint64_t rgaddr;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
sdp->new_rgrps = 0;
|
|
Packit |
6ef888 |
dev = &sdp->device;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* If this is a new file system, compute the length and number */
|
|
Packit |
6ef888 |
/* of rgs based on the size of the device. */
|
|
Packit |
6ef888 |
/* If we have existing RGs (i.e. gfs2_grow) find the last one. */
|
|
Packit |
6ef888 |
if (!rgtree->osi_node) {
|
|
Packit |
6ef888 |
dev->length -= LGFS2_SB_ADDR(sdp) + 1;
|
|
Packit |
6ef888 |
nrgrp = how_many_rgrps(sdp, dev, rgsize_specified);
|
|
Packit |
6ef888 |
rglength = dev->length / nrgrp;
|
|
Packit |
6ef888 |
sdp->new_rgrps = nrgrp;
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
uint64_t old_length, new_chunk;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
printf("Existing resource groups:\n");
|
|
Packit |
6ef888 |
for (rgrp = 0, n = osi_first(rgtree); n; n = next, rgrp++) {
|
|
Packit |
6ef888 |
next = osi_next(n);
|
|
Packit |
6ef888 |
rl = (struct rgrp_tree *)n;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
printf("%d: start: %" PRIu64 " (0x%"
|
|
Packit |
6ef888 |
PRIx64 "), length = %"PRIu64" (0x%"
|
|
Packit |
6ef888 |
PRIx64 ")\n", rgrp + 1, rl->start, rl->start,
|
|
Packit |
6ef888 |
rl->length, rl->length);
|
|
Packit |
6ef888 |
rlast = rl;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
rlast->start = rlast->ri.ri_addr;
|
|
Packit |
6ef888 |
rglength = rgrp_size(rlast);
|
|
Packit |
6ef888 |
rlast->length = rglength;
|
|
Packit |
6ef888 |
old_length = rlast->ri.ri_addr + rglength;
|
|
Packit |
6ef888 |
new_chunk = dev->length - old_length;
|
|
Packit |
6ef888 |
sdp->new_rgrps = new_chunk / rglength;
|
|
Packit |
6ef888 |
nrgrp = rgrp + sdp->new_rgrps;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (rgrp < nrgrp)
|
|
Packit |
6ef888 |
printf("\nNew resource groups:\n");
|
|
Packit |
6ef888 |
for (; rgrp < nrgrp; rgrp++) {
|
|
Packit |
6ef888 |
if (rgrp) {
|
|
Packit |
6ef888 |
rgaddr = rlast->start + rlast->length;
|
|
Packit |
6ef888 |
rl = rgrp_insert(rgtree, rgaddr);
|
|
Packit |
6ef888 |
rl->length = rglength;
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
rgaddr = LGFS2_SB_ADDR(sdp) + 1;
|
|
Packit |
6ef888 |
rl = rgrp_insert(rgtree, rgaddr);
|
|
Packit |
6ef888 |
rl->length = dev->length -
|
|
Packit |
6ef888 |
(nrgrp - 1) * (dev->length / nrgrp);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
rl->start = rgaddr;
|
|
Packit |
6ef888 |
/* printf("%d: start: %" PRIu64 " (0x%"
|
|
Packit |
6ef888 |
PRIx64 "), length = %"PRIu64" (0x%"
|
|
Packit |
6ef888 |
PRIx64 ")\n", rgrp + 1, rl->start, rl->start,
|
|
Packit |
6ef888 |
rl->length, rl->length);*/
|
|
Packit |
6ef888 |
rlast = rl;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
sdp->rgrps = nrgrp;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* gfs2_rindex_calculate - calculate what the rindex should look like
|
|
Packit |
6ef888 |
* in a perfect world (trust_lvl == open_minded)
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Calculate what the rindex should look like,
|
|
Packit |
6ef888 |
* so we can later check if all RG index entries are sane.
|
|
Packit |
6ef888 |
* This is a lot easier for gfs2 because we can just call the same libgfs2
|
|
Packit |
6ef888 |
* functions used by mkfs.
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Returns: 0 on success, -1 on failure
|
|
Packit |
6ef888 |
* Sets: sdp->rglist to a linked list of fsck_rgrp structs representing
|
|
Packit |
6ef888 |
* what we think the rindex should really look like.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int gfs2_rindex_calculate(struct gfs2_sbd *sdp, int *num_rgs)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
uint64_t num_rgrps = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* ----------------------------------------------------------------- */
|
|
Packit |
6ef888 |
/* Calculate how many RGs there are supposed to be based on the */
|
|
Packit |
6ef888 |
/* rindex filesize. Remember that our trust level is open-minded */
|
|
Packit |
6ef888 |
/* here. If the filesize of the rindex file is not a multiple of */
|
|
Packit |
6ef888 |
/* our rindex structures, then something's wrong and we can't trust */
|
|
Packit |
6ef888 |
/* the index. */
|
|
Packit |
6ef888 |
/* ----------------------------------------------------------------- */
|
|
Packit |
6ef888 |
*num_rgs = sdp->md.riinode->i_di.di_size / sizeof(struct gfs2_rindex);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
sdp->rgcalc.osi_node = NULL;
|
|
Packit |
6ef888 |
fix_device_geometry(sdp);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* Try all possible rgrp sizes: 2048, 1024, 512, 256, 128, 64, 32 */
|
|
Packit |
6ef888 |
for (sdp->rgsize = GFS2_DEFAULT_RGSIZE; sdp->rgsize >= 32;
|
|
Packit |
6ef888 |
sdp->rgsize /= 2) {
|
|
Packit |
6ef888 |
num_rgrps = how_many_rgrps(sdp, &sdp->device, TRUE);
|
|
Packit |
6ef888 |
if (num_rgrps == *num_rgs) {
|
|
Packit |
6ef888 |
log_info(_("rgsize must be: %lld (0x%llx)\n"),
|
|
Packit |
6ef888 |
(unsigned long long)sdp->rgsize,
|
|
Packit |
6ef888 |
(unsigned long long)sdp->rgsize);
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* Compute the default resource group layout as mkfs would have done */
|
|
Packit |
6ef888 |
compute_rgrp_layout(sdp, &sdp->rgcalc, TRUE);
|
|
Packit |
6ef888 |
if (build_rgrps(sdp, FALSE)) { /* FALSE = calc but don't write to disk. */
|
|
Packit |
6ef888 |
fprintf(stderr, _("Failed to build resource groups\n"));
|
|
Packit |
6ef888 |
exit(-1);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_debug( _("fs_total_size = 0x%llx blocks.\n"),
|
|
Packit |
6ef888 |
(unsigned long long)sdp->device.length);
|
|
Packit |
6ef888 |
log_warn( _("L3: number of rgs in the index = %d.\n"), *num_rgs);
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* rewrite_rg_block - rewrite ("fix") a buffer with rg or bitmap data
|
|
Packit |
6ef888 |
* returns: 0 if the rg was repaired, otherwise 1
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int rewrite_rg_block(struct gfs2_sbd *sdp, struct rgrp_tree *rg,
|
|
Packit |
6ef888 |
uint64_t errblock)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
int x = errblock - rg->ri.ri_addr;
|
|
Packit |
6ef888 |
const char *typedesc = x ? "GFS2_METATYPE_RB" : "GFS2_METATYPE_RG";
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_err( _("Block #%lld (0x%llx) (%d of %d) is not %s.\n"),
|
|
Packit |
6ef888 |
(unsigned long long)rg->ri.ri_addr + x,
|
|
Packit |
6ef888 |
(unsigned long long)rg->ri.ri_addr + x,
|
|
Packit |
6ef888 |
(int)x+1, (int)rg->ri.ri_length, typedesc);
|
|
Packit |
6ef888 |
if (query( _("Fix the Resource Group? (y/n)"))) {
|
|
Packit |
6ef888 |
log_err( _("Attempting to repair the rgrp.\n"));
|
|
Packit |
6ef888 |
rg->bits[x].bi_bh = bread(sdp, rg->ri.ri_addr + x);
|
|
Packit |
6ef888 |
if (x) {
|
|
Packit |
6ef888 |
struct gfs2_meta_header mh;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
mh.mh_magic = GFS2_MAGIC;
|
|
Packit |
6ef888 |
mh.mh_type = GFS2_METATYPE_RB;
|
|
Packit |
6ef888 |
mh.mh_format = GFS2_FORMAT_RB;
|
|
Packit |
6ef888 |
gfs2_meta_header_out(&mh, rg->bits[x].bi_bh->b_data);
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
if (sdp->gfs1)
|
|
Packit |
6ef888 |
memset(&rg->rg, 0, sizeof(struct gfs_rgrp));
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
memset(&rg->rg, 0, sizeof(struct gfs2_rgrp));
|
|
Packit |
6ef888 |
rg->rg.rg_header.mh_magic = GFS2_MAGIC;
|
|
Packit |
6ef888 |
rg->rg.rg_header.mh_type = GFS2_METATYPE_RG;
|
|
Packit |
6ef888 |
rg->rg.rg_header.mh_format = GFS2_FORMAT_RG;
|
|
Packit |
6ef888 |
rg->rg.rg_free = rg->ri.ri_data;
|
|
Packit |
6ef888 |
if (sdp->gfs1)
|
|
Packit |
6ef888 |
gfs_rgrp_out((struct gfs_rgrp *)&rg->rg, rg->bits[x].bi_bh);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
gfs2_rgrp_out(&rg->rg, rg->bits[x].bi_bh->b_data);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
bmodified(rg->bits[x].bi_bh);
|
|
Packit |
6ef888 |
brelse(rg->bits[x].bi_bh);
|
|
Packit |
6ef888 |
rg->bits[x].bi_bh = NULL;
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return 1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* expect_rindex_sanity - the rindex file seems trustworthy, so use those
|
|
Packit |
6ef888 |
* values as our expected values and assume the
|
|
Packit |
6ef888 |
* damage is only to the rgrps themselves.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int expect_rindex_sanity(struct gfs2_sbd *sdp, int *num_rgs)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct osi_node *n, *next = NULL;
|
|
Packit |
6ef888 |
struct rgrp_tree *rgd, *exp;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
*num_rgs = sdp->md.riinode->i_di.di_size / sizeof(struct gfs2_rindex) ;
|
|
Packit |
6ef888 |
for (n = osi_first(&sdp->rgtree); n; n = next) {
|
|
Packit |
6ef888 |
next = osi_next(n);
|
|
Packit |
6ef888 |
rgd = (struct rgrp_tree *)n;
|
|
Packit |
6ef888 |
exp = rgrp_insert(&sdp->rgcalc, rgd->ri.ri_addr);
|
|
Packit |
6ef888 |
if (exp == NULL) {
|
|
Packit |
6ef888 |
fprintf(stderr, "Out of memory in %s\n", __FUNCTION__);
|
|
Packit |
6ef888 |
exit(-1);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
exp->start = rgd->start;
|
|
Packit |
6ef888 |
exp->length = rgd->length;
|
|
Packit |
6ef888 |
memcpy(&exp->ri, &rgd->ri, sizeof(exp->ri));
|
|
Packit |
6ef888 |
memcpy(&exp->rg, &rgd->rg, sizeof(exp->rg));
|
|
Packit |
6ef888 |
exp->bits = NULL;
|
|
Packit |
6ef888 |
gfs2_compute_bitstructs(sdp->sd_sb.sb_bsize, exp);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
sdp->rgrps = *num_rgs;
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* rg_repair - try to repair a damaged rg index (rindex)
|
|
Packit |
6ef888 |
* trust_lvl - This is how much we trust the rindex file.
|
|
Packit |
6ef888 |
* blind_faith means we take the rindex at face value.
|
|
Packit |
6ef888 |
* open_minded means it might be okay, but we should verify it.
|
|
Packit |
6ef888 |
* distrust means it's not to be trusted, so we should go to
|
|
Packit |
6ef888 |
* greater lengths to build it from scratch.
|
|
Packit |
6ef888 |
* indignation means we have corruption, but the file system
|
|
Packit |
6ef888 |
* was converted from GFS via gfs2_convert, and its rgrps are
|
|
Packit |
6ef888 |
* not on nice boundaries thanks to previous gfs_grow ops. Lovely.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
int rg_repair(struct gfs2_sbd *sdp, int trust_lvl, int *rg_count, int *sane)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct osi_node *n, *next = NULL, *e, *enext;
|
|
Packit |
6ef888 |
int error, discrepancies, percent;
|
|
Packit |
6ef888 |
int calc_rg_count = 0, rg;
|
|
Packit |
6ef888 |
struct gfs2_rindex buf;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (trust_lvl == blind_faith)
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
if (trust_lvl == ye_of_little_faith) { /* if rindex seems sane */
|
|
Packit |
6ef888 |
/* Don't free previous incarnations in memory, if any.
|
|
Packit |
6ef888 |
* We need them to copy in the next function:
|
|
Packit |
6ef888 |
* gfs2_rgrp_free(&sdp->rglist); */
|
|
Packit |
6ef888 |
if (!(*sane)) {
|
|
Packit |
6ef888 |
log_err(_("The rindex file does not meet our "
|
|
Packit |
6ef888 |
"expectations.\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
error = expect_rindex_sanity(sdp, &calc_rg_count);
|
|
Packit |
6ef888 |
if (error) {
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgcalc);
|
|
Packit |
6ef888 |
return error;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
} else if (trust_lvl == open_minded) { /* If we can't trust RG index */
|
|
Packit |
6ef888 |
/* Free previous incarnations in memory, if any. */
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgtree);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* Calculate our own RG index for comparison */
|
|
Packit |
6ef888 |
error = gfs2_rindex_calculate(sdp, &calc_rg_count);
|
|
Packit |
6ef888 |
if (error) { /* If calculated RGs don't match the fs */
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgcalc);
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
} else if (trust_lvl == distrust) { /* If we can't trust RG index */
|
|
Packit |
6ef888 |
/* Free previous incarnations in memory, if any. */
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgtree);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
error = gfs2_rindex_rebuild(sdp, &calc_rg_count, 0);
|
|
Packit |
6ef888 |
if (error) {
|
|
Packit |
6ef888 |
log_crit( _("Error rebuilding rgrp list.\n"));
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgcalc);
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
} else if (trust_lvl == indignation) { /* If we can't trust anything */
|
|
Packit |
6ef888 |
/* Free previous incarnations in memory, if any. */
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgtree);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
error = gfs2_rindex_rebuild(sdp, &calc_rg_count, 1);
|
|
Packit |
6ef888 |
if (error) {
|
|
Packit |
6ef888 |
log_crit( _("Error rebuilding rgrp list.\n"));
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgcalc);
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* Read in the rindex */
|
|
Packit |
6ef888 |
sdp->rgtree.osi_node = NULL; /* Just to be safe */
|
|
Packit |
6ef888 |
rindex_read(sdp, 0, &sdp->rgrps, sane);
|
|
Packit |
6ef888 |
if (sdp->md.riinode->i_di.di_size % sizeof(struct gfs2_rindex)) {
|
|
Packit |
6ef888 |
log_warn( _("WARNING: rindex file has an invalid size.\n"));
|
|
Packit |
6ef888 |
if (!query( _("Truncate the rindex size? (y/n)"))) {
|
|
Packit |
6ef888 |
log_err(_("The rindex was not repaired.\n"));
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgcalc);
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgtree);
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
sdp->md.riinode->i_di.di_size /= sizeof(struct gfs2_rindex);
|
|
Packit |
6ef888 |
sdp->md.riinode->i_di.di_size *= sizeof(struct gfs2_rindex);
|
|
Packit |
6ef888 |
bmodified(sdp->md.riinode->i_bh);
|
|
Packit |
6ef888 |
log_err(_("Changing rindex size to %lld.\n"),
|
|
Packit |
6ef888 |
(unsigned long long)sdp->md.riinode->i_di.di_size);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_warn( _("L%d: number of rgs expected = %lld.\n"), trust_lvl + 1,
|
|
Packit |
6ef888 |
(unsigned long long)sdp->rgrps);
|
|
Packit |
6ef888 |
if (calc_rg_count != sdp->rgrps) {
|
|
Packit |
6ef888 |
int most_that_fit;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_warn( _("L%d: They don't match; either (1) the fs was "
|
|
Packit |
6ef888 |
"extended, (2) an odd\n"), trust_lvl + 1);
|
|
Packit |
6ef888 |
log_warn( _("L%d: rgrp size was used, or (3) we have a corrupt "
|
|
Packit |
6ef888 |
"rg index.\n"), trust_lvl + 1);
|
|
Packit |
6ef888 |
/* If the trust level is open_minded, we would have calculated
|
|
Packit |
6ef888 |
the rindex based on the device size. If it's not the same
|
|
Packit |
6ef888 |
number, don't trust it. Complain about the discrepancy,
|
|
Packit |
6ef888 |
then try again with a little more distrust. */
|
|
Packit |
6ef888 |
if ((trust_lvl < distrust) ||
|
|
Packit |
6ef888 |
!query( _("Attempt to use what rgrps we can? (y/n)"))) {
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgcalc);
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgtree);
|
|
Packit |
6ef888 |
log_err(_("The rindex was not repaired.\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* We cannot grow rindex at this point. Since pass1 has not
|
|
Packit |
6ef888 |
yet run, we can't allocate blocks. Therefore we must use
|
|
Packit |
6ef888 |
whatever will fix in the space given. */
|
|
Packit |
6ef888 |
most_that_fit = sdp->md.riinode->i_di.di_size /
|
|
Packit |
6ef888 |
sizeof(struct gfs2_rindex);
|
|
Packit |
6ef888 |
log_debug(_("The most we can fit is %d rgrps\n"),
|
|
Packit |
6ef888 |
most_that_fit);
|
|
Packit |
6ef888 |
if (most_that_fit < calc_rg_count)
|
|
Packit |
6ef888 |
calc_rg_count = most_that_fit;
|
|
Packit |
6ef888 |
log_err(_("Attempting to fix rindex with %d rgrps.\n"),
|
|
Packit |
6ef888 |
calc_rg_count);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* ------------------------------------------------------------- */
|
|
Packit |
6ef888 |
/* Now compare the rindex to what we think it should be. */
|
|
Packit |
6ef888 |
/* See how far off our expected values are. If too much, abort. */
|
|
Packit |
6ef888 |
/* The theory is: if we calculated the index to have 32 RGs and */
|
|
Packit |
6ef888 |
/* we have a large number that are completely wrong, we should */
|
|
Packit |
6ef888 |
/* abandon this method of recovery and try a better one. */
|
|
Packit |
6ef888 |
/* ------------------------------------------------------------- */
|
|
Packit |
6ef888 |
discrepancies = 0;
|
|
Packit |
6ef888 |
for (rg = 0, n = osi_first(&sdp->rgtree), e = osi_first(&sdp->rgcalc);
|
|
Packit |
6ef888 |
n && e && !fsck_abort && rg < calc_rg_count; rg++) {
|
|
Packit |
6ef888 |
struct rgrp_tree *expected, *actual;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
next = osi_next(n);
|
|
Packit |
6ef888 |
enext = osi_next(e);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
expected = (struct rgrp_tree *)e;
|
|
Packit |
6ef888 |
actual = (struct rgrp_tree *)n;
|
|
Packit |
6ef888 |
if (actual->ri.ri_addr < expected->ri.ri_addr) {
|
|
Packit |
6ef888 |
n = next;
|
|
Packit |
6ef888 |
discrepancies++;
|
|
Packit |
6ef888 |
log_info(_("%d addr: 0x%llx < 0x%llx * mismatch\n"),
|
|
Packit |
6ef888 |
rg + 1, actual->ri.ri_addr,
|
|
Packit |
6ef888 |
expected->ri.ri_addr);
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
} else if (expected->ri.ri_addr < actual->ri.ri_addr) {
|
|
Packit |
6ef888 |
e = enext;
|
|
Packit |
6ef888 |
discrepancies++;
|
|
Packit |
6ef888 |
log_info(_("%d addr: 0x%llx > 0x%llx * mismatch\n"),
|
|
Packit |
6ef888 |
rg + 1, actual->ri.ri_addr,
|
|
Packit |
6ef888 |
expected->ri.ri_addr);
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (!ri_equal(actual->ri, expected->ri, ri_length) ||
|
|
Packit |
6ef888 |
!ri_equal(actual->ri, expected->ri, ri_data0) ||
|
|
Packit |
6ef888 |
!ri_equal(actual->ri, expected->ri, ri_data) ||
|
|
Packit |
6ef888 |
!ri_equal(actual->ri, expected->ri, ri_bitbytes)) {
|
|
Packit |
6ef888 |
discrepancies++;
|
|
Packit |
6ef888 |
log_info(_("%d addr: 0x%llx 0x%llx * has mismatch\n"),
|
|
Packit |
6ef888 |
rg + 1, actual->ri.ri_addr,
|
|
Packit |
6ef888 |
expected->ri.ri_addr);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
n = next;
|
|
Packit |
6ef888 |
e = enext;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (rg) {
|
|
Packit |
6ef888 |
/* Check to see if more than 2% of the rgrps are wrong. */
|
|
Packit |
6ef888 |
percent = (discrepancies * 100) / rg;
|
|
Packit |
6ef888 |
if (percent > BAD_RG_PERCENT_TOLERANCE) {
|
|
Packit |
6ef888 |
log_warn( _("Level %d didn't work. Too many "
|
|
Packit |
6ef888 |
"discrepancies.\n"), trust_lvl + 1);
|
|
Packit |
6ef888 |
log_warn( _("%d out of %d rgrps (%d percent) did not "
|
|
Packit |
6ef888 |
"match what was expected.\n"),
|
|
Packit |
6ef888 |
discrepancies, rg, percent);
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgcalc);
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgtree);
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_debug("Calculated %d rgrps: Total: %d Match: %d Mismatch: %d\n",
|
|
Packit |
6ef888 |
calc_rg_count, rg, rg - discrepancies, discrepancies);
|
|
Packit |
6ef888 |
/* ------------------------------------------------------------- */
|
|
Packit |
6ef888 |
/* Now compare the rindex to what we think it should be. */
|
|
Packit |
6ef888 |
/* Our rindex should be pretty predictable unless we've grown */
|
|
Packit |
6ef888 |
/* so look for index problems first before looking at the rgs. */
|
|
Packit |
6ef888 |
/* ------------------------------------------------------------- */
|
|
Packit |
6ef888 |
for (rg = 0, n = osi_first(&sdp->rgtree), e = osi_first(&sdp->rgcalc);
|
|
Packit |
6ef888 |
e && !fsck_abort && rg < calc_rg_count; rg++) {
|
|
Packit |
6ef888 |
struct rgrp_tree *expected, *actual;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (n)
|
|
Packit |
6ef888 |
next = osi_next(n);
|
|
Packit |
6ef888 |
enext = osi_next(e);
|
|
Packit |
6ef888 |
expected = (struct rgrp_tree *)e;
|
|
Packit |
6ef888 |
actual = (struct rgrp_tree *)n;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* If the next "actual" rgrp in memory is too far away,
|
|
Packit |
6ef888 |
fill in a new one with the expected value. -or-
|
|
Packit |
6ef888 |
If we ran out of actual rindex entries due to rindex
|
|
Packit |
6ef888 |
damage, fill in a new one with the expected values. */
|
|
Packit |
6ef888 |
if (!n || /* end of actual rindex */
|
|
Packit |
6ef888 |
expected->ri.ri_addr < actual->ri.ri_addr) {
|
|
Packit |
6ef888 |
log_err( _("Entry missing from rindex: 0x%llx\n"),
|
|
Packit |
6ef888 |
(unsigned long long)expected->ri.ri_addr);
|
|
Packit |
6ef888 |
actual = rgrp_insert(&sdp->rgtree,
|
|
Packit |
6ef888 |
expected->ri.ri_addr);
|
|
Packit |
6ef888 |
if (!actual) {
|
|
Packit |
6ef888 |
log_err(_("Out of memory!\n"));
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
rindex_modified = 1;
|
|
Packit |
6ef888 |
next = n; /* Ensure that the old actual gets checked
|
|
Packit |
6ef888 |
against a new expected, since we added */
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
ri_compare(rg, actual->ri, expected->ri, ri_addr,
|
|
Packit |
6ef888 |
"llx", unsigned long long);
|
|
Packit |
6ef888 |
ri_compare(rg, actual->ri, expected->ri, ri_length,
|
|
Packit |
6ef888 |
"lx", unsigned long);
|
|
Packit |
6ef888 |
ri_compare(rg, actual->ri, expected->ri, ri_data0,
|
|
Packit |
6ef888 |
"llx", unsigned long long);
|
|
Packit |
6ef888 |
ri_compare(rg, actual->ri, expected->ri, ri_data,
|
|
Packit |
6ef888 |
"lx", unsigned long);
|
|
Packit |
6ef888 |
ri_compare(rg, actual->ri, expected->ri, ri_bitbytes,
|
|
Packit |
6ef888 |
"lx", unsigned long);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* If we modified the index, write it back to disk. */
|
|
Packit |
6ef888 |
if (rindex_modified) {
|
|
Packit |
6ef888 |
if (query( _("Fix the index? (y/n)"))) {
|
|
Packit |
6ef888 |
gfs2_rindex_out(&expected->ri, (char *)&buf;;
|
|
Packit |
6ef888 |
gfs2_writei(sdp->md.riinode, (char *)&buf,
|
|
Packit |
6ef888 |
rg * sizeof(struct gfs2_rindex),
|
|
Packit |
6ef888 |
sizeof(struct gfs2_rindex));
|
|
Packit |
6ef888 |
actual->ri.ri_addr = expected->ri.ri_addr;
|
|
Packit |
6ef888 |
actual->ri.ri_length = expected->ri.ri_length;
|
|
Packit |
6ef888 |
actual->ri.ri_data0 = expected->ri.ri_data0;
|
|
Packit |
6ef888 |
actual->ri.ri_data = expected->ri.ri_data;
|
|
Packit |
6ef888 |
actual->ri.ri_bitbytes =
|
|
Packit |
6ef888 |
expected->ri.ri_bitbytes;
|
|
Packit |
6ef888 |
/* If our rindex was hosed, ri_length is bad */
|
|
Packit |
6ef888 |
/* Therefore, gfs2_compute_bitstructs might */
|
|
Packit |
6ef888 |
/* have malloced the wrong length for bitmap */
|
|
Packit |
6ef888 |
/* buffers. So we have to redo it. */
|
|
Packit |
6ef888 |
if (actual->bits) {
|
|
Packit |
6ef888 |
free(actual->bits);
|
|
Packit |
6ef888 |
actual->bits = NULL;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
log_err( _("rindex not fixed.\n"));
|
|
Packit |
6ef888 |
gfs2_compute_bitstructs(sdp->sd_sb.sb_bsize, actual);
|
|
Packit |
6ef888 |
rindex_modified = FALSE;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
e = enext;
|
|
Packit |
6ef888 |
if (n)
|
|
Packit |
6ef888 |
n = next;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* ------------------------------------------------------------- */
|
|
Packit |
6ef888 |
/* Read the real RGs and check their integrity. */
|
|
Packit |
6ef888 |
/* Now we can somewhat trust the rindex and the RG addresses, */
|
|
Packit |
6ef888 |
/* so let's read them in, check them and optionally fix them. */
|
|
Packit |
6ef888 |
/* ------------------------------------------------------------- */
|
|
Packit |
6ef888 |
for (rg = 0, n = osi_first(&sdp->rgtree); n && !fsck_abort &&
|
|
Packit |
6ef888 |
rg < calc_rg_count; n = next, rg++) {
|
|
Packit |
6ef888 |
struct rgrp_tree *rgd;
|
|
Packit |
6ef888 |
uint64_t prev_err = 0, errblock;
|
|
Packit |
6ef888 |
int i;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
next = osi_next(n);
|
|
Packit |
6ef888 |
/* Now we try repeatedly to read in the rg. For every block */
|
|
Packit |
6ef888 |
/* we encounter that has errors, repair it and try again. */
|
|
Packit |
6ef888 |
i = 0;
|
|
Packit |
6ef888 |
do {
|
|
Packit |
6ef888 |
rgd = (struct rgrp_tree *)n;
|
|
Packit |
6ef888 |
errblock = gfs2_rgrp_read(sdp, rgd);
|
|
Packit |
6ef888 |
if (errblock) {
|
|
Packit |
6ef888 |
if (errblock == prev_err)
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
prev_err = errblock;
|
|
Packit |
6ef888 |
rewrite_rg_block(sdp, rgd, errblock);
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
gfs2_rgrp_relse(rgd);
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
i++;
|
|
Packit |
6ef888 |
} while (i < rgd->ri.ri_length);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
*rg_count = rg;
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgcalc);
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgtree);
|
|
Packit |
6ef888 |
/* We shouldn't need to worry about getting the user's permission to
|
|
Packit |
6ef888 |
make changes here. If b_modified is true, they already gave their
|
|
Packit |
6ef888 |
permission. */
|
|
Packit |
6ef888 |
if (sdp->md.riinode->i_bh->b_modified) {
|
|
Packit |
6ef888 |
log_debug("Syncing rindex inode changes to disk.\n");
|
|
Packit |
6ef888 |
gfs2_dinode_out(&sdp->md.riinode->i_di, sdp->md.riinode->i_bh->b_data);
|
|
Packit |
6ef888 |
bwrite(sdp->md.riinode->i_bh);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|