|
Packit |
6ef888 |
#include "clusterautoconfig.h"
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#include <stdio.h>
|
|
Packit |
6ef888 |
#include <stdint.h>
|
|
Packit |
6ef888 |
#include <inttypes.h>
|
|
Packit |
6ef888 |
#include <stdlib.h>
|
|
Packit |
6ef888 |
#include <sys/types.h>
|
|
Packit |
6ef888 |
#include <sys/stat.h>
|
|
Packit |
6ef888 |
#include <fcntl.h>
|
|
Packit |
6ef888 |
#include <string.h>
|
|
Packit |
6ef888 |
#include <unistd.h>
|
|
Packit |
6ef888 |
#include <libintl.h>
|
|
Packit |
6ef888 |
#include <errno.h>
|
|
Packit |
6ef888 |
#include <time.h>
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#define _(String) gettext(String)
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#include <logging.h>
|
|
Packit |
6ef888 |
#include "libgfs2.h"
|
|
Packit |
6ef888 |
#include "fsck.h"
|
|
Packit |
6ef888 |
#include "util.h"
|
|
Packit |
6ef888 |
#include "fs_recovery.h"
|
|
Packit |
6ef888 |
#include "metawalk.h"
|
|
Packit |
6ef888 |
#include "inode_hash.h"
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#define CLEAR_POINTER(x) \
|
|
Packit |
6ef888 |
if (x) { \
|
|
Packit |
6ef888 |
free(x); \
|
|
Packit |
6ef888 |
x = NULL; \
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
#define HIGHEST_BLOCK 0xffffffffffffffff
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
static int was_mounted_ro = 0;
|
|
Packit |
6ef888 |
static uint64_t possible_root = HIGHEST_BLOCK;
|
|
Packit |
6ef888 |
static struct master_dir fix_md;
|
|
Packit |
6ef888 |
static unsigned long long blks_2free = 0;
|
|
Packit |
6ef888 |
extern int sb_fixed;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* block_mounters
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Change the lock protocol so nobody can mount the fs
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int block_mounters(struct gfs2_sbd *sdp, int block_em)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
if (block_em) {
|
|
Packit |
6ef888 |
/* verify it starts with lock_ */
|
|
Packit |
6ef888 |
if (!strncmp(sdp->sd_sb.sb_lockproto, "lock_", 5)) {
|
|
Packit |
6ef888 |
/* Change lock_ to fsck_ */
|
|
Packit |
6ef888 |
memcpy(sdp->sd_sb.sb_lockproto, "fsck_", 5);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* FIXME: Need to do other verification in the else
|
|
Packit |
6ef888 |
* case */
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
/* verify it starts with fsck_ */
|
|
Packit |
6ef888 |
/* verify it starts with lock_ */
|
|
Packit |
6ef888 |
if (!strncmp(sdp->sd_sb.sb_lockproto, "fsck_", 5)) {
|
|
Packit |
6ef888 |
/* Change fsck_ to lock_ */
|
|
Packit |
6ef888 |
memcpy(sdp->sd_sb.sb_lockproto, "lock_", 5);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (lgfs2_sb_write(&sdp->sd_sb, sdp->device_fd, sdp->bsize)) {
|
|
Packit |
6ef888 |
stack;
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
static void gfs2_dup_free(void)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct osi_node *n;
|
|
Packit |
6ef888 |
struct duptree *dt;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
while ((n = osi_first(&dup_blocks))) {
|
|
Packit |
6ef888 |
dt = (struct duptree *)n;
|
|
Packit |
6ef888 |
dup_delete(dt);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
static void gfs2_dirtree_free(void)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct osi_node *n;
|
|
Packit |
6ef888 |
struct dir_info *dt;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
while ((n = osi_first(&dirtree))) {
|
|
Packit |
6ef888 |
dt = (struct dir_info *)n;
|
|
Packit |
6ef888 |
dirtree_delete(dt);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
static void gfs2_inodetree_free(void)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct osi_node *n;
|
|
Packit |
6ef888 |
struct inode_info *dt;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
while ((n = osi_first(&inodetree))) {
|
|
Packit |
6ef888 |
dt = (struct inode_info *)n;
|
|
Packit |
6ef888 |
inodetree_delete(dt);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* empty_super_block - free all structures in the super block
|
|
Packit |
6ef888 |
* sdp: the in-core super block
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* This function frees all allocated structures within the
|
|
Packit |
6ef888 |
* super block. It does not free the super block itself.
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Returns: Nothing
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static void empty_super_block(struct gfs2_sbd *sdp)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
log_info( _("Freeing buffers.\n"));
|
|
Packit |
6ef888 |
gfs2_rgrp_free(&sdp->rgtree);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
gfs2_inodetree_free();
|
|
Packit |
6ef888 |
gfs2_dirtree_free();
|
|
Packit |
6ef888 |
gfs2_dup_free();
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* set_block_ranges
|
|
Packit |
6ef888 |
* @sdp: superblock
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Uses info in rgrps and jindex to determine boundaries of the
|
|
Packit |
6ef888 |
* file system.
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Returns: 0 on success, -1 on failure
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int set_block_ranges(struct gfs2_sbd *sdp)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct osi_node *n, *next = NULL;
|
|
Packit |
6ef888 |
struct rgrp_tree *rgd;
|
|
Packit |
6ef888 |
struct gfs2_rindex *ri;
|
|
Packit |
6ef888 |
char buf[sdp->sd_sb.sb_bsize];
|
|
Packit |
6ef888 |
uint64_t rmax = 0;
|
|
Packit |
6ef888 |
uint64_t rmin = 0;
|
|
Packit |
6ef888 |
int error;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_info( _("Setting block ranges..."));
|
|
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 |
ri = &rgd->ri;
|
|
Packit |
6ef888 |
if (ri->ri_data0 + ri->ri_data &&
|
|
Packit |
6ef888 |
ri->ri_data0 + ri->ri_data - 1 > rmax)
|
|
Packit |
6ef888 |
rmax = ri->ri_data0 + ri->ri_data - 1;
|
|
Packit |
6ef888 |
if (!rmin || ri->ri_data0 < rmin)
|
|
Packit |
6ef888 |
rmin = ri->ri_data0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
last_fs_block = rmax;
|
|
Packit |
6ef888 |
if (last_fs_block > 0xffffffff && sizeof(unsigned long) <= 4) {
|
|
Packit |
6ef888 |
log_crit( _("This file system is too big for this computer to handle.\n"));
|
|
Packit |
6ef888 |
log_crit( _("Last fs block = 0x%llx, but sizeof(unsigned long) is %zu bytes.\n"),
|
|
Packit |
6ef888 |
(unsigned long long)last_fs_block,
|
|
Packit |
6ef888 |
sizeof(unsigned long));
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
last_data_block = rmax;
|
|
Packit |
6ef888 |
first_data_block = rmin;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (fsck_lseek(sdp->device_fd, (last_fs_block * sdp->sd_sb.sb_bsize))){
|
|
Packit |
6ef888 |
log_crit( _("Can't seek to last block in file system: %llu"
|
|
Packit |
6ef888 |
" (0x%llx)\n"), (unsigned long long)last_fs_block,
|
|
Packit |
6ef888 |
(unsigned long long)last_fs_block);
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
memset(buf, 0, sdp->sd_sb.sb_bsize);
|
|
Packit |
6ef888 |
error = read(sdp->device_fd, buf, sdp->sd_sb.sb_bsize);
|
|
Packit |
6ef888 |
if (error != sdp->sd_sb.sb_bsize){
|
|
Packit |
6ef888 |
log_crit( _("Can't read last block in file system (error %u), "
|
|
Packit |
6ef888 |
"last_fs_block: %llu (0x%llx)\n"), error,
|
|
Packit |
6ef888 |
(unsigned long long)last_fs_block,
|
|
Packit |
6ef888 |
(unsigned long long)last_fs_block);
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_info(_("0x%llx to 0x%llx\n"), (unsigned long long)first_data_block,
|
|
Packit |
6ef888 |
(unsigned long long)last_data_block);
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
fail:
|
|
Packit |
6ef888 |
log_info( _("Error\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* check_rgrp_integrity - verify a rgrp free block count against the bitmap
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static void check_rgrp_integrity(struct gfs2_sbd *sdp, struct rgrp_tree *rgd,
|
|
Packit |
6ef888 |
int *fixit, int *this_rg_fixed,
|
|
Packit |
6ef888 |
int *this_rg_bad, int *this_rg_cleaned)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
uint32_t rg_free, rg_reclaimed, rg_unlinked, rg_usedmeta, rg_useddi;
|
|
Packit |
6ef888 |
int rgb, x, y, off, bytes_to_check, total_bytes_to_check, asked = 0;
|
|
Packit |
6ef888 |
unsigned int state;
|
|
Packit |
6ef888 |
struct gfs_rgrp *gfs1rg = (struct gfs_rgrp *)&rgd->rg;
|
|
Packit |
6ef888 |
uint64_t diblock;
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
rg_free = rg_reclaimed = rg_unlinked = rg_usedmeta = rg_useddi = 0;
|
|
Packit |
6ef888 |
total_bytes_to_check = rgd->ri.ri_bitbytes;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
*this_rg_fixed = *this_rg_bad = *this_rg_cleaned = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
diblock = rgd->ri.ri_data0;
|
|
Packit |
6ef888 |
for (rgb = 0; rgb < rgd->ri.ri_length; rgb++){
|
|
Packit |
6ef888 |
/* Count up the free blocks in the bitmap */
|
|
Packit |
6ef888 |
off = (rgb) ? sizeof(struct gfs2_meta_header) :
|
|
Packit |
6ef888 |
sizeof(struct gfs2_rgrp);
|
|
Packit |
6ef888 |
if (total_bytes_to_check <= sdp->bsize - off)
|
|
Packit |
6ef888 |
bytes_to_check = total_bytes_to_check;
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
bytes_to_check = sdp->bsize - off;
|
|
Packit |
6ef888 |
total_bytes_to_check -= bytes_to_check;
|
|
Packit |
6ef888 |
for (x = 0; x < bytes_to_check; x++) {
|
|
Packit |
6ef888 |
unsigned char *byte;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
byte = (unsigned char *)&rgd->bits[rgb].bi_bh->b_data[off + x];
|
|
Packit |
6ef888 |
if (*byte == 0x55) {
|
|
Packit |
6ef888 |
diblock += GFS2_NBBY;
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (*byte == 0x00) {
|
|
Packit |
6ef888 |
diblock += GFS2_NBBY;
|
|
Packit |
6ef888 |
rg_free += GFS2_NBBY;
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
for (y = 0; y < GFS2_NBBY; y++) {
|
|
Packit |
6ef888 |
state = (*byte >>
|
|
Packit |
6ef888 |
(GFS2_BIT_SIZE * y)) & GFS2_BIT_MASK;
|
|
Packit |
6ef888 |
if (state == GFS2_BLKST_USED) {
|
|
Packit |
6ef888 |
diblock++;
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (state == GFS2_BLKST_DINODE) {
|
|
Packit |
6ef888 |
if (sdp->gfs1) {
|
|
Packit |
6ef888 |
bh = bread(sdp, diblock);
|
|
Packit |
6ef888 |
if (!gfs2_check_meta(bh,
|
|
Packit |
6ef888 |
GFS2_METATYPE_DI))
|
|
Packit |
6ef888 |
rg_useddi++;
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
rg_usedmeta++;
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
diblock++;
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (state == GFS2_BLKST_FREE) {
|
|
Packit |
6ef888 |
diblock++;
|
|
Packit |
6ef888 |
rg_free++;
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* GFS2_BLKST_UNLINKED */
|
|
Packit |
6ef888 |
if (sdp->gfs1)
|
|
Packit |
6ef888 |
log_info(_("Free metadata block 0x%llx"
|
|
Packit |
6ef888 |
" found.\n"),
|
|
Packit |
6ef888 |
(unsigned long long)diblock);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
log_info(_("Unlinked dinode 0x%llx "
|
|
Packit |
6ef888 |
"found.\n"),
|
|
Packit |
6ef888 |
(unsigned long long)diblock);
|
|
Packit |
6ef888 |
if (!asked) {
|
|
Packit |
6ef888 |
char msg[256];
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
asked = 1;
|
|
Packit |
6ef888 |
sprintf(msg,
|
|
Packit |
6ef888 |
_("Okay to reclaim free "
|
|
Packit |
6ef888 |
"metadata in resource group "
|
|
Packit |
6ef888 |
"%lld (0x%llx)? (y/n)"),
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr);
|
|
Packit |
6ef888 |
if (query("%s", msg))
|
|
Packit |
6ef888 |
*fixit = 1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (!(*fixit)) {
|
|
Packit |
6ef888 |
rg_unlinked++;
|
|
Packit |
6ef888 |
diblock++;
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
*byte &= ~(GFS2_BIT_MASK <<
|
|
Packit |
6ef888 |
(GFS2_BIT_SIZE * y));
|
|
Packit |
6ef888 |
bmodified(rgd->bits[rgb].bi_bh);
|
|
Packit |
6ef888 |
rg_reclaimed++;
|
|
Packit |
6ef888 |
rg_free++;
|
|
Packit |
6ef888 |
rgd->rg.rg_free++;
|
|
Packit |
6ef888 |
if (sdp->gfs1 && gfs1rg->rg_freemeta)
|
|
Packit |
6ef888 |
gfs1rg->rg_freemeta--;
|
|
Packit |
6ef888 |
log_info(_("Free metadata block %lld (0x%llx) "
|
|
Packit |
6ef888 |
"reclaimed.\n"),
|
|
Packit |
6ef888 |
(unsigned long long)diblock,
|
|
Packit |
6ef888 |
(unsigned long long)diblock);
|
|
Packit |
6ef888 |
bh = bread(sdp, diblock);
|
|
Packit |
6ef888 |
if (!gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
|
|
Packit |
6ef888 |
struct gfs2_inode *ip =
|
|
Packit |
6ef888 |
fsck_inode_get(sdp, rgd, bh);
|
|
Packit |
6ef888 |
if (ip->i_di.di_blocks > 1) {
|
|
Packit |
6ef888 |
blks_2free +=
|
|
Packit |
6ef888 |
ip->i_di.di_blocks - 1;
|
|
Packit |
6ef888 |
log_info(_("%lld blocks "
|
|
Packit |
6ef888 |
"(total) may need "
|
|
Packit |
6ef888 |
"to be freed in "
|
|
Packit |
6ef888 |
"pass 5.\n"),
|
|
Packit |
6ef888 |
blks_2free);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
fsck_inode_put(&ip);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
diblock++;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* The unlinked blocks we reclaim shouldn't be considered errors,
|
|
Packit |
6ef888 |
since we're just reclaiming them as a courtesy. If we already
|
|
Packit |
6ef888 |
got permission to reclaim them, we adjust the rgrp counts
|
|
Packit |
6ef888 |
accordingly. That way, only "real" rgrp count inconsistencies
|
|
Packit |
6ef888 |
will be reported. */
|
|
Packit |
6ef888 |
if (rg_reclaimed && *fixit) {
|
|
Packit |
6ef888 |
if (sdp->gfs1)
|
|
Packit |
6ef888 |
gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
gfs2_rgrp_out(&rgd->rg, rgd->bits[0].bi_bh->b_data);
|
|
Packit |
6ef888 |
bmodified(rgd->bits[0].bi_bh);
|
|
Packit |
6ef888 |
*this_rg_cleaned = 1;
|
|
Packit |
6ef888 |
log_info( _("The rgrp at %lld (0x%llx) was cleaned of %d "
|
|
Packit |
6ef888 |
"free metadata blocks.\n"),
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
rg_reclaimed);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (rgd->rg.rg_free != rg_free) {
|
|
Packit |
6ef888 |
*this_rg_bad = 1;
|
|
Packit |
6ef888 |
*this_rg_cleaned = 0;
|
|
Packit |
6ef888 |
log_err( _("Error: resource group %lld (0x%llx): "
|
|
Packit |
6ef888 |
"free space (%d) does not match bitmap (%d)\n"),
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
rgd->rg.rg_free, rg_free);
|
|
Packit |
6ef888 |
if (query( _("Fix the rgrp free blocks count? (y/n)"))) {
|
|
Packit |
6ef888 |
rgd->rg.rg_free = rg_free;
|
|
Packit |
6ef888 |
if (sdp->gfs1)
|
|
Packit |
6ef888 |
gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
gfs2_rgrp_out(&rgd->rg, rgd->bits[0].bi_bh->b_data);
|
|
Packit |
6ef888 |
bmodified(rgd->bits[0].bi_bh);
|
|
Packit |
6ef888 |
*this_rg_fixed = 1;
|
|
Packit |
6ef888 |
log_err( _("The rgrp was fixed.\n"));
|
|
Packit |
6ef888 |
} else
|
|
Packit |
6ef888 |
log_err( _("The rgrp was not fixed.\n"));
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (!sdp->gfs1)
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (gfs1rg->rg_freemeta != rg_unlinked) {
|
|
Packit |
6ef888 |
*this_rg_bad = 1;
|
|
Packit |
6ef888 |
*this_rg_cleaned = 0;
|
|
Packit |
6ef888 |
log_err( _("Error: resource group %lld (0x%llx): "
|
|
Packit |
6ef888 |
"free meta (%d) does not match bitmap (%d)\n"),
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
gfs1rg->rg_freemeta, rg_unlinked);
|
|
Packit |
6ef888 |
if (query( _("Fix the rgrp free meta blocks count? (y/n)"))) {
|
|
Packit |
6ef888 |
gfs1rg->rg_freemeta = rg_unlinked;
|
|
Packit |
6ef888 |
gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
|
|
Packit |
6ef888 |
*this_rg_fixed = 1;
|
|
Packit |
6ef888 |
log_err( _("The rgrp was fixed.\n"));
|
|
Packit |
6ef888 |
} else
|
|
Packit |
6ef888 |
log_err( _("The rgrp was not fixed.\n"));
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (gfs1rg->rg_useddi != rg_useddi) {
|
|
Packit |
6ef888 |
*this_rg_bad = 1;
|
|
Packit |
6ef888 |
*this_rg_cleaned = 0;
|
|
Packit |
6ef888 |
log_err( _("Error: resource group %lld (0x%llx): used dinode "
|
|
Packit |
6ef888 |
"count (%d) does not match bitmap (%d)\n"),
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
gfs1rg->rg_useddi, rg_useddi);
|
|
Packit |
6ef888 |
if (query( _("Fix the rgrp used dinode block count? (y/n)"))) {
|
|
Packit |
6ef888 |
gfs1rg->rg_useddi = rg_useddi;
|
|
Packit |
6ef888 |
gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg,
|
|
Packit |
6ef888 |
rgd->bits[0].bi_bh);
|
|
Packit |
6ef888 |
*this_rg_fixed = 1;
|
|
Packit |
6ef888 |
log_err( _("The rgrp was fixed.\n"));
|
|
Packit |
6ef888 |
} else
|
|
Packit |
6ef888 |
log_err( _("The rgrp was not fixed.\n"));
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (gfs1rg->rg_usedmeta != rg_usedmeta) {
|
|
Packit |
6ef888 |
*this_rg_bad = 1;
|
|
Packit |
6ef888 |
*this_rg_cleaned = 0;
|
|
Packit |
6ef888 |
log_err( _("Error: resource group %lld (0x%llx): used "
|
|
Packit |
6ef888 |
"metadata (%d) does not match bitmap (%d)\n"),
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
gfs1rg->rg_usedmeta, rg_usedmeta);
|
|
Packit |
6ef888 |
if (query( _("Fix the rgrp used meta blocks count? (y/n)"))) {
|
|
Packit |
6ef888 |
gfs1rg->rg_usedmeta = rg_usedmeta;
|
|
Packit |
6ef888 |
gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg,
|
|
Packit |
6ef888 |
rgd->bits[0].bi_bh);
|
|
Packit |
6ef888 |
*this_rg_fixed = 1;
|
|
Packit |
6ef888 |
log_err( _("The rgrp was fixed.\n"));
|
|
Packit |
6ef888 |
} else
|
|
Packit |
6ef888 |
log_err( _("The rgrp was not fixed.\n"));
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
else {
|
|
Packit |
6ef888 |
log_debug( _("Resource group %lld (0x%llx) free space "
|
|
Packit |
6ef888 |
"is consistent: free: %d reclaimed: %d\n"),
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
(unsigned long long)rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
rg_free, rg_reclaimed);
|
|
Packit |
6ef888 |
}*/
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* check_rgrps_integrity - verify rgrp consistency
|
|
Packit |
6ef888 |
* Note: We consider an rgrp "cleaned" if the unlinked meta blocks are
|
|
Packit |
6ef888 |
* cleaned, so not quite "bad" and not quite "good" but rewritten anyway.
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Returns: 0 on success, 1 if errors were detected
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static void check_rgrps_integrity(struct gfs2_sbd *sdp)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct osi_node *n, *next = NULL;
|
|
Packit |
6ef888 |
int rgs_good = 0, rgs_bad = 0, rgs_fixed = 0, rgs_cleaned = 0;
|
|
Packit |
6ef888 |
int was_bad = 0, was_fixed = 0, was_cleaned = 0;
|
|
Packit |
6ef888 |
struct rgrp_tree *rgd;
|
|
Packit |
6ef888 |
int reclaim_unlinked = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_info( _("Checking the integrity of all resource groups.\n"));
|
|
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 (fsck_abort)
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
check_rgrp_integrity(sdp, rgd, &reclaim_unlinked,
|
|
Packit |
6ef888 |
&was_fixed, &was_bad, &was_cleaned);
|
|
Packit |
6ef888 |
if (was_fixed)
|
|
Packit |
6ef888 |
rgs_fixed++;
|
|
Packit |
6ef888 |
if (was_cleaned)
|
|
Packit |
6ef888 |
rgs_cleaned++;
|
|
Packit |
6ef888 |
else if (was_bad)
|
|
Packit |
6ef888 |
rgs_bad++;
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
rgs_good++;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (rgs_bad || rgs_cleaned) {
|
|
Packit |
6ef888 |
log_err( _("RGs: Consistent: %d Cleaned: %d Inconsistent: "
|
|
Packit |
6ef888 |
"%d Fixed: %d Total: %d\n"),
|
|
Packit |
6ef888 |
rgs_good, rgs_cleaned, rgs_bad, rgs_fixed,
|
|
Packit |
6ef888 |
rgs_good + rgs_bad + rgs_cleaned);
|
|
Packit |
6ef888 |
if (rgs_cleaned && blks_2free)
|
|
Packit |
6ef888 |
log_err(_("%lld blocks may need to be freed in pass 5 "
|
|
Packit |
6ef888 |
"due to the cleaned resource groups.\n"),
|
|
Packit |
6ef888 |
blks_2free);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* rebuild_master - rebuild a destroyed master directory
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int rebuild_master(struct gfs2_sbd *sdp)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct gfs2_inum inum;
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh = NULL;
|
|
Packit |
6ef888 |
int err = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_err(_("The system master directory seems to be destroyed.\n"));
|
|
Packit |
6ef888 |
if (!query(_("Okay to rebuild it? (y/n)"))) {
|
|
Packit |
6ef888 |
log_err(_("System master not rebuilt; aborting.\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_err(_("Trying to rebuild the master directory.\n"));
|
|
Packit |
6ef888 |
inum.no_formal_ino = sdp->md.next_inum++;
|
|
Packit |
6ef888 |
inum.no_addr = sdp->sd_sb.sb_master_dir.no_addr;
|
|
Packit |
6ef888 |
err = init_dinode(sdp, &bh, &inum, S_IFDIR | 0755, GFS2_DIF_SYSTEM, &inum);
|
|
Packit |
6ef888 |
if (err != 0)
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
sdp->master_dir = lgfs2_inode_get(sdp, bh);
|
|
Packit |
6ef888 |
if (sdp->master_dir == NULL) {
|
|
Packit |
6ef888 |
log_crit(_("Error reading master: %s\n"), strerror(errno));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
sdp->master_dir->bh_owned = 1;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (fix_md.jiinode) {
|
|
Packit |
6ef888 |
inum.no_formal_ino = sdp->md.next_inum++;
|
|
Packit |
6ef888 |
inum.no_addr = fix_md.jiinode->i_di.di_num.no_addr;
|
|
Packit |
6ef888 |
err = dir_add(sdp->master_dir, "jindex", 6, &inum,
|
|
Packit |
6ef888 |
IF2DT(S_IFDIR | 0700));
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d adding jindex directory\n"), errno);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
sdp->master_dir->i_di.di_nlink++;
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
err = build_jindex(sdp);
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d building jindex\n"), err);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (fix_md.pinode) {
|
|
Packit |
6ef888 |
inum.no_formal_ino = sdp->md.next_inum++;
|
|
Packit |
6ef888 |
inum.no_addr = fix_md.pinode->i_di.di_num.no_addr;
|
|
Packit |
6ef888 |
err = dir_add(sdp->master_dir, "per_node", 8, &inum,
|
|
Packit |
6ef888 |
IF2DT(S_IFDIR | 0700));
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d adding per_node directory\n"),
|
|
Packit |
6ef888 |
errno);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
sdp->master_dir->i_di.di_nlink++;
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
err = build_per_node(sdp);
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d building per_node directory\n"),
|
|
Packit |
6ef888 |
err);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (fix_md.inum) {
|
|
Packit |
6ef888 |
inum.no_formal_ino = sdp->md.next_inum++;
|
|
Packit |
6ef888 |
inum.no_addr = fix_md.inum->i_di.di_num.no_addr;
|
|
Packit |
6ef888 |
err = dir_add(sdp->master_dir, "inum", 4, &inum,
|
|
Packit |
6ef888 |
IF2DT(S_IFREG | 0600));
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d adding inum inode\n"), errno);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
err = build_inum(sdp);
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d building inum inode\n"), err);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (fix_md.statfs) {
|
|
Packit |
6ef888 |
inum.no_formal_ino = sdp->md.next_inum++;
|
|
Packit |
6ef888 |
inum.no_addr = fix_md.statfs->i_di.di_num.no_addr;
|
|
Packit |
6ef888 |
err = dir_add(sdp->master_dir, "statfs", 6, &inum,
|
|
Packit |
6ef888 |
IF2DT(S_IFREG | 0600));
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d adding statfs inode\n"), errno);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
err = build_statfs(sdp);
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d building statfs inode\n"), err);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (fix_md.riinode) {
|
|
Packit |
6ef888 |
inum.no_formal_ino = sdp->md.next_inum++;
|
|
Packit |
6ef888 |
inum.no_addr = fix_md.riinode->i_di.di_num.no_addr;
|
|
Packit |
6ef888 |
err = dir_add(sdp->master_dir, "rindex", 6, &inum,
|
|
Packit |
6ef888 |
IF2DT(S_IFREG | 0600));
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d adding rindex inode\n"), errno);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
err = build_rindex(sdp);
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d building rindex inode\n"), err);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (fix_md.qinode) {
|
|
Packit |
6ef888 |
inum.no_formal_ino = sdp->md.next_inum++;
|
|
Packit |
6ef888 |
inum.no_addr = fix_md.qinode->i_di.di_num.no_addr;
|
|
Packit |
6ef888 |
err = dir_add(sdp->master_dir, "quota", 5, &inum,
|
|
Packit |
6ef888 |
IF2DT(S_IFREG | 0600));
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d adding quota inode\n"), errno);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
err = build_quota(sdp);
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d building quota inode\n"), err);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_err(_("Master directory rebuilt.\n"));
|
|
Packit |
6ef888 |
inode_put(&sdp->md.inum);
|
|
Packit |
6ef888 |
inode_put(&sdp->md.statfs);
|
|
Packit |
6ef888 |
inode_put(&sdp->master_dir);
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* lookup_per_node - Make sure the per_node directory is read in
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* This function is used to read in the per_node directory. It is called
|
|
Packit |
6ef888 |
* twice. The first call tries to read in the dinode early on. That ensures
|
|
Packit |
6ef888 |
* that if any journals are missing, we can figure out the number of journals
|
|
Packit |
6ef888 |
* from per_node. However, we unfortunately can't rebuild per_node at that
|
|
Packit |
6ef888 |
* point in time because our resource groups aren't read in yet.
|
|
Packit |
6ef888 |
* The second time it's called is much later when we can rebuild it.
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* allow_rebuild: 0 if rebuilds are not allowed
|
|
Packit |
6ef888 |
* 1 if rebuilds are allowed
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static void lookup_per_node(struct gfs2_sbd *sdp, int allow_rebuild)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
if (sdp->md.pinode)
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
gfs2_lookupi(sdp->master_dir, "per_node", 8, &sdp->md.pinode);
|
|
Packit |
6ef888 |
if (sdp->md.pinode)
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
if (!allow_rebuild) {
|
|
Packit |
6ef888 |
log_err( _("The gfs2 system per_node directory "
|
|
Packit |
6ef888 |
"inode is missing, so we might not be \nable to "
|
|
Packit |
6ef888 |
"rebuild missing journals this run.\n"));
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (query( _("The gfs2 system per_node directory "
|
|
Packit |
6ef888 |
"inode is missing. Okay to rebuild it? (y/n) "))) {
|
|
Packit |
6ef888 |
int err;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
err = build_per_node(sdp);
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d rebuilding per_node directory\n"),
|
|
Packit |
6ef888 |
err);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
gfs2_lookupi(sdp->master_dir, "per_node", 8, &sdp->md.pinode);
|
|
Packit |
6ef888 |
if (!sdp->md.pinode) {
|
|
Packit |
6ef888 |
log_err( _("Unable to rebuild per_node; aborting.\n"));
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* fetch_rgrps - fetch the resource groups from disk, and check their integrity
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int fetch_rgrps(struct gfs2_sbd *sdp)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
enum rgindex_trust_level trust_lvl;
|
|
Packit |
6ef888 |
int rgcount, sane = 1;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
const char *level_desc[] = {
|
|
Packit |
6ef888 |
_("Checking if all rgrp and rindex values are good"),
|
|
Packit |
6ef888 |
_("Checking if rindex values may be easily repaired"),
|
|
Packit |
6ef888 |
_("Calculating where the rgrps should be if evenly spaced"),
|
|
Packit |
6ef888 |
_("Trying to rebuild rindex assuming evenly spaced rgrps"),
|
|
Packit |
6ef888 |
_("Trying to rebuild rindex assuming unevenly spaced rgrps"),
|
|
Packit |
6ef888 |
};
|
|
Packit |
6ef888 |
const char *fail_desc[] = {
|
|
Packit |
6ef888 |
_("Some damage was found; we need to take remedial measures"),
|
|
Packit |
6ef888 |
_("rindex is unevenly spaced: either gfs1-style or corrupt"),
|
|
Packit |
6ef888 |
_("rindex calculations don't match: uneven rgrp boundaries"),
|
|
Packit |
6ef888 |
_("Too many rgrp misses: rgrps must be unevenly spaced"),
|
|
Packit |
6ef888 |
_("Too much damage found: we cannot rebuild this rindex"),
|
|
Packit |
6ef888 |
};
|
|
Packit |
6ef888 |
/*******************************************************************
|
|
Packit |
6ef888 |
******** Validate and read in resource group information ********
|
|
Packit |
6ef888 |
*******************************************************************/
|
|
Packit |
6ef888 |
log_notice(_("Validating resource group index.\n"));
|
|
Packit |
6ef888 |
for (trust_lvl = blind_faith; trust_lvl <= indignation; trust_lvl++) {
|
|
Packit |
6ef888 |
int ret = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_notice(_("Level %d resource group check: %s.\n"), trust_lvl + 1,
|
|
Packit |
6ef888 |
level_desc[trust_lvl]);
|
|
Packit |
6ef888 |
if ((rg_repair(sdp, trust_lvl, &rgcount, &sane) == 0) &&
|
|
Packit |
6ef888 |
((ret = ri_update(sdp, 0, &rgcount, &sane)) == 0)) {
|
|
Packit |
6ef888 |
log_notice(_("(level %d passed)\n"), trust_lvl + 1);
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
if (ret == -1)
|
|
Packit |
6ef888 |
log_err( _("(level %d failed: %s)\n"),
|
|
Packit |
6ef888 |
trust_lvl + 1, fail_desc[trust_lvl]);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
log_err( _("(level %d failed at block %lld "
|
|
Packit |
6ef888 |
"(0x%llx): %s)\n"), trust_lvl + 1,
|
|
Packit |
6ef888 |
(unsigned long long)ret,
|
|
Packit |
6ef888 |
(unsigned long long)ret,
|
|
Packit |
6ef888 |
fail_desc[trust_lvl]);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (fsck_abort)
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (trust_lvl > indignation) {
|
|
Packit |
6ef888 |
log_err( _("Resource group recovery impossible; I can't fix "
|
|
Packit |
6ef888 |
"this file system.\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_info( _("%u resource groups found.\n"), rgcount);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
check_rgrps_integrity(sdp);
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* init_system_inodes
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Returns: 0 on success, -1 on failure
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int init_system_inodes(struct gfs2_sbd *sdp)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
uint64_t inumbuf = 0;
|
|
Packit |
6ef888 |
char *buf;
|
|
Packit |
6ef888 |
struct gfs2_statfs_change sc;
|
|
Packit |
6ef888 |
int err;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*******************************************************************
|
|
Packit |
6ef888 |
****************** Initialize important inodes ******************
|
|
Packit |
6ef888 |
*******************************************************************/
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_info( _("Initializing special inodes...\n"));
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* Get root dinode */
|
|
Packit |
6ef888 |
sdp->md.rooti = lgfs2_inode_read(sdp, sdp->sd_sb.sb_root_dir.no_addr);
|
|
Packit |
6ef888 |
if (sdp->md.rooti == NULL)
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*******************************************************************
|
|
Packit |
6ef888 |
***************** Initialize more system inodes *****************
|
|
Packit |
6ef888 |
*******************************************************************/
|
|
Packit |
6ef888 |
if (!sdp->gfs1) {
|
|
Packit |
6ef888 |
/* Look for "inum" entry in master dinode */
|
|
Packit |
6ef888 |
gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
|
|
Packit |
6ef888 |
if (!sdp->md.inum) {
|
|
Packit |
6ef888 |
if (!query( _("The gfs2 system inum inode is missing. "
|
|
Packit |
6ef888 |
"Okay to rebuild it? (y/n) "))) {
|
|
Packit |
6ef888 |
log_err( _("fsck.gfs2 cannot continue without "
|
|
Packit |
6ef888 |
"a valid inum file; aborting.\n"));
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
err = build_inum(sdp);
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d rebuilding inum inode\n"),
|
|
Packit |
6ef888 |
err);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
gfs2_lookupi(sdp->master_dir, "inum", 4,
|
|
Packit |
6ef888 |
&sdp->md.inum);
|
|
Packit |
6ef888 |
if (!sdp->md.inum) {
|
|
Packit |
6ef888 |
log_crit(_("System inum inode was not rebuilt."
|
|
Packit |
6ef888 |
" Aborting.\n"));
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* Read inum entry into buffer */
|
|
Packit |
6ef888 |
err = gfs2_readi(sdp->md.inum, &inumbuf, 0,
|
|
Packit |
6ef888 |
sdp->md.inum->i_di.di_size);
|
|
Packit |
6ef888 |
if (err != sdp->md.inum->i_di.di_size) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d reading system inum inode. "
|
|
Packit |
6ef888 |
"Aborting.\n"), err);
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* call gfs2_inum_range_in() to retrieve range */
|
|
Packit |
6ef888 |
sdp->md.next_inum = be64_to_cpu(inumbuf);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sdp->gfs1) {
|
|
Packit |
6ef888 |
/* In gfs1, the license_di is always 3 blocks after the jindex_di */
|
|
Packit |
6ef888 |
if ((sbd1->sb_license_di.no_addr != sbd1->sb_jindex_di.no_addr + 3) ||
|
|
Packit |
6ef888 |
(sbd1->sb_license_di.no_formal_ino != sbd1->sb_jindex_di.no_addr + 3)) {
|
|
Packit |
6ef888 |
if (!query( _("The gfs system statfs inode pointer is incorrect. "
|
|
Packit |
6ef888 |
"Okay to correct? (y/n) "))) {
|
|
Packit |
6ef888 |
log_err( _("fsck.gfs2 cannot continue without a valid "
|
|
Packit |
6ef888 |
"statfs file; aborting.\n"));
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
sbd1->sb_license_di.no_addr = sbd1->sb_license_di.no_formal_ino
|
|
Packit |
6ef888 |
= sbd1->sb_jindex_di.no_addr + 3;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
sdp->md.statfs = lgfs2_inode_read(sdp, sbd1->sb_license_di.no_addr);
|
|
Packit |
6ef888 |
if (sdp->md.statfs == NULL) {
|
|
Packit |
6ef888 |
log_crit(_("Error reading statfs inode: %s\n"), strerror(errno));
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
} else
|
|
Packit |
6ef888 |
gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
|
|
Packit |
6ef888 |
if (!sdp->gfs1 && !sdp->md.statfs) {
|
|
Packit |
6ef888 |
if (!query( _("The gfs2 system statfs inode is missing. "
|
|
Packit |
6ef888 |
"Okay to rebuild it? (y/n) "))) {
|
|
Packit |
6ef888 |
log_err( _("fsck.gfs2 cannot continue without a valid "
|
|
Packit |
6ef888 |
"statfs file; aborting.\n"));
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
err = build_statfs(sdp);
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d rebuilding statfs inode\n"), err);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
|
|
Packit |
6ef888 |
if (!sdp->md.statfs) {
|
|
Packit |
6ef888 |
log_err( _("Rebuild of statfs system file failed."));
|
|
Packit |
6ef888 |
log_err( _("fsck.gfs2 cannot continue without "
|
|
Packit |
6ef888 |
"a valid statfs file; aborting.\n"));
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
do_init_statfs(sdp);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (sdp->md.statfs->i_di.di_size) {
|
|
Packit |
6ef888 |
buf = malloc(sdp->md.statfs->i_di.di_size);
|
|
Packit |
6ef888 |
if (buf) {
|
|
Packit |
6ef888 |
err = gfs2_readi(sdp->md.statfs, buf, 0,
|
|
Packit |
6ef888 |
sdp->md.statfs->i_di.di_size);
|
|
Packit |
6ef888 |
if (err != sdp->md.statfs->i_di.di_size) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d reading statfs file. "
|
|
Packit |
6ef888 |
"Aborting.\n"), err);
|
|
Packit |
6ef888 |
free(buf);
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* call gfs2_inum_range_in() to retrieve range */
|
|
Packit |
6ef888 |
gfs2_statfs_change_in(&sc, buf);
|
|
Packit |
6ef888 |
free(buf);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sdp->gfs1) {
|
|
Packit |
6ef888 |
/* In gfs1, the quota_di is always 2 blocks after the jindex_di */
|
|
Packit |
6ef888 |
if ((sbd1->sb_quota_di.no_addr != sbd1->sb_jindex_di.no_addr + 2) ||
|
|
Packit |
6ef888 |
(sbd1->sb_quota_di.no_formal_ino != sbd1->sb_jindex_di.no_addr + 2)) {
|
|
Packit |
6ef888 |
if (!query( _("The gfs system quota inode pointer is incorrect. "
|
|
Packit |
6ef888 |
" Okay to correct? (y/n) "))) {
|
|
Packit |
6ef888 |
log_err( _("fsck.gfs2 cannot continue without a valid "
|
|
Packit |
6ef888 |
"quota file; aborting.\n"));
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
sbd1->sb_quota_di.no_addr = sbd1->sb_quota_di.no_formal_ino
|
|
Packit |
6ef888 |
= sbd1->sb_jindex_di.no_addr + 2;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
sdp->md.qinode = lgfs2_inode_read(sdp, sbd1->sb_quota_di.no_addr);
|
|
Packit |
6ef888 |
if (sdp->md.qinode == NULL) {
|
|
Packit |
6ef888 |
log_crit(_("Error reading quota inode: %s\n"), strerror(errno));
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
} else
|
|
Packit |
6ef888 |
gfs2_lookupi(sdp->master_dir, "quota", 5, &sdp->md.qinode);
|
|
Packit |
6ef888 |
if (!sdp->gfs1 && !sdp->md.qinode) {
|
|
Packit |
6ef888 |
if (!query( _("The gfs2 system quota inode is missing. "
|
|
Packit |
6ef888 |
"Okay to rebuild it? (y/n) "))) {
|
|
Packit |
6ef888 |
log_crit(_("System quota inode was not "
|
|
Packit |
6ef888 |
"rebuilt. Aborting.\n"));
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
err = build_quota(sdp);
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d rebuilding quota inode\n"), err);
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
gfs2_lookupi(sdp->master_dir, "quota", 5, &sdp->md.qinode);
|
|
Packit |
6ef888 |
if (!sdp->md.qinode) {
|
|
Packit |
6ef888 |
log_crit(_("Unable to rebuild system quota file "
|
|
Packit |
6ef888 |
"inode. Aborting.\n"));
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* Try to lookup the per_node inode. If it was missing, it is now
|
|
Packit |
6ef888 |
safe to rebuild it. */
|
|
Packit |
6ef888 |
if (!sdp->gfs1)
|
|
Packit |
6ef888 |
lookup_per_node(sdp, 1);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*******************************************************************
|
|
Packit |
6ef888 |
******* Now, set boundary fields in the super block *************
|
|
Packit |
6ef888 |
*******************************************************************/
|
|
Packit |
6ef888 |
if (set_block_ranges(sdp)){
|
|
Packit |
6ef888 |
log_err( _("Unable to determine the boundaries of the"
|
|
Packit |
6ef888 |
" file system.\n"));
|
|
Packit |
6ef888 |
goto fail;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
fail:
|
|
Packit |
6ef888 |
empty_super_block(sdp);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* is_journal_copy - Is this a "real" dinode or a copy inside a journal?
|
|
Packit |
6ef888 |
* A real dinode will be located at the block number in its no_addr.
|
|
Packit |
6ef888 |
* A journal-copy will be at a different block (inside the journal).
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int is_journal_copy(struct gfs2_inode *ip, struct gfs2_buffer_head *bh)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
if (ip->i_di.di_num.no_addr == bh->b_blocknr)
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
return 1; /* journal copy */
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* peruse_system_dinode - process a system dinode
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* This function looks at a system dinode and tries to figure out which
|
|
Packit |
6ef888 |
* dinode it is: statfs, inum, per_node, master, etc. Some of them we
|
|
Packit |
6ef888 |
* can deduce from the contents. For example, di_size will be a multiple
|
|
Packit |
6ef888 |
* of 96 for the rindex. di_size will be 8 for inum, 24 for statfs, etc.
|
|
Packit |
6ef888 |
* the per_node directory will have a ".." entry that will lead us to
|
|
Packit |
6ef888 |
* the master dinode if it's been destroyed.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static void peruse_system_dinode(struct gfs2_sbd *sdp, struct gfs2_dinode *di,
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct gfs2_inode *ip, *child_ip;
|
|
Packit |
6ef888 |
struct gfs2_inum inum;
|
|
Packit |
6ef888 |
int error;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (di->di_num.no_formal_ino == 2) {
|
|
Packit |
6ef888 |
if (sdp->sd_sb.sb_master_dir.no_addr)
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
log_warn(_("Found system master directory at: 0x%llx.\n"),
|
|
Packit |
6ef888 |
di->di_num.no_addr);
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_master_dir.no_addr = di->di_num.no_addr;
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
ip = lgfs2_inode_read(sdp, di->di_num.no_addr);
|
|
Packit |
6ef888 |
if (ip == NULL) {
|
|
Packit |
6ef888 |
log_crit(_("Error reading inode: %s\n"), strerror(errno));
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if ((!sdp->gfs1 && di->di_num.no_formal_ino == 3) ||
|
|
Packit |
6ef888 |
(sdp->gfs1 && (di->di_flags & GFS2_DIF_JDATA) &&
|
|
Packit |
6ef888 |
(di->di_size % sizeof(struct gfs_jindex) == 0))) {
|
|
Packit |
6ef888 |
if (fix_md.jiinode || is_journal_copy(ip, bh))
|
|
Packit |
6ef888 |
goto out_discard_ip;
|
|
Packit |
6ef888 |
log_warn(_("Found system jindex file at: 0x%llx\n"),
|
|
Packit |
6ef888 |
di->di_num.no_addr);
|
|
Packit |
6ef888 |
fix_md.jiinode = ip;
|
|
Packit |
6ef888 |
} else if (!sdp->gfs1 && is_dir(di, sdp->gfs1)) {
|
|
Packit |
6ef888 |
/* Check for a jindex dir entry. Only one system dir has a
|
|
Packit |
6ef888 |
jindex: master */
|
|
Packit |
6ef888 |
gfs2_lookupi(ip, "jindex", 6, &child_ip);
|
|
Packit |
6ef888 |
if (child_ip) {
|
|
Packit |
6ef888 |
if (fix_md.jiinode || is_journal_copy(ip, bh)) {
|
|
Packit |
6ef888 |
inode_put(&child_ip);
|
|
Packit |
6ef888 |
goto out_discard_ip;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
fix_md.jiinode = child_ip;
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_master_dir.no_addr = di->di_num.no_addr;
|
|
Packit |
6ef888 |
log_warn(_("Found system master directory at: "
|
|
Packit |
6ef888 |
"0x%llx\n"), di->di_num.no_addr);
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* Check for a statfs_change0 dir entry. Only one system dir
|
|
Packit |
6ef888 |
has a statfs_change: per_node, and its .. will be master. */
|
|
Packit |
6ef888 |
gfs2_lookupi(ip, "statfs_change0", 14, &child_ip);
|
|
Packit |
6ef888 |
if (child_ip) {
|
|
Packit |
6ef888 |
inode_put(&child_ip);
|
|
Packit |
6ef888 |
if (fix_md.pinode || is_journal_copy(ip, bh))
|
|
Packit |
6ef888 |
goto out_discard_ip;
|
|
Packit |
6ef888 |
log_warn(_("Found system per_node directory at: "
|
|
Packit |
6ef888 |
"0x%llx\n"), ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
fix_md.pinode = ip;
|
|
Packit |
6ef888 |
error = dir_search(ip, "..", 2, NULL, &inum);
|
|
Packit |
6ef888 |
if (!error && inum.no_addr) {
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_master_dir.no_addr =
|
|
Packit |
6ef888 |
inum.no_addr;
|
|
Packit |
6ef888 |
log_warn(_("From per_node\'s \'..\' I "
|
|
Packit |
6ef888 |
"backtracked the master directory "
|
|
Packit |
6ef888 |
"to: 0x%llx\n"), inum.no_addr);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_debug(_("Unknown system directory at block 0x%llx\n"),
|
|
Packit |
6ef888 |
di->di_num.no_addr);
|
|
Packit |
6ef888 |
goto out_discard_ip;
|
|
Packit |
6ef888 |
} else if (!sdp->gfs1 && di->di_size == 8) {
|
|
Packit |
6ef888 |
if (fix_md.inum || is_journal_copy(ip, bh))
|
|
Packit |
6ef888 |
goto out_discard_ip;
|
|
Packit |
6ef888 |
fix_md.inum = ip;
|
|
Packit |
6ef888 |
log_warn(_("Found system inum file at: 0x%llx\n"),
|
|
Packit |
6ef888 |
di->di_num.no_addr);
|
|
Packit |
6ef888 |
} else if (di->di_size == 24) {
|
|
Packit |
6ef888 |
if (fix_md.statfs || is_journal_copy(ip, bh))
|
|
Packit |
6ef888 |
goto out_discard_ip;
|
|
Packit |
6ef888 |
fix_md.statfs = ip;
|
|
Packit |
6ef888 |
log_warn(_("Found system statfs file at: 0x%llx\n"),
|
|
Packit |
6ef888 |
di->di_num.no_addr);
|
|
Packit |
6ef888 |
} else if ((di->di_size % 96) == 0) {
|
|
Packit |
6ef888 |
if (fix_md.riinode || is_journal_copy(ip, bh))
|
|
Packit |
6ef888 |
goto out_discard_ip;
|
|
Packit |
6ef888 |
fix_md.riinode = ip;
|
|
Packit |
6ef888 |
log_warn(_("Found system rindex file at: 0x%llx\n"),
|
|
Packit |
6ef888 |
di->di_num.no_addr);
|
|
Packit |
6ef888 |
} else if (!fix_md.qinode && di->di_size >= 176 &&
|
|
Packit |
6ef888 |
di->di_num.no_formal_ino >= 12 &&
|
|
Packit |
6ef888 |
di->di_num.no_formal_ino <= 100) {
|
|
Packit |
6ef888 |
if (is_journal_copy(ip, bh))
|
|
Packit |
6ef888 |
goto out_discard_ip;
|
|
Packit |
6ef888 |
fix_md.qinode = ip;
|
|
Packit |
6ef888 |
log_warn(_("Found system quota file at: 0x%llx\n"),
|
|
Packit |
6ef888 |
di->di_num.no_addr);
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
out_discard_ip:
|
|
Packit |
6ef888 |
inode_put(&ip);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* peruse_user_dinode - process a user dinode trying to find the root directory
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static void peruse_user_dinode(struct gfs2_sbd *sdp, struct gfs2_dinode *di,
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct gfs2_inode *ip, *parent_ip;
|
|
Packit |
6ef888 |
struct gfs2_inum inum;
|
|
Packit |
6ef888 |
int error;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sdp->sd_sb.sb_root_dir.no_addr) /* if we know the root dinode */
|
|
Packit |
6ef888 |
return; /* we don't need to find the root */
|
|
Packit |
6ef888 |
if (!is_dir(di, sdp->gfs1)) /* if this isn't a directory */
|
|
Packit |
6ef888 |
return; /* it can't lead us to the root anyway */
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (di->di_num.no_formal_ino == 1) {
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *root_bh;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (di->di_num.no_addr == bh->b_blocknr) {
|
|
Packit |
6ef888 |
log_warn(_("Found the root directory at: 0x%llx.\n"),
|
|
Packit |
6ef888 |
di->di_num.no_addr);
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_root_dir.no_addr = di->di_num.no_addr;
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_warn(_("The root dinode should be at block 0x%llx but it "
|
|
Packit |
6ef888 |
"seems to be destroyed.\n"),
|
|
Packit |
6ef888 |
(unsigned long long)di->di_num.no_addr);
|
|
Packit |
6ef888 |
log_warn(_("Found a copy of the root directory in a journal "
|
|
Packit |
6ef888 |
"at block: 0x%llx.\n"),
|
|
Packit |
6ef888 |
(unsigned long long)bh->b_blocknr);
|
|
Packit |
6ef888 |
if (!query(_("Do you want to replace the root dinode from the "
|
|
Packit |
6ef888 |
"copy? (y/n)"))) {
|
|
Packit |
6ef888 |
log_err(_("Damaged root dinode not fixed.\n"));
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
root_bh = bread(sdp, di->di_num.no_addr);
|
|
Packit |
6ef888 |
memcpy(root_bh->b_data, bh->b_data, sdp->bsize);
|
|
Packit |
6ef888 |
bmodified(root_bh);
|
|
Packit |
6ef888 |
brelse(root_bh);
|
|
Packit |
6ef888 |
log_warn(_("Root directory copied from the journal.\n"));
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
ip = lgfs2_inode_read(sdp, di->di_num.no_addr);
|
|
Packit |
6ef888 |
if (ip == NULL) {
|
|
Packit |
6ef888 |
log_crit(_("Error reading inode: %s\n"), strerror(errno));
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
while (ip) {
|
|
Packit |
6ef888 |
gfs2_lookupi(ip, "..", 2, &parent_ip);
|
|
Packit |
6ef888 |
if (parent_ip && parent_ip->i_di.di_num.no_addr ==
|
|
Packit |
6ef888 |
ip->i_di.di_num.no_addr) {
|
|
Packit |
6ef888 |
log_warn(_("Found the root directory at: 0x%llx\n"),
|
|
Packit |
6ef888 |
ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_root_dir.no_addr =
|
|
Packit |
6ef888 |
ip->i_di.di_num.no_addr;
|
|
Packit |
6ef888 |
inode_put(&parent_ip);
|
|
Packit |
6ef888 |
inode_put(&ip);
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (!parent_ip)
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
inode_put(&ip);
|
|
Packit |
6ef888 |
ip = parent_ip;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
error = dir_search(ip, "..", 2, NULL, &inum);
|
|
Packit |
6ef888 |
if (!error && inum.no_addr && inum.no_addr < possible_root) {
|
|
Packit |
6ef888 |
possible_root = inum.no_addr;
|
|
Packit |
6ef888 |
log_debug(_("Found a possible root at: 0x%llx\n"),
|
|
Packit |
6ef888 |
(unsigned long long)possible_root);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
inode_put(&ip);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* find_rgs_for_bsize - check a range of blocks for rgrps to determine bsize.
|
|
Packit |
6ef888 |
* Assumes: device is open.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int find_rgs_for_bsize(struct gfs2_sbd *sdp, uint64_t startblock,
|
|
Packit |
6ef888 |
uint32_t *known_bsize)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
uint64_t blk, max_rg_size, rb_addr;
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh, *rb_bh;
|
|
Packit |
6ef888 |
uint32_t bsize, bsize2;
|
|
Packit |
6ef888 |
uint32_t chk;
|
|
Packit |
6ef888 |
char *p;
|
|
Packit |
6ef888 |
int found_rg;
|
|
Packit |
6ef888 |
struct gfs2_meta_header mh;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
sdp->bsize = GFS2_DEFAULT_BSIZE;
|
|
Packit |
6ef888 |
max_rg_size = 524288;
|
|
Packit |
6ef888 |
/* Max RG size is 2GB. Max block size is 4K. 2G / 4K blks = 524288,
|
|
Packit |
6ef888 |
So this is traversing 2GB in 4K block increments. */
|
|
Packit |
6ef888 |
for (blk = startblock; blk < startblock + max_rg_size; blk++) {
|
|
Packit |
6ef888 |
bh = bread(sdp, blk);
|
|
Packit |
6ef888 |
found_rg = 0;
|
|
Packit |
6ef888 |
for (bsize = 0; bsize < GFS2_DEFAULT_BSIZE;
|
|
Packit |
6ef888 |
bsize += GFS2_BASIC_BLOCK) {
|
|
Packit |
6ef888 |
p = bh->b_data + bsize;
|
|
Packit |
6ef888 |
chk = ((struct gfs2_meta_header *)p)->mh_magic;
|
|
Packit |
6ef888 |
if (be32_to_cpu(chk) != GFS2_MAGIC)
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
chk = ((struct gfs2_meta_header *)p)->mh_type;
|
|
Packit |
6ef888 |
if (be32_to_cpu(chk) == GFS2_METATYPE_RG) {
|
|
Packit |
6ef888 |
found_rg = 1;
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (!found_rg)
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
/* Try all the block sizes in 512 byte multiples */
|
|
Packit |
6ef888 |
for (bsize2 = GFS2_BASIC_BLOCK; bsize2 <= GFS2_DEFAULT_BSIZE;
|
|
Packit |
6ef888 |
bsize2 += GFS2_BASIC_BLOCK) {
|
|
Packit |
6ef888 |
rb_addr = (bh->b_blocknr *
|
|
Packit |
6ef888 |
(GFS2_DEFAULT_BSIZE / bsize2)) +
|
|
Packit |
6ef888 |
(bsize / bsize2) + 1;
|
|
Packit |
6ef888 |
sdp->bsize = bsize2; /* temporarily */
|
|
Packit |
6ef888 |
rb_bh = bread(sdp, rb_addr);
|
|
Packit |
6ef888 |
gfs2_meta_header_in(&mh, rb_bh->b_data);
|
|
Packit |
6ef888 |
brelse(rb_bh);
|
|
Packit |
6ef888 |
if (mh.mh_magic == GFS2_MAGIC &&
|
|
Packit |
6ef888 |
mh.mh_type == GFS2_METATYPE_RB) {
|
|
Packit |
6ef888 |
log_debug(_("boff:%d bsize2:%d rg:0x%llx, "
|
|
Packit |
6ef888 |
"rb:0x%llx\n"), bsize, bsize2,
|
|
Packit |
6ef888 |
(unsigned long long)blk,
|
|
Packit |
6ef888 |
(unsigned long long)rb_addr);
|
|
Packit |
6ef888 |
*known_bsize = bsize2;
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
if (!(*known_bsize)) {
|
|
Packit |
6ef888 |
sdp->bsize = GFS2_DEFAULT_BSIZE;
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
sdp->bsize = *known_bsize;
|
|
Packit |
6ef888 |
log_warn(_("Block size determined to be: %d\n"), *known_bsize);
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* peruse_metadata - check a range of blocks for metadata
|
|
Packit |
6ef888 |
* Assumes: device is open.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int peruse_metadata(struct gfs2_sbd *sdp, uint64_t startblock)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
uint64_t blk, max_rg_size;
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh;
|
|
Packit |
6ef888 |
struct gfs2_dinode di;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
max_rg_size = 2147483648ull / sdp->bsize;
|
|
Packit |
6ef888 |
/* Max RG size is 2GB. 2G / bsize. */
|
|
Packit |
6ef888 |
for (blk = startblock; blk < startblock + max_rg_size; blk++) {
|
|
Packit |
6ef888 |
bh = bread(sdp, blk);
|
|
Packit |
6ef888 |
if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
gfs2_dinode_in(&di, bh->b_data);
|
|
Packit |
6ef888 |
if (di.di_flags & GFS2_DIF_SYSTEM)
|
|
Packit |
6ef888 |
peruse_system_dinode(sdp, &di, bh);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
peruse_user_dinode(sdp, &di, bh);
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* sb_repair - repair a damaged superblock
|
|
Packit |
6ef888 |
* Assumes: device is open.
|
|
Packit |
6ef888 |
* The biggest RG size is 2GB
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int sb_repair(struct gfs2_sbd *sdp)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
uint64_t half;
|
|
Packit |
6ef888 |
uint32_t known_bsize = 0;
|
|
Packit |
6ef888 |
int error = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
memset(&fix_md, 0, sizeof(fix_md));
|
|
Packit |
6ef888 |
/* Step 1 - First we need to determine the correct block size. */
|
|
Packit |
6ef888 |
sdp->bsize = GFS2_DEFAULT_BSIZE;
|
|
Packit |
6ef888 |
log_warn(_("Gathering information to repair the gfs2 superblock. "
|
|
Packit |
6ef888 |
"This may take some time.\n"));
|
|
Packit |
6ef888 |
error = find_rgs_for_bsize(sdp, (GFS2_SB_ADDR * GFS2_BASIC_BLOCK) /
|
|
Packit |
6ef888 |
GFS2_DEFAULT_BSIZE, &known_bsize);
|
|
Packit |
6ef888 |
if (error)
|
|
Packit |
6ef888 |
return error;
|
|
Packit |
6ef888 |
if (!known_bsize) {
|
|
Packit |
6ef888 |
log_warn(_("Block size not apparent; checking elsewhere.\n"));
|
|
Packit |
6ef888 |
/* First, figure out the device size. We need that so we can
|
|
Packit |
6ef888 |
find a suitable start point to determine what's what. */
|
|
Packit |
6ef888 |
half = sdp->dinfo.size / 2; /* in bytes */
|
|
Packit |
6ef888 |
half /= sdp->bsize;
|
|
Packit |
6ef888 |
/* Start looking halfway through the device for gfs2
|
|
Packit |
6ef888 |
structures. If there aren't any at all, forget it. */
|
|
Packit |
6ef888 |
error = find_rgs_for_bsize(sdp, half, &known_bsize);
|
|
Packit |
6ef888 |
if (error)
|
|
Packit |
6ef888 |
return error;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (!known_bsize) {
|
|
Packit |
6ef888 |
log_err(_("Unable to determine the block size; this "
|
|
Packit |
6ef888 |
"does not look like a gfs2 file system.\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* Step 2 - look for the sytem dinodes */
|
|
Packit |
6ef888 |
error = peruse_metadata(sdp, (GFS2_SB_ADDR * GFS2_BASIC_BLOCK) /
|
|
Packit |
6ef888 |
GFS2_DEFAULT_BSIZE);
|
|
Packit |
6ef888 |
if (error)
|
|
Packit |
6ef888 |
return error;
|
|
Packit |
6ef888 |
if (!sdp->sd_sb.sb_master_dir.no_addr) {
|
|
Packit |
6ef888 |
log_err(_("Unable to locate the system master directory.\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (!sdp->sd_sb.sb_root_dir.no_addr) {
|
|
Packit |
6ef888 |
struct gfs2_inum inum;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_err(_("Unable to locate the root directory.\n"));
|
|
Packit |
6ef888 |
if (possible_root == HIGHEST_BLOCK) {
|
|
Packit |
6ef888 |
/* Take advantage of the fact that mkfs.gfs2
|
|
Packit |
6ef888 |
creates master immediately after root. */
|
|
Packit |
6ef888 |
log_err(_("Can't find any dinodes that might "
|
|
Packit |
6ef888 |
"be the root; using master - 1.\n"));
|
|
Packit |
6ef888 |
possible_root = sdp->sd_sb.sb_master_dir.no_addr - 1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_err(_("Found a possible root at: 0x%llx\n"),
|
|
Packit |
6ef888 |
(unsigned long long)possible_root);
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_root_dir.no_addr = possible_root;
|
|
Packit |
6ef888 |
sdp->md.rooti = lgfs2_inode_read(sdp, possible_root);
|
|
Packit |
6ef888 |
if (!sdp->md.rooti ||
|
|
Packit |
6ef888 |
sdp->md.rooti->i_di.di_header.mh_magic != GFS2_MAGIC) {
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh = NULL;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_err(_("The root dinode block is destroyed.\n"));
|
|
Packit |
6ef888 |
log_err(_("At this point I recommend "
|
|
Packit |
6ef888 |
"reinitializing it.\n"
|
|
Packit |
6ef888 |
"Hopefully everything will later "
|
|
Packit |
6ef888 |
"be put into lost+found.\n"));
|
|
Packit |
6ef888 |
if (!query(_("Okay to reinitialize the root "
|
|
Packit |
6ef888 |
"dinode? (y/n)"))) {
|
|
Packit |
6ef888 |
log_err(_("The root dinode was not "
|
|
Packit |
6ef888 |
"reinitialized; aborting.\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
inum.no_formal_ino = 1;
|
|
Packit |
6ef888 |
inum.no_addr = possible_root;
|
|
Packit |
6ef888 |
error = init_dinode(sdp, &bh, &inum, S_IFDIR | 0755, 0, &inum);
|
|
Packit |
6ef888 |
if (error != 0)
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* Step 3 - Rebuild the lock protocol and file system table name */
|
|
Packit |
6ef888 |
if (query(_("Okay to fix the GFS2 superblock? (y/n)"))) {
|
|
Packit |
6ef888 |
struct gfs2_sb sb;
|
|
Packit |
6ef888 |
log_info(_("Found system master directory at: 0x%llx\n"),
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_master_dir.no_addr);
|
|
Packit |
6ef888 |
sdp->master_dir = lgfs2_inode_read(sdp,
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_master_dir.no_addr);
|
|
Packit |
6ef888 |
if (sdp->master_dir == NULL) {
|
|
Packit |
6ef888 |
log_crit(_("Error reading master inode: %s\n"), strerror(errno));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
sdp->master_dir->i_di.di_num.no_addr =
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_master_dir.no_addr;
|
|
Packit |
6ef888 |
log_info(_("Found the root directory at: 0x%llx\n"),
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_root_dir.no_addr);
|
|
Packit |
6ef888 |
sdp->md.rooti = lgfs2_inode_read(sdp,
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_root_dir.no_addr);
|
|
Packit |
6ef888 |
if (sdp->md.rooti == NULL) {
|
|
Packit |
6ef888 |
log_crit(_("Error reading root inode: %s\n"), strerror(errno));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
lgfs2_sb_init(&sb, sdp->bsize);
|
|
Packit |
6ef888 |
strcpy(sb.sb_lockproto, GFS2_DEFAULT_LOCKPROTO);
|
|
Packit |
6ef888 |
strcpy(sb.sb_locktable, "unknown");
|
|
Packit |
6ef888 |
sb.sb_master_dir = sdp->master_dir->i_di.di_num;
|
|
Packit |
6ef888 |
sb.sb_root_dir = sdp->md.rooti->i_di.di_num;
|
|
Packit |
6ef888 |
lgfs2_sb_write(&sb, sdp->device_fd, sdp->bsize);
|
|
Packit |
6ef888 |
inode_put(&sdp->md.rooti);
|
|
Packit |
6ef888 |
inode_put(&sdp->master_dir);
|
|
Packit |
6ef888 |
sb_fixed = 1;
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
log_crit(_("GFS2 superblock not fixed; fsck cannot proceed "
|
|
Packit |
6ef888 |
"without a valid superblock.\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* fill_super_block
|
|
Packit |
6ef888 |
* @sdp:
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Returns: 0 on success, -1 on failure
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int fill_super_block(struct gfs2_sbd *sdp)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
int ret;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
sync();
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/********************************************************************
|
|
Packit |
6ef888 |
***************** First, initialize all lists **********************
|
|
Packit |
6ef888 |
********************************************************************/
|
|
Packit |
6ef888 |
log_info( _("Initializing lists...\n"));
|
|
Packit |
6ef888 |
sdp->rgtree.osi_node = NULL;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/********************************************************************
|
|
Packit |
6ef888 |
************ next, read in on-disk SB and set constants **********
|
|
Packit |
6ef888 |
********************************************************************/
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_bsize = GFS2_DEFAULT_BSIZE;
|
|
Packit |
6ef888 |
sdp->bsize = sdp->sd_sb.sb_bsize;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sizeof(struct gfs2_sb) > sdp->sd_sb.sb_bsize){
|
|
Packit |
6ef888 |
log_crit( _("GFS superblock is larger than the blocksize!\n"));
|
|
Packit |
6ef888 |
log_debug("sizeof(struct gfs2_sb) > sdp->sd_sb.sb_bsize\n");
|
|
Packit Service |
5478d6 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (compute_constants(sdp)) {
|
|
Packit |
6ef888 |
log_crit("%s\n", _("Failed to compute file system constants"));
|
|
Packit Service |
5478d6 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
ret = read_sb(sdp);
|
|
Packit |
6ef888 |
if (ret < 0) {
|
|
Packit |
6ef888 |
if (sb_repair(sdp) != 0)
|
|
Packit |
6ef888 |
return -1; /* unrepairable, so exit */
|
|
Packit |
6ef888 |
/* Now that we've tried to repair it, re-read it. */
|
|
Packit |
6ef888 |
ret = read_sb(sdp);
|
|
Packit |
6ef888 |
if (ret < 0)
|
|
Packit Service |
5478d6 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (sdp->gfs1)
|
|
Packit |
6ef888 |
sbd1 = (struct gfs_sb *)&sdp->sd_sb;
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
static void gfs_log_header_out(struct gfs_log_header *head, char *buf)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct gfs_log_header *str = (struct gfs_log_header *) buf;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
str->lh_header.mh_magic = cpu_to_be32(head->lh_header.mh_magic);
|
|
Packit |
6ef888 |
str->lh_header.mh_type = cpu_to_be32(head->lh_header.mh_type);
|
|
Packit |
6ef888 |
str->lh_header.mh_format = cpu_to_be32(head->lh_header.mh_format);
|
|
Packit |
6ef888 |
str->lh_header.__pad0 = cpu_to_be32(head->lh_header.__pad0);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
str->lh_flags = cpu_to_be32(head->lh_flags);
|
|
Packit |
6ef888 |
str->lh_pad = cpu_to_be32(head->lh_pad);
|
|
Packit |
6ef888 |
str->lh_first = cpu_to_be64(head->lh_first);
|
|
Packit |
6ef888 |
str->lh_sequence = cpu_to_be64(head->lh_sequence);
|
|
Packit |
6ef888 |
str->lh_tail = cpu_to_be64(head->lh_tail);
|
|
Packit |
6ef888 |
str->lh_last_dump = cpu_to_be64(head->lh_last_dump);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* reconstruct_single_journal - write a fresh GFS1 journal
|
|
Packit |
6ef888 |
* @sdp: superblock
|
|
Packit |
6ef888 |
* @jnum: journal number
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* This function will write a fresh journal over the top of
|
|
Packit |
6ef888 |
* the previous journal. All journal information is lost. This
|
|
Packit |
6ef888 |
* process is basically stolen from write_journals() in the mkfs code.
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Returns: -1 on error, 0 otherwise
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int reconstruct_single_journal(struct gfs2_sbd *sdp, int jnum,
|
|
Packit |
6ef888 |
uint32_t ji_nsegment)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct gfs_log_header lh;
|
|
Packit |
6ef888 |
uint32_t seg, sequence;
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *bh;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
srandom(time(NULL));
|
|
Packit |
6ef888 |
sequence = ji_nsegment / (RAND_MAX + 1.0) * random();
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_info(_("Clearing journal %d\n"), jnum);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
for (seg = 0; seg < ji_nsegment; seg++){
|
|
Packit |
6ef888 |
memset(&lh, 0, sizeof(struct gfs_log_header));
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
lh.lh_header.mh_magic = GFS2_MAGIC;
|
|
Packit |
6ef888 |
lh.lh_header.mh_type = GFS2_METATYPE_LH;
|
|
Packit |
6ef888 |
lh.lh_header.mh_format = GFS2_FORMAT_LH;
|
|
Packit |
6ef888 |
lh.lh_header.__pad0 = 0x101674; /* mh_generation */
|
|
Packit |
6ef888 |
lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT;
|
|
Packit |
6ef888 |
lh.lh_first = sdp->md.journal[jnum]->i_di.di_num.no_addr +
|
|
Packit |
6ef888 |
(seg * sbd1->sb_seg_size);
|
|
Packit |
6ef888 |
lh.lh_sequence = sequence;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
bh = bget(sdp, lh.lh_first * sdp->bsize);
|
|
Packit |
6ef888 |
memset(bh->b_data, 0, sdp->bsize);
|
|
Packit |
6ef888 |
gfs_log_header_out(&lh, bh->b_data);
|
|
Packit |
6ef888 |
gfs_log_header_out(&lh, bh->b_data + GFS2_BASIC_BLOCK -
|
|
Packit |
6ef888 |
sizeof(struct gfs_log_header));
|
|
Packit |
6ef888 |
brelse(bh);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (++sequence == ji_nsegment)
|
|
Packit |
6ef888 |
sequence = 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
static int reset_journal_seg_size(unsigned int jsize, unsigned int nsegs,
|
|
Packit |
6ef888 |
unsigned int bsize)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
unsigned int seg_size = jsize / (nsegs * bsize);
|
|
Packit |
6ef888 |
if (!seg_size)
|
|
Packit |
6ef888 |
seg_size = 16; /* The default with 128MB journal and 4K bsize */
|
|
Packit |
6ef888 |
if (seg_size != sbd1->sb_seg_size) {
|
|
Packit |
6ef888 |
sbd1->sb_seg_size = seg_size;
|
|
Packit |
6ef888 |
if (!query(_("Computed correct journal segment size to %u."
|
|
Packit |
6ef888 |
" Reset it? (y/n) "), seg_size)) {
|
|
Packit |
6ef888 |
log_crit(_("Error: Cannot proceed without a valid journal"
|
|
Packit |
6ef888 |
" segment size value.\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_err(_("Resetting journal segment size to %u\n"), sbd1->sb_seg_size);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
static int correct_journal_seg_size(struct gfs2_sbd *sdp)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
int count;
|
|
Packit |
6ef888 |
struct gfs_jindex ji_0, ji_1;
|
|
Packit |
6ef888 |
char buf[sizeof(struct gfs_jindex)];
|
|
Packit |
6ef888 |
unsigned int jsize = GFS2_DEFAULT_JSIZE * 1024 * 1024;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
count = gfs2_readi(sdp->md.jiinode, buf, 0, sizeof(struct gfs_jindex));
|
|
Packit |
6ef888 |
if (count != sizeof(struct gfs_jindex)) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d reading system journal index inode. "
|
|
Packit |
6ef888 |
"Aborting\n"), count);
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
gfs_jindex_in(&ji_0, buf);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sdp->md.journals == 1) {
|
|
Packit |
6ef888 |
if (sbd1->sb_seg_size == 0) {
|
|
Packit |
6ef888 |
if (!query(_("The gfs2 journal segment size is 0 and a"
|
|
Packit |
6ef888 |
" correct value cannot be determined in a"
|
|
Packit |
6ef888 |
" single-journal filesystem.\n"
|
|
Packit |
6ef888 |
"Continue with default? (y/n) "))) {
|
|
Packit |
6ef888 |
log_crit(_("Error: Cannot proceed without a valid"
|
|
Packit |
6ef888 |
" sb_seg_size value.\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
goto out;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* Don't mess with sb_seg_size because we don't know what
|
|
Packit |
6ef888 |
* it needs to be
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
count = gfs2_readi(sdp->md.jiinode, buf, sizeof(struct gfs_jindex),
|
|
Packit |
6ef888 |
sizeof(struct gfs_jindex));
|
|
Packit |
6ef888 |
if (count != sizeof(struct gfs_jindex)) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d reading system journal index inode. "
|
|
Packit |
6ef888 |
"Aborting\n"), count);
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
gfs_jindex_in(&ji_1, buf);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
jsize = (ji_1.ji_addr - ji_0.ji_addr) * sbd1->sb_bsize;
|
|
Packit |
6ef888 |
out:
|
|
Packit |
6ef888 |
return reset_journal_seg_size(jsize, ji_0.ji_nsegment, sbd1->sb_bsize);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/*
|
|
Packit |
6ef888 |
* reconstruct_journals - write fresh journals for GFS1 only
|
|
Packit |
6ef888 |
* sdp: the super block
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Returns: 0 on success, -1 on failure
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int reconstruct_journals(struct gfs2_sbd *sdp)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
int i, count;
|
|
Packit |
6ef888 |
struct gfs_jindex ji;
|
|
Packit |
6ef888 |
char buf[sizeof(struct gfs_jindex)];
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* Ensure that sb_seg_size is valid */
|
|
Packit |
6ef888 |
if (correct_journal_seg_size(sdp)) {
|
|
Packit |
6ef888 |
log_crit(_("Failed to set correct journal segment size. Cannot continue\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_err(_("Clearing GFS journals (this may take a while)\n"));
|
|
Packit |
6ef888 |
for (i = 0; i < sdp->md.journals; i++) {
|
|
Packit |
6ef888 |
count = gfs2_readi(sdp->md.jiinode, buf,
|
|
Packit |
6ef888 |
i * sizeof(struct gfs_jindex),
|
|
Packit |
6ef888 |
sizeof(struct gfs_jindex));
|
|
Packit |
6ef888 |
if (count != sizeof(struct gfs_jindex))
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
gfs_jindex_in(&ji, buf);
|
|
Packit |
6ef888 |
if ((i % 2) == 0)
|
|
Packit |
6ef888 |
log_err(".");
|
|
Packit |
6ef888 |
if (reconstruct_single_journal(sdp, i, ji.ji_nsegment))
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_err(_("\nJournals cleared.\n"));
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* init_rindex - read in the rindex file
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int init_rindex(struct gfs2_sbd *sdp)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
int err;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sdp->gfs1)
|
|
Packit |
6ef888 |
sdp->md.riinode = lgfs2_inode_read(sdp, sbd1->sb_rindex_di.no_addr);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
gfs2_lookupi(sdp->master_dir, "rindex", 6, &sdp->md.riinode);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sdp->md.riinode)
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (!query( _("The gfs2 system rindex inode is missing. "
|
|
Packit |
6ef888 |
"Okay to rebuild it? (y/n) "))) {
|
|
Packit |
6ef888 |
log_crit(_("Error: Cannot proceed without a valid rindex.\n"));
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if ((err = build_rindex(sdp))) {
|
|
Packit |
6ef888 |
log_crit(_("Error %d rebuilding rindex\n"), err);
|
|
Packit |
6ef888 |
return -1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* initialize - initialize superblock pointer
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
int initialize(struct gfs2_sbd *sdp, int force_check, int preen,
|
|
Packit |
6ef888 |
int *all_clean)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
int clean_journals = 0, open_flag;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
*all_clean = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (opts.no)
|
|
Packit |
6ef888 |
open_flag = O_RDONLY;
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
open_flag = O_RDWR | O_EXCL;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
sdp->device_fd = open(opts.device, open_flag);
|
|
Packit |
6ef888 |
if (sdp->device_fd < 0) {
|
|
Packit |
6ef888 |
struct mntent *mnt;
|
|
Packit |
6ef888 |
if (open_flag == O_RDONLY || errno != EBUSY) {
|
|
Packit |
6ef888 |
log_crit( _("Unable to open device: %s\n"),
|
|
Packit |
6ef888 |
opts.device);
|
|
Packit |
6ef888 |
return FSCK_USAGE;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* We can't open it EXCL. It may be already open rw (in which
|
|
Packit |
6ef888 |
case we want to deny them access) or it may be mounted as
|
|
Packit |
6ef888 |
the root file system at boot time (in which case we need to
|
|
Packit |
6ef888 |
allow it.)
|
|
Packit |
6ef888 |
If the device is busy, but not because it's mounted, fail.
|
|
Packit |
6ef888 |
This protects against cases where the file system is LVM
|
|
Packit |
6ef888 |
and perhaps mounted on a different node.
|
|
Packit |
6ef888 |
Try opening without O_EXCL. */
|
|
Packit |
6ef888 |
sdp->device_fd = lgfs2_open_mnt_dev(opts.device, O_RDWR, &mnt;;
|
|
Packit |
6ef888 |
if (sdp->device_fd < 0)
|
|
Packit |
6ef888 |
goto mount_fail;
|
|
Packit |
6ef888 |
/* If the device is mounted, but not mounted RO, fail. This
|
|
Packit |
6ef888 |
protects them against cases where the file system is
|
|
Packit |
6ef888 |
mounted RW, but still allows us to check our own root
|
|
Packit |
6ef888 |
file system. */
|
|
Packit |
6ef888 |
if (!hasmntopt(mnt, MNTOPT_RO))
|
|
Packit |
6ef888 |
goto close_fail;
|
|
Packit |
6ef888 |
/* The device is mounted RO, so it's likely our own root
|
|
Packit |
6ef888 |
file system. We can only do so much to protect the users
|
|
Packit |
6ef888 |
from themselves. */
|
|
Packit |
6ef888 |
was_mounted_ro = 1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (lgfs2_get_dev_info(sdp->device_fd, &sdp->dinfo)) {
|
|
Packit |
6ef888 |
perror(opts.device);
|
|
Packit |
6ef888 |
return FSCK_ERROR;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* read in sb from disk */
|
|
Packit Service |
5478d6 |
if (fill_super_block(sdp))
|
|
Packit Service |
5478d6 |
return FSCK_ERROR;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* Change lock protocol to be fsck_* instead of lock_* */
|
|
Packit |
6ef888 |
if (!opts.no && preen_is_safe(sdp, preen, force_check)) {
|
|
Packit |
6ef888 |
if (block_mounters(sdp, 1)) {
|
|
Packit |
6ef888 |
log_err( _("Unable to block other mounters\n"));
|
|
Packit |
6ef888 |
return FSCK_USAGE;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* Get master dinode */
|
|
Packit |
6ef888 |
if (sdp->gfs1)
|
|
Packit |
6ef888 |
sdp->master_dir = NULL;
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
sdp->master_dir = lgfs2_inode_read(sdp,
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_master_dir.no_addr);
|
|
Packit |
6ef888 |
if (!sdp->gfs1 &&
|
|
Packit |
6ef888 |
(sdp->master_dir->i_di.di_header.mh_magic != GFS2_MAGIC ||
|
|
Packit |
6ef888 |
sdp->master_dir->i_di.di_header.mh_type != GFS2_METATYPE_DI ||
|
|
Packit |
6ef888 |
!sdp->master_dir->i_di.di_size)) {
|
|
Packit |
6ef888 |
inode_put(&sdp->master_dir);
|
|
Packit |
6ef888 |
rebuild_master(sdp);
|
|
Packit |
6ef888 |
sdp->master_dir = lgfs2_inode_read(sdp,
|
|
Packit |
6ef888 |
sdp->sd_sb.sb_master_dir.no_addr);
|
|
Packit |
6ef888 |
if (sdp->master_dir == NULL) {
|
|
Packit |
6ef888 |
log_crit(_("Error reading master directory: %s\n"), strerror(errno));
|
|
Packit |
6ef888 |
return FSCK_ERROR;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* Look up the "per_node" inode. If there are journals missing, we
|
|
Packit |
6ef888 |
need to figure out what's missing from per_node. And we need all
|
|
Packit |
6ef888 |
our journals to be there before we can replay them. */
|
|
Packit |
6ef888 |
if (!sdp->gfs1)
|
|
Packit |
6ef888 |
lookup_per_node(sdp, 0);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* We need rindex first in case jindex is missing and needs to read
|
|
Packit |
6ef888 |
in the rgrps before rebuilding it. However, note that if the rindex
|
|
Packit |
6ef888 |
is damaged, we need the journals to repair it. That's because the
|
|
Packit |
6ef888 |
journals likely contain rgrps and bitmaps, which we need to ignore
|
|
Packit |
6ef888 |
when we're trying to find the rgrps. */
|
|
Packit |
6ef888 |
if (init_rindex(sdp))
|
|
Packit |
6ef888 |
return FSCK_ERROR;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (fetch_rgrps(sdp))
|
|
Packit |
6ef888 |
return FSCK_ERROR;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* We need to read in jindex in order to replay the journals. If
|
|
Packit |
6ef888 |
there's an error, we may proceed and let init_system_inodes
|
|
Packit |
6ef888 |
try to rebuild it. */
|
|
Packit |
6ef888 |
if (init_jindex(sdp, 1) == 0) {
|
|
Packit |
6ef888 |
/* If GFS, rebuild the journals. If GFS2, replay them. We don't
|
|
Packit |
6ef888 |
have the smarts to replay GFS1 journals (neither did
|
|
Packit |
6ef888 |
gfs_fsck). */
|
|
Packit |
6ef888 |
if (sdp->gfs1) {
|
|
Packit |
6ef888 |
if (reconstruct_journals(sdp))
|
|
Packit |
6ef888 |
return FSCK_ERROR;
|
|
Packit |
6ef888 |
} else if (replay_journals(sdp, preen, force_check,
|
|
Packit |
6ef888 |
&clean_journals)) {
|
|
Packit |
6ef888 |
if (!opts.no && preen_is_safe(sdp, preen, force_check))
|
|
Packit |
6ef888 |
block_mounters(sdp, 0);
|
|
Packit |
6ef888 |
stack;
|
|
Packit |
6ef888 |
return FSCK_ERROR;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (sdp->md.journals == clean_journals)
|
|
Packit |
6ef888 |
*all_clean = 1;
|
|
Packit |
6ef888 |
else if (force_check || !preen)
|
|
Packit |
6ef888 |
log_notice( _("\nJournal recovery complete.\n"));
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (!force_check && *all_clean && preen)
|
|
Packit |
6ef888 |
return FSCK_OK;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (init_system_inodes(sdp))
|
|
Packit |
6ef888 |
return FSCK_ERROR;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
return FSCK_OK;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
close_fail:
|
|
Packit |
6ef888 |
close(sdp->device_fd);
|
|
Packit |
6ef888 |
mount_fail:
|
|
Packit |
6ef888 |
log_crit( _("Device %s is busy.\n"), opts.device);
|
|
Packit |
6ef888 |
return FSCK_USAGE;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
void destroy(struct gfs2_sbd *sdp)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
if (!opts.no) {
|
|
Packit |
6ef888 |
if (block_mounters(sdp, 0)) {
|
|
Packit |
6ef888 |
log_warn( _("Unable to unblock other mounters - manual intervention required\n"));
|
|
Packit |
6ef888 |
log_warn( _("Use 'gfs2_tool sb <device> proto' to fix\n"));
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_info( _("Syncing the device.\n"));
|
|
Packit |
6ef888 |
fsync(sdp->device_fd);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
empty_super_block(sdp);
|
|
Packit |
6ef888 |
close(sdp->device_fd);
|
|
Packit |
6ef888 |
if (was_mounted_ro && errors_corrected) {
|
|
Packit |
6ef888 |
sdp->device_fd = open("/proc/sys/vm/drop_caches", O_WRONLY);
|
|
Packit |
6ef888 |
if (sdp->device_fd >= 0) {
|
|
Packit |
6ef888 |
if (write(sdp->device_fd, "2", 1) == 2) {
|
|
Packit |
6ef888 |
close(sdp->device_fd);
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
close(sdp->device_fd);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_warn(_("fsck.gfs2: Could not flush caches (non-fatal).\n"));
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|