|
Packit Service |
360c39 |
/* pass1 checks inodes for format & type, duplicate blocks, & incorrect
|
|
Packit Service |
360c39 |
* block count.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* It builds up tables that contains the state of each block (free,
|
|
Packit Service |
360c39 |
* block in use, metadata type, etc), as well as bad blocks and
|
|
Packit Service |
360c39 |
* duplicate blocks. (See block_list.[ch] for more info)
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include <stdio.h>
|
|
Packit Service |
360c39 |
#include <stdlib.h>
|
|
Packit Service |
360c39 |
#include <sys/time.h>
|
|
Packit Service |
360c39 |
#include <sys/stat.h>
|
|
Packit Service |
360c39 |
#include <unistd.h>
|
|
Packit Service |
360c39 |
#include <string.h>
|
|
Packit Service |
360c39 |
#include <time.h>
|
|
Packit Service |
360c39 |
#include <fcntl.h>
|
|
Packit Service |
360c39 |
#include <sys/ioctl.h>
|
|
Packit Service |
360c39 |
#include <inttypes.h>
|
|
Packit Service |
360c39 |
#include <libintl.h>
|
|
Packit Service |
360c39 |
#define _(String) gettext(String)
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include <logging.h>
|
|
Packit Service |
360c39 |
#include "libgfs2.h"
|
|
Packit Service |
360c39 |
#include "fsck.h"
|
|
Packit Service |
360c39 |
#include "inode_hash.h"
|
|
Packit Service |
360c39 |
#include "util.h"
|
|
Packit Service |
360c39 |
#include "link.h"
|
|
Packit Service |
360c39 |
#include "metawalk.h"
|
|
Packit Service |
360c39 |
#include "fs_recovery.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct special_blocks gfs1_rindex_blks;
|
|
Packit Service |
360c39 |
struct gfs2_bmap *bl = NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct block_count {
|
|
Packit Service |
360c39 |
uint64_t indir_count;
|
|
Packit Service |
360c39 |
uint64_t data_count;
|
|
Packit Service |
360c39 |
uint64_t ea_count;
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private);
|
|
Packit Service |
360c39 |
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, int h, int *is_valid,
|
|
Packit Service |
360c39 |
int *was_duplicate, void *private);
|
|
Packit Service |
360c39 |
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
int h, void *private);
|
|
Packit Service |
360c39 |
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
|
|
Packit Service |
360c39 |
uint64_t block, void *private,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh, uint64_t *ptr);
|
|
Packit Service |
360c39 |
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
void *private);
|
|
Packit Service |
360c39 |
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
|
|
Packit Service |
360c39 |
uint64_t parent, struct gfs2_buffer_head **bh,
|
|
Packit Service |
360c39 |
void *private);
|
|
Packit Service |
360c39 |
static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
uint64_t parent, struct gfs2_buffer_head **bh,
|
|
Packit Service |
360c39 |
void *private);
|
|
Packit Service |
360c39 |
static int check_eattr_entries(struct gfs2_inode *ip,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *leaf_bh,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *ea_hdr,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *ea_hdr_prev,
|
|
Packit Service |
360c39 |
void *private);
|
|
Packit Service |
360c39 |
static int check_extended_leaf_eattr(struct gfs2_inode *ip, int i,
|
|
Packit Service |
360c39 |
uint64_t *data_ptr,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *leaf_bh,
|
|
Packit Service |
360c39 |
uint32_t tot_ealen,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *ea_hdr,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *ea_hdr_prev,
|
|
Packit Service |
360c39 |
void *private);
|
|
Packit Service |
360c39 |
static int finish_eattr_indir(struct gfs2_inode *ip, int leaf_pointers,
|
|
Packit Service |
360c39 |
int leaf_pointer_errors, void *private);
|
|
Packit Service |
360c39 |
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, int h,
|
|
Packit Service |
360c39 |
int *is_valid, int *was_duplicate,
|
|
Packit Service |
360c39 |
void *private);
|
|
Packit Service |
360c39 |
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
void *private);
|
|
Packit Service |
360c39 |
static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
|
|
Packit Service |
360c39 |
uint64_t block, void *private,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh, uint64_t *ptr);
|
|
Packit Service |
360c39 |
static int invalidate_eattr_indir(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
uint64_t parent,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh,
|
|
Packit Service |
360c39 |
void *private);
|
|
Packit Service |
360c39 |
static int invalidate_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
uint64_t parent, struct gfs2_buffer_head **bh,
|
|
Packit Service |
360c39 |
void *private);
|
|
Packit Service |
360c39 |
static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip);
|
|
Packit Service |
360c39 |
static int delete_block(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, const char *btype,
|
|
Packit Service |
360c39 |
void *private);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int gfs2_blockmap_set(struct gfs2_bmap *bmap, uint64_t bblock, int mark)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
static unsigned char *byte;
|
|
Packit Service |
360c39 |
static uint64_t b;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!bmap)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
if (bblock > bmap->size)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
byte = bmap->map + BLOCKMAP_SIZE2(bblock);
|
|
Packit Service |
360c39 |
b = BLOCKMAP_BYTE_OFFSET2(bblock);
|
|
Packit Service |
360c39 |
*byte &= ~(BLOCKMAP_MASK2 << b);
|
|
Packit Service |
360c39 |
*byte |= (mark & BLOCKMAP_MASK2) << b;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* _fsck_blockmap_set - Mark a block in the 4-bit blockmap and the 2-bit
|
|
Packit Service |
360c39 |
* bitmap, and adjust free space accordingly.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
|
|
Packit Service |
360c39 |
const char *btype, int mark, int error_on_dinode,
|
|
Packit Service |
360c39 |
const char *caller, int fline)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int error = _fsck_bitmap_set(ip, bblock, btype, mark, error_on_dinode,
|
|
Packit Service |
360c39 |
caller, fline);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return gfs2_blockmap_set(bl, bblock, mark);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#define fsck_blockmap_set(ip, b, bt, m) \
|
|
Packit Service |
360c39 |
_fsck_blockmap_set(ip, b, bt, m, 0, __FUNCTION__, __LINE__)
|
|
Packit Service |
360c39 |
#define fsck_blkmap_set_noino(ip, b, bt, m) \
|
|
Packit Service |
360c39 |
_fsck_blockmap_set(ip, b, bt, m, 1, __FUNCTION__, __LINE__)
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* delete_block - delete a block associated with an inode
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int delete_block(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, const char *btype,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if (valid_block_ip(ip, block)) {
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, block, btype, GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* This is a pass1-specific leaf repair. Since we are not allowed to do
|
|
Packit Service |
360c39 |
* block allocations, we do what we can. */
|
|
Packit Service |
360c39 |
static int pass1_repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no,
|
|
Packit Service |
360c39 |
int lindex, int ref_count, const char *msg)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t *cpyptr;
|
|
Packit Service |
360c39 |
char *padbuf;
|
|
Packit Service |
360c39 |
int pad_size, i;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_err( _("Directory Inode %llu (0x%llx) points to leaf %llu"
|
|
Packit Service |
360c39 |
" (0x%llx) %s.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)*leaf_no,
|
|
Packit Service |
360c39 |
(unsigned long long)*leaf_no, msg);
|
|
Packit Service |
360c39 |
if (!query( _("Attempt to patch around it? (y/n) "))) {
|
|
Packit Service |
360c39 |
log_err( _("Bad leaf left in place.\n"));
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
padbuf = malloc(ref_count * sizeof(uint64_t));
|
|
Packit Service |
360c39 |
cpyptr = (uint64_t *)padbuf;
|
|
Packit Service |
360c39 |
for (i = 0; i < ref_count; i++) {
|
|
Packit Service |
360c39 |
*cpyptr = 0;
|
|
Packit Service |
360c39 |
cpyptr++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
pad_size = ref_count * sizeof(uint64_t);
|
|
Packit Service |
360c39 |
log_err(_("Writing zeros to the hash table of directory %lld "
|
|
Packit Service |
360c39 |
"(0x%llx) at index: 0x%x for 0x%x pointers.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr, lindex,
|
|
Packit Service |
360c39 |
ref_count);
|
|
Packit Service |
360c39 |
if (ip->i_sbd->gfs1)
|
|
Packit Service |
360c39 |
gfs1_writei(ip, padbuf, lindex * sizeof(uint64_t), pad_size);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
gfs2_writei(ip, padbuf, lindex * sizeof(uint64_t), pad_size);
|
|
Packit Service |
360c39 |
free(padbuf);
|
|
Packit Service |
360c39 |
log_err( _("Directory Inode %llu (0x%llx) patched.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
out:
|
|
Packit Service |
360c39 |
*leaf_no = 0;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct metawalk_fxns pass1_fxns = {
|
|
Packit Service |
360c39 |
.private = NULL,
|
|
Packit Service |
360c39 |
.check_leaf = p1check_leaf,
|
|
Packit Service |
360c39 |
.check_metalist = check_metalist,
|
|
Packit Service |
360c39 |
.check_data = check_data,
|
|
Packit Service |
360c39 |
.check_eattr_indir = check_eattr_indir,
|
|
Packit Service |
360c39 |
.check_eattr_leaf = check_eattr_leaf,
|
|
Packit Service |
360c39 |
.check_dentry = NULL,
|
|
Packit Service |
360c39 |
.check_eattr_entry = check_eattr_entries,
|
|
Packit Service |
360c39 |
.check_eattr_extentry = check_extended_leaf_eattr,
|
|
Packit Service |
360c39 |
.big_file_msg = big_file_comfort,
|
|
Packit Service |
360c39 |
.repair_leaf = pass1_repair_leaf,
|
|
Packit Service |
360c39 |
.undo_check_meta = undo_check_metalist,
|
|
Packit Service |
360c39 |
.undo_check_data = undo_check_data,
|
|
Packit Service |
360c39 |
.delete_block = delete_block,
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct metawalk_fxns invalidate_fxns = {
|
|
Packit Service |
360c39 |
.private = NULL,
|
|
Packit Service |
360c39 |
.check_metalist = invalidate_metadata,
|
|
Packit Service |
360c39 |
.check_data = invalidate_data,
|
|
Packit Service |
360c39 |
.check_leaf = invalidate_leaf,
|
|
Packit Service |
360c39 |
.check_eattr_indir = invalidate_eattr_indir,
|
|
Packit Service |
360c39 |
.check_eattr_leaf = invalidate_eattr_leaf,
|
|
Packit Service |
360c39 |
.delete_block = delete_block,
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* resuscitate_metalist - make sure a system directory entry's metadata blocks
|
|
Packit Service |
360c39 |
* are marked "in use" in the bitmap.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* This function makes sure metadata blocks for system and root directories are
|
|
Packit Service |
360c39 |
* marked "in use" by the bitmap. You don't want root's indirect blocks
|
|
Packit Service |
360c39 |
* deleted, do you? Or worse, reused for lost+found.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, int h,
|
|
Packit Service |
360c39 |
int *is_valid, int *was_duplicate,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct block_count *bc = (struct block_count *)private;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*is_valid = 1;
|
|
Packit Service |
360c39 |
*was_duplicate = 0;
|
|
Packit Service |
360c39 |
*bh = NULL;
|
|
Packit Service |
360c39 |
if (!valid_block_ip(ip, block)){ /* blk outside of FS */
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
_("itself"), GFS2_BLKST_UNLINKED);
|
|
Packit Service |
360c39 |
log_err( _("Bad indirect block pointer (invalid or out of "
|
|
Packit Service |
360c39 |
"range) found in system inode %lld (0x%llx).\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
*is_valid = 0;
|
|
Packit Service |
360c39 |
return meta_is_good;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (fsck_system_inode(ip->i_sbd, block))
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, block, _("system file"),
|
|
Packit Service |
360c39 |
ip->i_sbd->gfs1 ?
|
|
Packit Service |
360c39 |
GFS2_BLKST_DINODE : GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
check_n_fix_bitmap(ip->i_sbd, ip->i_rgd, block, 0,
|
|
Packit Service |
360c39 |
ip->i_sbd->gfs1 ?
|
|
Packit Service |
360c39 |
GFS2_BLKST_DINODE : GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
bc->indir_count++;
|
|
Packit Service |
360c39 |
return meta_is_good;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* resuscitate_dentry - make sure a system directory entry is alive
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* This function makes sure directory entries in system directories are
|
|
Packit Service |
360c39 |
* kept alive. You don't want journal0 deleted from jindex, do you?
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int resuscitate_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
|
|
Packit Service |
360c39 |
struct gfs2_dirent *prev_de,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh, char *filename,
|
|
Packit Service |
360c39 |
uint32_t *count, int *lindex, void *priv)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
struct gfs2_dirent dentry, *de;
|
|
Packit Service |
360c39 |
char tmp_name[PATH_MAX];
|
|
Packit Service |
360c39 |
uint64_t block;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
memset(&dentry, 0, sizeof(struct gfs2_dirent));
|
|
Packit Service |
360c39 |
gfs2_dirent_in(&dentry, (char *)dent);
|
|
Packit Service |
360c39 |
de = &dentry;
|
|
Packit Service |
360c39 |
block = de->de_inum.no_addr;
|
|
Packit Service |
360c39 |
/* Start of checks */
|
|
Packit Service |
360c39 |
memset(tmp_name, 0, sizeof(tmp_name));
|
|
Packit Service |
360c39 |
if (de->de_name_len < sizeof(tmp_name))
|
|
Packit Service |
360c39 |
strncpy(tmp_name, filename, de->de_name_len);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
strncpy(tmp_name, filename, sizeof(tmp_name) - 1);
|
|
Packit Service |
360c39 |
if (!valid_block_ip(ip, block)) {
|
|
Packit Service |
360c39 |
log_err( _("Block # referenced by system directory entry %s "
|
|
Packit Service |
360c39 |
"in inode %lld (0x%llx) is invalid or out of range;"
|
|
Packit Service |
360c39 |
" ignored.\n"),
|
|
Packit Service |
360c39 |
tmp_name, (unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* If this is a system dinode, we'll handle it later in
|
|
Packit Service |
360c39 |
check_system_inodes. If not, it'll be handled by pass1 but
|
|
Packit Service |
360c39 |
since it's in a system directory we need to make sure it's
|
|
Packit Service |
360c39 |
represented in the rgrp bitmap. */
|
|
Packit Service |
360c39 |
if (fsck_system_inode(sdp, block))
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, block, _("system file"),
|
|
Packit Service |
360c39 |
GFS2_BLKST_DINODE);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
check_n_fix_bitmap(sdp, ip->i_rgd, block, 0,
|
|
Packit Service |
360c39 |
GFS2_BLKST_DINODE);
|
|
Packit Service |
360c39 |
/* Return the number of leaf entries so metawalk doesn't flag this
|
|
Packit Service |
360c39 |
leaf as having none. */
|
|
Packit Service |
360c39 |
*count = be16_to_cpu(((struct gfs2_leaf *)bh->b_data)->lf_entries);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct metawalk_fxns sysdir_fxns = {
|
|
Packit Service |
360c39 |
.private = NULL,
|
|
Packit Service |
360c39 |
.check_metalist = resuscitate_metalist,
|
|
Packit Service |
360c39 |
.check_dentry = resuscitate_dentry,
|
|
Packit Service |
360c39 |
.delete_block = delete_block,
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct block_count *bc = (struct block_count *) private;
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Note if we've gotten this far, the block has already passed the
|
|
Packit Service |
360c39 |
check in metawalk: gfs2_check_meta(lbh, GFS2_METATYPE_LF).
|
|
Packit Service |
360c39 |
So we know it's a leaf block. */
|
|
Packit Service |
360c39 |
bc->indir_count++;
|
|
Packit Service |
360c39 |
q = block_type(bl, block);
|
|
Packit Service |
360c39 |
if (q != GFS2_BLKST_FREE) {
|
|
Packit Service |
360c39 |
log_err( _("Found duplicate block #%llu (0x%llx) referenced "
|
|
Packit Service |
360c39 |
"as a directory leaf in dinode "
|
|
Packit Service |
360c39 |
"%llu (0x%llx) - was marked %d (%s)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr, q,
|
|
Packit Service |
360c39 |
block_type_string(q));
|
|
Packit Service |
360c39 |
add_duplicate_ref(ip, block, ref_as_meta, 0, INODE_VALID);
|
|
Packit Service |
360c39 |
if (q == (ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE :
|
|
Packit Service |
360c39 |
GFS2_BLKST_USED))
|
|
Packit Service |
360c39 |
/* If the previous reference also saw this as a leaf,
|
|
Packit Service |
360c39 |
it was already checked, so don't check again. */
|
|
Packit Service |
360c39 |
return EEXIST; /* non-fatal */
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, block, _("directory leaf"),
|
|
Packit Service |
360c39 |
ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE :
|
|
Packit Service |
360c39 |
GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, int h, int *is_valid,
|
|
Packit Service |
360c39 |
int *was_duplicate, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
int iblk_type;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *nbh;
|
|
Packit Service |
360c39 |
struct block_count *bc = (struct block_count *)private;
|
|
Packit Service |
360c39 |
const char *blktypedesc;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*bh = NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*was_duplicate = 0;
|
|
Packit Service |
360c39 |
*is_valid = 0;
|
|
Packit Service |
360c39 |
if (!valid_block_ip(ip, block)) { /* blk outside of FS */
|
|
Packit Service |
360c39 |
/* The bad dinode should be invalidated later due to
|
|
Packit Service |
360c39 |
"unrecoverable" errors. The inode itself should be
|
|
Packit Service |
360c39 |
set "free" and removed from the inodetree by
|
|
Packit Service |
360c39 |
undo_check_metalist. */
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
_("bad block referencing"), GFS2_BLKST_UNLINKED);
|
|
Packit Service |
360c39 |
log_debug( _("Bad indirect block (invalid/out of range) "
|
|
Packit Service |
360c39 |
"found in inode %lld (0x%llx).\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return meta_skip_further;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (is_dir(&ip->i_di, ip->i_sbd->gfs1) && h == ip->i_di.di_height) {
|
|
Packit Service |
360c39 |
iblk_type = GFS2_METATYPE_JD;
|
|
Packit Service |
360c39 |
blktypedesc = _("a directory hash table block");
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
iblk_type = GFS2_METATYPE_IN;
|
|
Packit Service |
360c39 |
blktypedesc = _("a journaled data block");
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
q = block_type(bl, block);
|
|
Packit Service |
360c39 |
if (q != GFS2_BLKST_FREE) {
|
|
Packit Service |
360c39 |
log_err( _("Found duplicate block #%llu (0x%llx) referenced "
|
|
Packit Service |
360c39 |
"as metadata in indirect block for dinode "
|
|
Packit Service |
360c39 |
"%llu (0x%llx) - was marked %d (%s)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr, q,
|
|
Packit Service |
360c39 |
block_type_string(q));
|
|
Packit Service |
360c39 |
*was_duplicate = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
nbh = bread(ip->i_sbd, block);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*is_valid = (gfs2_check_meta(nbh, iblk_type) == 0);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!(*is_valid)) {
|
|
Packit Service |
360c39 |
log_err( _("Inode %lld (0x%llx) has a bad indirect block "
|
|
Packit Service |
360c39 |
"pointer %lld (0x%llx) (points to something "
|
|
Packit Service |
360c39 |
"that is not %s).\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block, blktypedesc);
|
|
Packit Service |
360c39 |
brelse(nbh);
|
|
Packit Service |
360c39 |
return meta_skip_further;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bc->indir_count++;
|
|
Packit Service |
360c39 |
if (*was_duplicate) {
|
|
Packit Service |
360c39 |
add_duplicate_ref(ip, block, ref_as_meta, 0,
|
|
Packit Service |
360c39 |
*is_valid ? INODE_VALID : INODE_INVALID);
|
|
Packit Service |
360c39 |
brelse(nbh);
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
*bh = nbh;
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, block, _("indirect"), ip->i_sbd->gfs1 ?
|
|
Packit Service |
360c39 |
GFS2_BLKST_DINODE : GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (*is_valid)
|
|
Packit Service |
360c39 |
return meta_is_good;
|
|
Packit Service |
360c39 |
return meta_skip_further;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* undo_reference - undo previously processed data or metadata
|
|
Packit Service |
360c39 |
* We've treated the metadata for this dinode as good so far, but not we
|
|
Packit Service |
360c39 |
* realize it's bad. So we need to undo what we've done.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 - We need to process the block as metadata. In other words,
|
|
Packit Service |
360c39 |
* we need to undo any blocks it refers to.
|
|
Packit Service |
360c39 |
* 1 - We can't process the block as metadata.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int undo_reference(struct gfs2_inode *ip, uint64_t block, int meta,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct block_count *bc = (struct block_count *)private;
|
|
Packit Service |
360c39 |
struct duptree *dt;
|
|
Packit Service |
360c39 |
struct inode_with_dups *id;
|
|
Packit Service |
360c39 |
int old_bitmap_state = 0;
|
|
Packit Service |
360c39 |
struct rgrp_tree *rgd;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!valid_block_ip(ip, block)) { /* blk outside of FS */
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
_("bad block referencing"), GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (meta)
|
|
Packit Service |
360c39 |
bc->indir_count--;
|
|
Packit Service |
360c39 |
dt = dupfind(block);
|
|
Packit Service |
360c39 |
if (dt) {
|
|
Packit Service |
360c39 |
/* remove all duplicate reference structures from this inode */
|
|
Packit Service |
360c39 |
do {
|
|
Packit Service |
360c39 |
id = find_dup_ref_inode(dt, ip);
|
|
Packit Service |
360c39 |
if (!id)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
dup_listent_delete(dt, id);
|
|
Packit Service |
360c39 |
} while (id);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (dt->refs) {
|
|
Packit Service |
360c39 |
log_err(_("Block %llu (0x%llx) is still referenced "
|
|
Packit Service |
360c39 |
"from another inode; not freeing.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
if (dt->refs == 1) {
|
|
Packit Service |
360c39 |
log_err(_("This was the only duplicate "
|
|
Packit Service |
360c39 |
"reference so far; removing it.\n"));
|
|
Packit Service |
360c39 |
dup_delete(dt);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!meta) {
|
|
Packit Service |
360c39 |
rgd = gfs2_blk2rgrpd(ip->i_sbd, block);
|
|
Packit Service |
360c39 |
old_bitmap_state = lgfs2_get_bitmap(ip->i_sbd, block, rgd);
|
|
Packit Service |
360c39 |
if (old_bitmap_state == GFS2_BLKST_DINODE)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, block,
|
|
Packit Service |
360c39 |
meta ? _("bad indirect") : _("referenced data"),
|
|
Packit Service |
360c39 |
GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
int h, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return undo_reference(ip, block, 1, private);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return undo_reference(ip, block, 0, private);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* blockmap_set_as_data - set block as 'data' in the blockmap, if not dinode
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* This function tries to set a block that's referenced as data as 'data'
|
|
Packit Service |
360c39 |
* in the fsck blockmap. But if that block is marked as 'dinode' in the
|
|
Packit Service |
360c39 |
* rgrp bitmap, it does additional checks to see if it looks like a dinode.
|
|
Packit Service |
360c39 |
* Note that previous checks were done for duplicate references, so this
|
|
Packit Service |
360c39 |
* is checking for dinodes that we haven't processed yet.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int blockmap_set_as_data(struct gfs2_inode *ip, uint64_t block)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
struct gfs2_dinode *di;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = fsck_blkmap_set_noino(ip, block, _("data"), GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
if (!error)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = 0;
|
|
Packit Service |
360c39 |
/* The bitmap says it's a dinode, but a block reference begs to differ.
|
|
Packit Service |
360c39 |
So which is it? */
|
|
Packit Service |
360c39 |
bh = bread(ip->i_sbd, block);
|
|
Packit Service |
360c39 |
if (gfs2_check_meta(bh, GFS2_METATYPE_DI) != 0)
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* The meta header agrees it's a dinode. But it might be data in
|
|
Packit Service |
360c39 |
disguise, so do some extra checks. */
|
|
Packit Service |
360c39 |
di = (struct gfs2_dinode *)bh->b_data;
|
|
Packit Service |
360c39 |
if (be64_to_cpu(di->di_num.no_addr) != block)
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_err(_("Inode %lld (0x%llx) has a reference to block %lld (0x%llx) "
|
|
Packit Service |
360c39 |
"as a data block, but it appears to be a dinode we "
|
|
Packit Service |
360c39 |
"haven't checked yet.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)block, (unsigned long long)block);
|
|
Packit Service |
360c39 |
error = -1;
|
|
Packit Service |
360c39 |
out:
|
|
Packit Service |
360c39 |
if (!error)
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, block, _("data"), GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
|
|
Packit Service |
360c39 |
uint64_t block, void *private,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bbh, uint64_t *ptr)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
struct block_count *bc = (struct block_count *) private;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!valid_block_ip(ip, block)) {
|
|
Packit Service |
360c39 |
log_err( _("inode %lld (0x%llx) has a bad data block pointer "
|
|
Packit Service |
360c39 |
"%lld (0x%llx) (invalid or out of range) "),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)block, (unsigned long long)block);
|
|
Packit Service |
360c39 |
if (metablock == ip->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
log_err("\n");
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
log_err(_("from metadata block %llu (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)metablock,
|
|
Packit Service |
360c39 |
(unsigned long long)metablock);
|
|
Packit Service |
360c39 |
/* Mark the owner of this block with the bad_block
|
|
Packit Service |
360c39 |
* designator so we know to check it for out of range
|
|
Packit Service |
360c39 |
* blocks later */
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
_("bad (out of range) data"),
|
|
Packit Service |
360c39 |
GFS2_BLKST_UNLINKED);
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
bc->data_count++; /* keep the count sane anyway */
|
|
Packit Service |
360c39 |
q = block_type(bl, block);
|
|
Packit Service |
360c39 |
if (q != GFS2_BLKST_FREE) {
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
struct gfs2_meta_header mh;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_err( _("Found duplicate %s block %llu (0x%llx) "
|
|
Packit Service |
360c39 |
"referenced as data by dinode %llu (0x%llx) "),
|
|
Packit Service |
360c39 |
block_type_string(q),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if (metablock == ip->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
log_err("\n");
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
log_err(_("from metadata block %llu (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)metablock,
|
|
Packit Service |
360c39 |
(unsigned long long)metablock);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
switch (q) {
|
|
Packit Service |
360c39 |
case GFS2_BLKST_DINODE:
|
|
Packit Service |
360c39 |
log_info(_("The block was processed earlier as an "
|
|
Packit Service |
360c39 |
"inode, so it can't possibly be data.\n"));
|
|
Packit Service |
360c39 |
/* We still need to add a duplicate record here because
|
|
Packit Service |
360c39 |
when check_metatree tries to delete the inode, we
|
|
Packit Service |
360c39 |
can't have the "undo" functions freeing the block
|
|
Packit Service |
360c39 |
out from other the original referencing inode. */
|
|
Packit Service |
360c39 |
add_duplicate_ref(ip, block, ref_as_data, 0,
|
|
Packit Service |
360c39 |
INODE_VALID);
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
case GFS2_BLKST_USED: /* tough decision: May be data or meta */
|
|
Packit Service |
360c39 |
bh = bread(ip->i_sbd, block);
|
|
Packit Service |
360c39 |
gfs2_meta_header_in(&mh, bh->b_data);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
if (mh.mh_magic == GFS2_MAGIC &&
|
|
Packit Service |
360c39 |
mh.mh_type >= GFS2_METATYPE_RG &&
|
|
Packit Service |
360c39 |
mh.mh_type <= GFS2_METATYPE_QC &&
|
|
Packit Service |
360c39 |
mh.mh_type != GFS2_METATYPE_DI &&
|
|
Packit Service |
360c39 |
mh.mh_format % 100 == 0) {
|
|
Packit Service |
360c39 |
log_info(_("The block was processed earlier "
|
|
Packit Service |
360c39 |
"as valid metadata, so it can't "
|
|
Packit Service |
360c39 |
"possibly be data.\n"));
|
|
Packit Service |
360c39 |
/* We still need to add a duplicate record here
|
|
Packit Service |
360c39 |
because when check_metatree tries to delete
|
|
Packit Service |
360c39 |
the inode, we can't have the "undo"
|
|
Packit Service |
360c39 |
functions freeing the block out from other
|
|
Packit Service |
360c39 |
the original referencing inode. */
|
|
Packit Service |
360c39 |
add_duplicate_ref(ip, block, ref_as_data, 0,
|
|
Packit Service |
360c39 |
INODE_VALID);
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_info( _("Seems to be a normal duplicate; I'll "
|
|
Packit Service |
360c39 |
"sort it out in pass1b.\n"));
|
|
Packit Service |
360c39 |
add_duplicate_ref(ip, block, ref_as_data, 0,
|
|
Packit Service |
360c39 |
INODE_VALID);
|
|
Packit Service |
360c39 |
/* This inode references the block as data. So if this
|
|
Packit Service |
360c39 |
all is validated, we want to keep this count. */
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
case GFS2_BLKST_UNLINKED:
|
|
Packit Service |
360c39 |
log_info( _("The block was invalid as metadata but might be "
|
|
Packit Service |
360c39 |
"okay as data. I'll sort it out in pass1b.\n"));
|
|
Packit Service |
360c39 |
add_duplicate_ref(ip, block, ref_as_data, 0, INODE_VALID);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* In gfs1, rgrp indirect blocks are marked in the bitmap as "meta".
|
|
Packit Service |
360c39 |
In gfs2, "meta" is only for dinodes. So here we dummy up the
|
|
Packit Service |
360c39 |
blocks so that the bitmap isn't changed improperly. */
|
|
Packit Service |
360c39 |
if (ip->i_sbd->gfs1 && ip == ip->i_sbd->md.riinode) {
|
|
Packit Service |
360c39 |
log_info(_("Block %lld (0x%llx) is a GFS1 rindex block\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block, (unsigned long long)block);
|
|
Packit Service |
360c39 |
gfs2_special_set(&gfs1_rindex_blks, block);
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, block, _("rgrp"), GFS2_BLKST_DINODE);
|
|
Packit Service |
360c39 |
/*gfs2_meta_rgrp);*/
|
|
Packit Service |
360c39 |
} else if (ip->i_sbd->gfs1 && ip->i_di.di_flags & GFS2_DIF_JDATA) {
|
|
Packit Service |
360c39 |
log_info(_("Block %lld (0x%llx) is a GFS1 journaled data "
|
|
Packit Service |
360c39 |
"block\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block, (unsigned long long)block);
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, block, _("jdata"), GFS2_BLKST_DINODE);
|
|
Packit Service |
360c39 |
} else
|
|
Packit Service |
360c39 |
return blockmap_set_as_data(ip, block);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int ask_remove_inode_eattr(struct gfs2_inode *ip,
|
|
Packit Service |
360c39 |
struct block_count *bc)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if (ip->i_di.di_eattr == 0)
|
|
Packit Service |
360c39 |
return 0; /* eattr was removed prior to this call */
|
|
Packit Service |
360c39 |
log_err( _("Inode %lld (0x%llx) has unrecoverable Extended Attribute "
|
|
Packit Service |
360c39 |
"errors.\n"), (unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if (query( _("Clear all Extended Attributes from the inode? (y/n) "))){
|
|
Packit Service |
360c39 |
undo_reference(ip, ip->i_di.di_eattr, 0, bc);
|
|
Packit Service |
360c39 |
ip->i_di.di_eattr = 0;
|
|
Packit Service |
360c39 |
bc->ea_count = 0;
|
|
Packit Service |
360c39 |
ip->i_di.di_blocks = 1 + bc->indir_count + bc->data_count;
|
|
Packit Service |
360c39 |
ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT;
|
|
Packit Service |
360c39 |
bmodified(ip->i_bh);
|
|
Packit Service |
360c39 |
log_err( _("Extended attributes were removed.\n"));
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
log_err( _("Extended attributes were not removed.\n"));
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int undo_eattr_indir_or_leaf(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
uint64_t parent,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
struct block_count *bc = (struct block_count *) private;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!valid_block_ip(ip, block))
|
|
Packit Service |
360c39 |
return meta_error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Need to check block_type before undoing the reference, which can
|
|
Packit Service |
360c39 |
set it to free, which would cause the test below to fail. */
|
|
Packit Service |
360c39 |
q = block_type(bl, block);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = undo_reference(ip, block, 0, private);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bc->ea_count--;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (q != (sdp->gfs1 ? GFS2_BLKST_DINODE : GFS2_BLKST_USED))
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*bh = bread(sdp, block);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* complain_eas - complain about extended attribute errors for an inode
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* @ip - in core inode pointer
|
|
Packit Service |
360c39 |
* block - the block that had the problem
|
|
Packit Service |
360c39 |
* duplicate - if this is a duplicate block, don't set it "free"
|
|
Packit Service |
360c39 |
* emsg - what to tell the user about the eas being checked
|
|
Packit Service |
360c39 |
* Returns: 1 if the EA is fixed, else 0 if it was not fixed.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static void complain_eas(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
const char *emsg)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
log_err(_("Inode #%llu (0x%llx): %s"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr, emsg);
|
|
Packit Service |
360c39 |
log_err(_(" at block #%lld (0x%llx).\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block, (unsigned long long)block);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
|
|
Packit Service |
360c39 |
uint64_t parent, struct gfs2_buffer_head **bh,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
int ret = 0;
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
struct block_count *bc = (struct block_count *) private;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* This inode contains an eattr - it may be invalid, but the
|
|
Packit Service |
360c39 |
* eattr attributes points to a non-zero block */
|
|
Packit Service |
360c39 |
if (!valid_block_ip(ip, indirect)) {
|
|
Packit Service |
360c39 |
/* Doesn't help to mark this here - this gets checked
|
|
Packit Service |
360c39 |
* in pass1c */
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
q = block_type(bl, indirect);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Special duplicate processing: If we have an EA block,
|
|
Packit Service |
360c39 |
check if it really is an EA. If it is, let duplicate
|
|
Packit Service |
360c39 |
handling sort it out. If it isn't, clear it but don't
|
|
Packit Service |
360c39 |
count it as a duplicate. */
|
|
Packit Service |
360c39 |
*bh = bread(sdp, indirect);
|
|
Packit Service |
360c39 |
if (gfs2_check_meta(*bh, GFS2_METATYPE_IN)) {
|
|
Packit Service |
360c39 |
bc->ea_count++;
|
|
Packit Service |
360c39 |
if (q != GFS2_BLKST_FREE) { /* Duplicate? */
|
|
Packit Service |
360c39 |
add_duplicate_ref(ip, indirect, ref_as_ea, 0,
|
|
Packit Service |
360c39 |
INODE_VALID);
|
|
Packit Service |
360c39 |
complain_eas(ip, indirect,
|
|
Packit Service |
360c39 |
_("Bad indirect Extended Attribute "
|
|
Packit Service |
360c39 |
"duplicate found"));
|
|
Packit Service |
360c39 |
/* Return 0 here because if all that's wrong is a
|
|
Packit Service |
360c39 |
duplicate block reference, we want pass1b to figure
|
|
Packit Service |
360c39 |
it out. We don't want to delete all the extended
|
|
Packit Service |
360c39 |
attributes as if they are in error. */
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
complain_eas(ip, indirect,
|
|
Packit Service |
360c39 |
_("Extended Attribute indirect block has "
|
|
Packit Service |
360c39 |
"incorrect type"));
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (q != GFS2_BLKST_FREE) { /* Duplicate? */
|
|
Packit Service |
360c39 |
add_duplicate_ref(ip, indirect, ref_as_ea, 0, INODE_VALID);
|
|
Packit Service |
360c39 |
complain_eas(ip, indirect,
|
|
Packit Service |
360c39 |
_("Duplicate Extended Attribute indirect block"));
|
|
Packit Service |
360c39 |
bc->ea_count++;
|
|
Packit Service |
360c39 |
ret = 0; /* For the same reason stated above. */
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, indirect,
|
|
Packit Service |
360c39 |
_("indirect Extended Attribute"), sdp->gfs1 ?
|
|
Packit Service |
360c39 |
GFS2_BLKST_DINODE : GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
bc->ea_count++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return ret;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int finish_eattr_indir(struct gfs2_inode *ip, int leaf_pointers,
|
|
Packit Service |
360c39 |
int leaf_pointer_errors, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct block_count *bc = (struct block_count *) private;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (leaf_pointer_errors == leaf_pointers) /* All eas were bad */
|
|
Packit Service |
360c39 |
return ask_remove_inode_eattr(ip, bc);
|
|
Packit Service |
360c39 |
log_debug( _("Marking inode #%llu (0x%llx) with extended "
|
|
Packit Service |
360c39 |
"attribute block\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if (!leaf_pointer_errors)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
log_err( _("Inode %lld (0x%llx) has recoverable indirect "
|
|
Packit Service |
360c39 |
"Extended Attribute errors.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if (query( _("Okay to fix the block count for the inode? (y/n) "))) {
|
|
Packit Service |
360c39 |
ip->i_di.di_blocks = 1 + bc->indir_count +
|
|
Packit Service |
360c39 |
bc->data_count + bc->ea_count;
|
|
Packit Service |
360c39 |
bmodified(ip->i_bh);
|
|
Packit Service |
360c39 |
log_err(_("Block count fixed: 1+%lld+%lld+%lld = %lld.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)bc->indir_count,
|
|
Packit Service |
360c39 |
(unsigned long long)bc->data_count,
|
|
Packit Service |
360c39 |
(unsigned long long)bc->ea_count,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_blocks);
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_err( _("Block count not fixed.\n"));
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* check_ealeaf_block
|
|
Packit Service |
360c39 |
* checks an extended attribute (not directory) leaf block
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int check_ealeaf_block(struct gfs2_inode *ip, uint64_t block, int btype,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *leaf_bh = NULL;
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
struct block_count *bc = (struct block_count *) private;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
q = block_type(bl, block);
|
|
Packit Service |
360c39 |
/* Special duplicate processing: If we have an EA block, check if it
|
|
Packit Service |
360c39 |
really is an EA. If it is, let duplicate handling sort it out.
|
|
Packit Service |
360c39 |
If it isn't, clear it but don't count it as a duplicate. */
|
|
Packit Service |
360c39 |
leaf_bh = bread(sdp, block);
|
|
Packit Service |
360c39 |
if (gfs2_check_meta(leaf_bh, btype)) {
|
|
Packit Service |
360c39 |
bc->ea_count++;
|
|
Packit Service |
360c39 |
if (q != GFS2_BLKST_FREE) { /* Duplicate? */
|
|
Packit Service |
360c39 |
add_duplicate_ref(ip, block, ref_as_ea, 0,
|
|
Packit Service |
360c39 |
INODE_VALID);
|
|
Packit Service |
360c39 |
complain_eas(ip, block, _("Extended attribute leaf "
|
|
Packit Service |
360c39 |
"duplicate found"));
|
|
Packit Service |
360c39 |
/* Return 0 here because if all that's wrong is a
|
|
Packit Service |
360c39 |
duplicate block reference, we want pass1b to figure
|
|
Packit Service |
360c39 |
it out. We don't want to delete all the extended
|
|
Packit Service |
360c39 |
attributes as if they are in error. */
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
complain_eas(ip, block, _("Extended Attribute leaf block has "
|
|
Packit Service |
360c39 |
"incorrect type"));
|
|
Packit Service |
360c39 |
brelse(leaf_bh);
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (q != GFS2_BLKST_FREE) { /* Duplicate? */
|
|
Packit Service |
360c39 |
complain_eas(ip, block, _("Extended Attribute leaf "
|
|
Packit Service |
360c39 |
"duplicate found"));
|
|
Packit Service |
360c39 |
add_duplicate_ref(ip, block, ref_as_data, 0, INODE_VALID);
|
|
Packit Service |
360c39 |
bc->ea_count++;
|
|
Packit Service |
360c39 |
brelse(leaf_bh);
|
|
Packit Service |
360c39 |
/* Return 0 here because if all that's wrong is a duplicate
|
|
Packit Service |
360c39 |
block reference, we want pass1b to figure it out. We don't
|
|
Packit Service |
360c39 |
want to delete all the extended attributes as if they are
|
|
Packit Service |
360c39 |
in error. */
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Point of confusion: We've got to set the ea block itself to
|
|
Packit Service |
360c39 |
GFS2_BLKST_USED here. Elsewhere we mark the inode with
|
|
Packit Service |
360c39 |
gfs2_eattr_block meaning it contains an eattr. */
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, block, _("Extended Attribute"),
|
|
Packit Service |
360c39 |
sdp->gfs1 ? GFS2_BLKST_DINODE : GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
bc->ea_count++;
|
|
Packit Service |
360c39 |
*bh = leaf_bh;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* check_extended_leaf_eattr
|
|
Packit Service |
360c39 |
* @ip
|
|
Packit Service |
360c39 |
* @el_blk: block number of the extended leaf
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* An EA leaf block can contain EA's with pointers to blocks
|
|
Packit Service |
360c39 |
* where the data for that EA is kept. Those blocks still
|
|
Packit Service |
360c39 |
* have the gfs2 meta header of type GFS2_METATYPE_EA
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 if correct[able], -1 if removal is needed
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int check_extended_leaf_eattr(struct gfs2_inode *ip, int i,
|
|
Packit Service |
360c39 |
uint64_t *data_ptr,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *leaf_bh,
|
|
Packit Service |
360c39 |
uint32_t tot_ealen,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *ea_hdr,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *ea_hdr_prev,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t el_blk = be64_to_cpu(*data_ptr);
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh = NULL;
|
|
Packit Service |
360c39 |
int error = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!valid_block_ip(ip, el_blk)) {
|
|
Packit Service |
360c39 |
log_err( _("Inode #%llu (0x%llx): Extended Attribute block "
|
|
Packit Service |
360c39 |
"%llu (0x%llx) has an extended leaf block #%llu "
|
|
Packit Service |
360c39 |
"(0x%llx) that is invalid or out of range.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_eattr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_eattr,
|
|
Packit Service |
360c39 |
(unsigned long long)el_blk,
|
|
Packit Service |
360c39 |
(unsigned long long)el_blk);
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, ip->i_di.di_eattr,
|
|
Packit Service |
360c39 |
_("bad (out of range) Extended Attribute "),
|
|
Packit Service |
360c39 |
GFS2_BLKST_UNLINKED);
|
|
Packit Service |
360c39 |
error = 1;
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
error = check_ealeaf_block(ip, el_blk, GFS2_METATYPE_ED, &bh,
|
|
Packit Service |
360c39 |
private);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (bh)
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
log_err(_("Bad extended attribute found at block %lld "
|
|
Packit Service |
360c39 |
"(0x%llx)"),
|
|
Packit Service |
360c39 |
(unsigned long long)be64_to_cpu(*data_ptr),
|
|
Packit Service |
360c39 |
(unsigned long long)be64_to_cpu(*data_ptr));
|
|
Packit Service |
360c39 |
if (query( _("Repair the bad Extended Attribute? (y/n) "))) {
|
|
Packit Service |
360c39 |
ea_hdr->ea_num_ptrs = i;
|
|
Packit Service |
360c39 |
ea_hdr->ea_data_len = cpu_to_be32(tot_ealen);
|
|
Packit Service |
360c39 |
*data_ptr = 0;
|
|
Packit Service |
360c39 |
bmodified(leaf_bh);
|
|
Packit Service |
360c39 |
/* Endianness doesn't matter in this case because it's
|
|
Packit Service |
360c39 |
a single byte. */
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, ip->i_di.di_eattr,
|
|
Packit Service |
360c39 |
_("extended attribute"),
|
|
Packit Service |
360c39 |
sdp->gfs1 ? GFS2_BLKST_DINODE :
|
|
Packit Service |
360c39 |
GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
log_err( _("The EA was fixed.\n"));
|
|
Packit Service |
360c39 |
error = 0;
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
error = 1;
|
|
Packit Service |
360c39 |
log_err( _("The bad EA was not fixed.\n"));
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
uint64_t parent, struct gfs2_buffer_head **bh,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if (!valid_block_ip(ip, block)) {
|
|
Packit Service |
360c39 |
log_warn( _("Inode #%llu (0x%llx): Extended Attribute leaf "
|
|
Packit Service |
360c39 |
"block #%llu (0x%llx) is invalid or out of "
|
|
Packit Service |
360c39 |
"range.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)block, (unsigned long long)block);
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, ip->i_di.di_eattr,
|
|
Packit Service |
360c39 |
_("bad (out of range) Extended "
|
|
Packit Service |
360c39 |
"Attribute leaf"), GFS2_BLKST_UNLINKED);
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return check_ealeaf_block(ip, block, GFS2_METATYPE_EA, bh, private);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int ask_remove_eattr_entry(struct gfs2_sbd *sdp,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *leaf_bh,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *curr,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *prev,
|
|
Packit Service |
360c39 |
int fix_curr, int fix_curr_len)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if (!query( _("Remove the bad Extended Attribute entry? (y/n) "))) {
|
|
Packit Service |
360c39 |
log_err( _("Bad Extended Attribute not removed.\n"));
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (fix_curr)
|
|
Packit Service |
360c39 |
curr->ea_flags |= GFS2_EAFLAG_LAST;
|
|
Packit Service |
360c39 |
if (fix_curr_len) {
|
|
Packit Service |
360c39 |
uint32_t max_size = sdp->sd_sb.sb_bsize;
|
|
Packit Service |
360c39 |
uint32_t offset = (uint32_t)(((unsigned long)curr) -
|
|
Packit Service |
360c39 |
((unsigned long)leaf_bh->b_data));
|
|
Packit Service |
360c39 |
curr->ea_rec_len = cpu_to_be32(max_size - offset);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!prev)
|
|
Packit Service |
360c39 |
curr->ea_type = GFS2_EATYPE_UNUSED;
|
|
Packit Service |
360c39 |
else {
|
|
Packit Service |
360c39 |
uint32_t tmp32 = be32_to_cpu(curr->ea_rec_len) +
|
|
Packit Service |
360c39 |
be32_to_cpu(prev->ea_rec_len);
|
|
Packit Service |
360c39 |
prev->ea_rec_len = cpu_to_be32(tmp32);
|
|
Packit Service |
360c39 |
if (curr->ea_flags & GFS2_EAFLAG_LAST)
|
|
Packit Service |
360c39 |
prev->ea_flags |= GFS2_EAFLAG_LAST;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_err( _("Bad Extended Attribute at block #%llu"
|
|
Packit Service |
360c39 |
" (0x%llx) removed.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)leaf_bh->b_blocknr,
|
|
Packit Service |
360c39 |
(unsigned long long)leaf_bh->b_blocknr);
|
|
Packit Service |
360c39 |
bmodified(leaf_bh);
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int check_eattr_entries(struct gfs2_inode *ip,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *leaf_bh,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *ea_hdr,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *ea_hdr_prev,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
char ea_name[256];
|
|
Packit Service |
360c39 |
uint32_t offset = (uint32_t)(((unsigned long)ea_hdr) -
|
|
Packit Service |
360c39 |
((unsigned long)leaf_bh->b_data));
|
|
Packit Service |
360c39 |
uint32_t max_size = sdp->sd_sb.sb_bsize;
|
|
Packit Service |
360c39 |
uint32_t avail_size;
|
|
Packit Service |
360c39 |
int max_ptrs;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!ea_hdr->ea_name_len){
|
|
Packit Service |
360c39 |
log_err( _("EA has name length of zero\n"));
|
|
Packit Service |
360c39 |
return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
|
|
Packit Service |
360c39 |
ea_hdr_prev, 1, 1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (offset + be32_to_cpu(ea_hdr->ea_rec_len) > max_size){
|
|
Packit Service |
360c39 |
log_err( _("EA rec length too long\n"));
|
|
Packit Service |
360c39 |
return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
|
|
Packit Service |
360c39 |
ea_hdr_prev, 1, 1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (offset + be32_to_cpu(ea_hdr->ea_rec_len) == max_size &&
|
|
Packit Service |
360c39 |
(ea_hdr->ea_flags & GFS2_EAFLAG_LAST) == 0){
|
|
Packit Service |
360c39 |
log_err( _("last EA has no last entry flag\n"));
|
|
Packit Service |
360c39 |
return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
|
|
Packit Service |
360c39 |
ea_hdr_prev, 0, 0);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!ea_hdr->ea_name_len){
|
|
Packit Service |
360c39 |
log_err( _("EA has name length of zero\n"));
|
|
Packit Service |
360c39 |
return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
|
|
Packit Service |
360c39 |
ea_hdr_prev, 0, 0);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
memset(ea_name, 0, sizeof(ea_name));
|
|
Packit Service |
360c39 |
strncpy(ea_name, (char *)ea_hdr + sizeof(struct gfs2_ea_header),
|
|
Packit Service |
360c39 |
ea_hdr->ea_name_len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!GFS2_EATYPE_VALID(ea_hdr->ea_type) &&
|
|
Packit Service |
360c39 |
((ea_hdr_prev) || (!ea_hdr_prev && ea_hdr->ea_type))){
|
|
Packit Service |
360c39 |
/* Skip invalid entry */
|
|
Packit Service |
360c39 |
log_err(_("EA (%s) type is invalid (%d > %d).\n"),
|
|
Packit Service |
360c39 |
ea_name, ea_hdr->ea_type, GFS2_EATYPE_LAST);
|
|
Packit Service |
360c39 |
return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
|
|
Packit Service |
360c39 |
ea_hdr_prev, 0, 0);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!ea_hdr->ea_num_ptrs)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
avail_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header);
|
|
Packit Service |
360c39 |
max_ptrs = (be32_to_cpu(ea_hdr->ea_data_len)+avail_size-1)/avail_size;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (max_ptrs > ea_hdr->ea_num_ptrs) {
|
|
Packit Service |
360c39 |
log_err(_("EA (%s) has incorrect number of pointers.\n"),
|
|
Packit Service |
360c39 |
ea_name);
|
|
Packit Service |
360c39 |
log_err(_(" Required: %d\n Reported: %d\n"),
|
|
Packit Service |
360c39 |
max_ptrs, ea_hdr->ea_num_ptrs);
|
|
Packit Service |
360c39 |
return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
|
|
Packit Service |
360c39 |
ea_hdr_prev, 0, 0);
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
log_debug( _(" Pointers Required: %d\n Pointers Reported: %d\n"),
|
|
Packit Service |
360c39 |
max_ptrs, ea_hdr->ea_num_ptrs);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* mark_block_invalid - mark blocks associated with an inode as invalid
|
|
Packit Service |
360c39 |
* unless the block is a duplicate.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* An "invalid" block is now considered free in the bitmap, and pass2 will
|
|
Packit Service |
360c39 |
* delete any invalid blocks. This is nearly identical to function
|
|
Packit Service |
360c39 |
* delete_block_if_notdup.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
enum dup_ref_type reftype, const char *btype,
|
|
Packit Service |
360c39 |
int *is_valid, int *was_duplicate)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* If the block isn't valid, we obviously can't invalidate it.
|
|
Packit Service |
360c39 |
* However, if we return an error, invalidating will stop, and
|
|
Packit Service |
360c39 |
* we want it to continue to invalidate the valid blocks. If we
|
|
Packit Service |
360c39 |
* don't do this, block references that follow that are also
|
|
Packit Service |
360c39 |
* referenced elsewhere (duplicates) won't be flagged as such,
|
|
Packit Service |
360c39 |
* and as a result, they'll be freed when this dinode is deleted,
|
|
Packit Service |
360c39 |
* despite being used by another dinode as a valid block. */
|
|
Packit Service |
360c39 |
if (is_valid)
|
|
Packit Service |
360c39 |
*is_valid = 1;
|
|
Packit Service |
360c39 |
if (was_duplicate)
|
|
Packit Service |
360c39 |
*was_duplicate = 0;
|
|
Packit Service |
360c39 |
if (!valid_block_ip(ip, block)) {
|
|
Packit Service |
360c39 |
if (is_valid)
|
|
Packit Service |
360c39 |
*is_valid = 0;
|
|
Packit Service |
360c39 |
return meta_is_good;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
q = block_type(bl, block);
|
|
Packit Service |
360c39 |
if (q != GFS2_BLKST_FREE) {
|
|
Packit Service |
360c39 |
if (was_duplicate)
|
|
Packit Service |
360c39 |
*was_duplicate = 1;
|
|
Packit Service |
360c39 |
add_duplicate_ref(ip, block, reftype, 0, INODE_INVALID);
|
|
Packit Service |
360c39 |
log_info( _("%s block %lld (0x%llx), part of inode "
|
|
Packit Service |
360c39 |
"%lld (0x%llx), was previously referenced so "
|
|
Packit Service |
360c39 |
"the invalid reference is ignored.\n"),
|
|
Packit Service |
360c39 |
btype, (unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
return meta_is_good;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, block, btype, GFS2_BLKST_UNLINKED);
|
|
Packit Service |
360c39 |
return meta_is_good;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, int h,
|
|
Packit Service |
360c39 |
int *is_valid, int *was_duplicate,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
*is_valid = 1;
|
|
Packit Service |
360c39 |
*was_duplicate = 0;
|
|
Packit Service |
360c39 |
return mark_block_invalid(ip, block, ref_as_meta, _("metadata"),
|
|
Packit Service |
360c39 |
is_valid, was_duplicate);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return mark_block_invalid(ip, block, ref_as_meta, _("leaf"),
|
|
Packit Service |
360c39 |
NULL, NULL);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
|
|
Packit Service |
360c39 |
uint64_t block, void *private,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh, uint64_t *ptr)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return mark_block_invalid(ip, block, ref_as_data, _("data"),
|
|
Packit Service |
360c39 |
NULL, NULL);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int invalidate_eattr_indir(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
uint64_t parent,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return mark_block_invalid(ip, block, ref_as_ea,
|
|
Packit Service |
360c39 |
_("indirect extended attribute"),
|
|
Packit Service |
360c39 |
NULL, NULL);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int invalidate_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
uint64_t parent, struct gfs2_buffer_head **bh,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return mark_block_invalid(ip, block, ref_as_ea,
|
|
Packit Service |
360c39 |
_("extended attribute"),
|
|
Packit Service |
360c39 |
NULL, NULL);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Check for massive amounts of pointer corruption. If the block has
|
|
Packit Service |
360c39 |
* lots of out-of-range pointers, we can't trust any of the pointers.
|
|
Packit Service |
360c39 |
* For example, a stray pointer with a value of 0x1d might be
|
|
Packit Service |
360c39 |
* corruption/nonsense, and if so, we don't want to delete an
|
|
Packit Service |
360c39 |
* important file (like master or the root directory) because of it.
|
|
Packit Service |
360c39 |
* We need to check for a large number of bad pointers BEFORE we start
|
|
Packit Service |
360c39 |
* messing with them because we don't want to mark a block as a
|
|
Packit Service |
360c39 |
* duplicate (for example) until we know if the pointers in general can
|
|
Packit Service |
360c39 |
* be trusted. Thus it needs to be in a separate loop.
|
|
Packit Service |
360c39 |
* Returns: 0 if good range, otherwise != 0
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
enum b_types { btype_meta, btype_leaf, btype_data, btype_ieattr, btype_eattr};
|
|
Packit Service |
360c39 |
const char *btypes[5] = {
|
|
Packit Service |
360c39 |
"metadata", "leaf", "data", "indirect extended attribute",
|
|
Packit Service |
360c39 |
"extended attribute" };
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, enum b_types btype,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
long *bad_pointers = (long *)private;
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!valid_block_ip(ip, block)) {
|
|
Packit Service |
360c39 |
(*bad_pointers)++;
|
|
Packit Service |
360c39 |
log_info( _("Bad %s block pointer (invalid or out of range "
|
|
Packit Service |
360c39 |
"#%ld) found in inode %lld (0x%llx).\n"),
|
|
Packit Service |
360c39 |
btypes[btype], *bad_pointers,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
|
|
Packit Service |
360c39 |
return meta_is_good;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
return meta_error; /* Exits check_metatree quicker */
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* See how many duplicate blocks it has */
|
|
Packit Service |
360c39 |
q = block_type(bl, block);
|
|
Packit Service |
360c39 |
if (q != GFS2_BLKST_FREE) {
|
|
Packit Service |
360c39 |
(*bad_pointers)++;
|
|
Packit Service |
360c39 |
log_info( _("Duplicated %s block pointer (violation %ld, block"
|
|
Packit Service |
360c39 |
" %lld (0x%llx)) found in inode %lld (0x%llx).\n"),
|
|
Packit Service |
360c39 |
btypes[btype], *bad_pointers,
|
|
Packit Service |
360c39 |
(unsigned long long)block, (unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
|
|
Packit Service |
360c39 |
return meta_is_good;
|
|
Packit Service |
360c39 |
else {
|
|
Packit Service |
360c39 |
log_debug(_("Inode 0x%llx bad pointer tolerance "
|
|
Packit Service |
360c39 |
"exceeded: block 0x%llx.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
return meta_error; /* Exits check_metatree quicker */
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return meta_is_good;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int rangecheck_metadata(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, int h,
|
|
Packit Service |
360c39 |
int *is_valid, int *was_duplicate,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
*is_valid = 1;
|
|
Packit Service |
360c39 |
*was_duplicate = 0;
|
|
Packit Service |
360c39 |
return rangecheck_block(ip, block, bh, btype_meta, private);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int rangecheck_leaf(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return rangecheck_block(ip, block, NULL, btype_leaf, private);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int rangecheck_data(struct gfs2_inode *ip, uint64_t metablock,
|
|
Packit Service |
360c39 |
uint64_t block, void *private,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh, uint64_t *ptr)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return rangecheck_block(ip, block, NULL, btype_data, private);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int rangecheck_eattr_indir(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
uint64_t parent,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return rangecheck_block(ip, block, NULL, btype_ieattr, private);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int rangecheck_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
uint64_t parent, struct gfs2_buffer_head **bh,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return rangecheck_block(ip, block, NULL, btype_eattr, private);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct metawalk_fxns rangecheck_fxns = {
|
|
Packit Service |
360c39 |
.private = NULL,
|
|
Packit Service |
360c39 |
.readahead = 1,
|
|
Packit Service |
360c39 |
.check_metalist = rangecheck_metadata,
|
|
Packit Service |
360c39 |
.check_data = rangecheck_data,
|
|
Packit Service |
360c39 |
.check_leaf = rangecheck_leaf,
|
|
Packit Service |
360c39 |
.check_eattr_indir = rangecheck_eattr_indir,
|
|
Packit Service |
360c39 |
.check_eattr_leaf = rangecheck_eattr_leaf,
|
|
Packit Service |
360c39 |
.delete_block = delete_block,
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct metawalk_fxns eattr_undo_fxns = {
|
|
Packit Service |
360c39 |
.private = NULL,
|
|
Packit Service |
360c39 |
.check_eattr_indir = undo_eattr_indir_or_leaf,
|
|
Packit Service |
360c39 |
.check_eattr_leaf = undo_eattr_indir_or_leaf,
|
|
Packit Service |
360c39 |
.finish_eattr_indir = finish_eattr_indir,
|
|
Packit Service |
360c39 |
.delete_block = delete_block,
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
/* set_ip_blockmap - set the blockmap for a dinode
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* returns: 0 if no error, -EINVAL if dinode has a bad mode, -EPERM on error
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int set_ip_blockmap(struct gfs2_inode *ip)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t block = ip->i_bh->b_blocknr;
|
|
Packit Service |
360c39 |
uint32_t mode;
|
|
Packit Service |
360c39 |
const char *ty;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (ip->i_sbd->gfs1)
|
|
Packit Service |
360c39 |
mode = gfs_to_gfs2_mode(ip);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
mode = ip->i_di.di_mode & S_IFMT;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
switch (mode) {
|
|
Packit Service |
360c39 |
case S_IFDIR:
|
|
Packit Service |
360c39 |
ty = _("directory");
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case S_IFREG:
|
|
Packit Service |
360c39 |
ty = _("file");
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case S_IFLNK:
|
|
Packit Service |
360c39 |
ty = _("symlink");
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case S_IFBLK:
|
|
Packit Service |
360c39 |
ty = _("block device");
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case S_IFCHR:
|
|
Packit Service |
360c39 |
ty = _("character device");
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case S_IFIFO:
|
|
Packit Service |
360c39 |
ty = _("fifo");
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
case S_IFSOCK:
|
|
Packit Service |
360c39 |
ty = _("socket");
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
default:
|
|
Packit Service |
360c39 |
return -EINVAL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (fsck_blockmap_set(ip, block, ty, GFS2_BLKST_DINODE) ||
|
|
Packit Service |
360c39 |
(mode == S_IFDIR && !dirtree_insert(ip->i_di.di_num))) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return -EPERM;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, int h, int *is_valid,
|
|
Packit Service |
360c39 |
int *was_duplicate, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
const char *desc = (const char *)private;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* No need to range_check here--if it was added, it's in range. */
|
|
Packit Service |
360c39 |
/* We can't check the bitmap here because this function is called
|
|
Packit Service |
360c39 |
after the bitmap has been set but before the blockmap has. */
|
|
Packit Service |
360c39 |
*is_valid = 1;
|
|
Packit Service |
360c39 |
*was_duplicate = 0;
|
|
Packit Service |
360c39 |
*bh = bread(ip->i_sbd, block);
|
|
Packit Service |
360c39 |
q = bitmap_type(ip->i_sbd, block);
|
|
Packit Service |
360c39 |
if (q == GFS2_BLKST_FREE) {
|
|
Packit Service |
360c39 |
log_debug(_("%s reference to new metadata block "
|
|
Packit Service |
360c39 |
"%lld (0x%llx) is now marked as indirect.\n"),
|
|
Packit Service |
360c39 |
desc, (unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
gfs2_blockmap_set(bl, block, ip->i_sbd->gfs1 ?
|
|
Packit Service |
360c39 |
GFS2_BLKST_DINODE : GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return meta_is_good;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int alloc_data(struct gfs2_inode *ip, uint64_t metablock,
|
|
Packit Service |
360c39 |
uint64_t block, void *private,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh, uint64_t *ptr)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
const char *desc = (const char *)private;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* No need to range_check here--if it was added, it's in range. */
|
|
Packit Service |
360c39 |
/* We can't check the bitmap here because this function is called
|
|
Packit Service |
360c39 |
after the bitmap has been set but before the blockmap has. */
|
|
Packit Service |
360c39 |
q = bitmap_type(ip->i_sbd, block);
|
|
Packit Service |
360c39 |
if (q == GFS2_BLKST_FREE) {
|
|
Packit Service |
360c39 |
log_debug(_("%s reference to new data block "
|
|
Packit Service |
360c39 |
"%lld (0x%llx) is now marked as data.\n"),
|
|
Packit Service |
360c39 |
desc, (unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
gfs2_blockmap_set(bl, block, GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int alloc_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* No need to range_check here--if it was added, it's in range. */
|
|
Packit Service |
360c39 |
/* We can't check the bitmap here because this function is called
|
|
Packit Service |
360c39 |
after the bitmap has been set but before the blockmap has. */
|
|
Packit Service |
360c39 |
q = bitmap_type(ip->i_sbd, block);
|
|
Packit Service |
360c39 |
if (q == GFS2_BLKST_FREE)
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, block, _("newly allocated leaf"),
|
|
Packit Service |
360c39 |
ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE :
|
|
Packit Service |
360c39 |
GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct metawalk_fxns alloc_fxns = {
|
|
Packit Service |
360c39 |
.private = NULL,
|
|
Packit Service |
360c39 |
.check_leaf = alloc_leaf,
|
|
Packit Service |
360c39 |
.check_metalist = alloc_metalist,
|
|
Packit Service |
360c39 |
.check_data = alloc_data,
|
|
Packit Service |
360c39 |
.check_eattr_indir = NULL,
|
|
Packit Service |
360c39 |
.check_eattr_leaf = NULL,
|
|
Packit Service |
360c39 |
.check_dentry = NULL,
|
|
Packit Service |
360c39 |
.check_eattr_entry = NULL,
|
|
Packit Service |
360c39 |
.check_eattr_extentry = NULL,
|
|
Packit Service |
360c39 |
.finish_eattr_indir = NULL,
|
|
Packit Service |
360c39 |
.delete_block = delete_block,
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* pass1_check_metatree - wrapper function for check_metatree
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Generic function check_metatree sets the bitmap values, but not the
|
|
Packit Service |
360c39 |
* corresponding values in the blockmap. If we get an error, the inode will
|
|
Packit Service |
360c39 |
* have been freed in the bitmap. We need to set the inode address as free
|
|
Packit Service |
360c39 |
* as well.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int pass1_check_metatree(struct gfs2_inode *ip,
|
|
Packit Service |
360c39 |
struct metawalk_fxns *pass)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = check_metatree(ip, pass);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
gfs2_blockmap_set(bl, ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* reprocess_inode - fixes the blockmap to match the bitmap due to an
|
|
Packit Service |
360c39 |
* unexpected block allocation via libgfs2.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* The problem we're trying to overcome here is when a new block must be
|
|
Packit Service |
360c39 |
* added to a dinode because of a write. This will happen when lost+found
|
|
Packit Service |
360c39 |
* needs a new indirect block for its hash table. In that case, the write
|
|
Packit Service |
360c39 |
* causes a new block to be assigned in the bitmap but that block is not yet
|
|
Packit Service |
360c39 |
* accurately reflected in the fsck blockmap. We need to compensate here.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* We can't really use fsck_blockmap_set here because the new block
|
|
Packit Service |
360c39 |
* was already allocated by libgfs2 and therefore it took care of
|
|
Packit Service |
360c39 |
* the rgrp free space variable. fsck_blockmap_set adjusts the free space
|
|
Packit Service |
360c39 |
* in the rgrp according to the change, which has already been done.
|
|
Packit Service |
360c39 |
* So it's only our blockmap that now disagrees with the rgrp bitmap, so we
|
|
Packit Service |
360c39 |
* need to fix only that.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static void reprocess_inode(struct gfs2_inode *ip, const char *desc)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
alloc_fxns.private = (void *)desc;
|
|
Packit Service |
360c39 |
log_info( _("%s inode %llu (0x%llx) had blocks added; reprocessing "
|
|
Packit Service |
360c39 |
"its metadata tree at height=%d.\n"), desc,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
ip->i_di.di_height);
|
|
Packit Service |
360c39 |
error = pass1_check_metatree(ip, &alloc_fxns);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
log_err( _("Error %d reprocessing the %s metadata tree.\n"),
|
|
Packit Service |
360c39 |
error, desc);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* handle_ip - process an incore structure representing a dinode.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
struct block_count bc = {0};
|
|
Packit Service |
360c39 |
long bad_pointers;
|
|
Packit Service |
360c39 |
uint64_t lf_blks = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bad_pointers = 0L;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* First, check the metadata for massive amounts of pointer corruption.
|
|
Packit Service |
360c39 |
Such corruption can only lead us to ruin trying to clean it up,
|
|
Packit Service |
360c39 |
so it's better to check it up front and delete the inode if
|
|
Packit Service |
360c39 |
there is corruption. */
|
|
Packit Service |
360c39 |
rangecheck_fxns.private = &bad_pointers;
|
|
Packit Service |
360c39 |
error = pass1_check_metatree(ip, &rangecheck_fxns);
|
|
Packit Service |
360c39 |
if (bad_pointers > BAD_POINTER_TOLERANCE) {
|
|
Packit Service |
360c39 |
log_err( _("Error: inode %llu (0x%llx) has more than "
|
|
Packit Service |
360c39 |
"%d bad pointers.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
BAD_POINTER_TOLERANCE);
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
_("badly corrupt"), GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = set_ip_blockmap(ip);
|
|
Packit Service |
360c39 |
if (error == -EINVAL) {
|
|
Packit Service |
360c39 |
/* We found a dinode that has an invalid mode. At this point
|
|
Packit Service |
360c39 |
set_ip_blockmap returned an error, which means it never
|
|
Packit Service |
360c39 |
got inserted into the inode tree. Since we haven't even
|
|
Packit Service |
360c39 |
processed its metadata with pass1_fxns, none of its
|
|
Packit Service |
360c39 |
metadata will be flagged as metadata or data blocks yet.
|
|
Packit Service |
360c39 |
Therefore, we don't need to invalidate anything. */
|
|
Packit Service |
360c39 |
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
_("invalid mode"), GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
} else if (error)
|
|
Packit Service |
360c39 |
goto bad_dinode;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (set_di_nlink(ip))
|
|
Packit Service |
360c39 |
goto bad_dinode;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (lf_dip)
|
|
Packit Service |
360c39 |
lf_blks = lf_dip->i_di.di_blocks;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
pass1_fxns.private = &bc;
|
|
Packit Service |
360c39 |
error = pass1_check_metatree(ip, &pass1_fxns);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Pass1 may have added some blocks to lost+found by virtue of leafs
|
|
Packit Service |
360c39 |
that were misplaced. If it did, we need to reprocess lost+found
|
|
Packit Service |
360c39 |
to correctly account for its blocks. */
|
|
Packit Service |
360c39 |
if (lf_dip && lf_dip->i_di.di_blocks != lf_blks)
|
|
Packit Service |
360c39 |
reprocess_inode(lf_dip, "lost+found");
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* We there was an error, we return 0 because we want fsck to continue
|
|
Packit Service |
360c39 |
and analyze the other dinodes as well. */
|
|
Packit Service |
360c39 |
if (fsck_abort)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!error) {
|
|
Packit Service |
360c39 |
error = check_inode_eattr(ip, &pass1_fxns);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
if (!query(_("Clear the bad Extended Attributes? "
|
|
Packit Service |
360c39 |
"(y/n) "))) {
|
|
Packit Service |
360c39 |
log_err( _("The bad Extended Attributes were "
|
|
Packit Service |
360c39 |
"not fixed.\n"));
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_err(_("Clearing the bad Extended Attributes in "
|
|
Packit Service |
360c39 |
"inode %lld (0x%llx).\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
eattr_undo_fxns.private = &bc;
|
|
Packit Service |
360c39 |
check_inode_eattr(ip, &eattr_undo_fxns);
|
|
Packit Service |
360c39 |
ask_remove_inode_eattr(ip, &bc);
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (ip->i_di.di_blocks !=
|
|
Packit Service |
360c39 |
(1 + bc.indir_count + bc.data_count + bc.ea_count)) {
|
|
Packit Service |
360c39 |
log_err( _("Inode #%llu (0x%llx): Ondisk block count (%llu"
|
|
Packit Service |
360c39 |
") does not match what fsck found (%llu)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_blocks,
|
|
Packit Service |
360c39 |
(unsigned long long)1 + bc.indir_count +
|
|
Packit Service |
360c39 |
bc.data_count + bc.ea_count);
|
|
Packit Service |
360c39 |
log_info( _("inode has: %lld, but fsck counts: Dinode:1 + "
|
|
Packit Service |
360c39 |
"indir:%lld + data: %lld + ea: %lld\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_blocks,
|
|
Packit Service |
360c39 |
(unsigned long long)bc.indir_count,
|
|
Packit Service |
360c39 |
(unsigned long long)bc.data_count,
|
|
Packit Service |
360c39 |
(unsigned long long)bc.ea_count);
|
|
Packit Service |
360c39 |
if (query( _("Fix ondisk block count? (y/n) "))) {
|
|
Packit Service |
360c39 |
ip->i_di.di_blocks = 1 + bc.indir_count + bc.data_count +
|
|
Packit Service |
360c39 |
bc.ea_count;
|
|
Packit Service |
360c39 |
bmodified(ip->i_bh);
|
|
Packit Service |
360c39 |
log_err( _("Block count for #%llu (0x%llx) fixed\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
} else
|
|
Packit Service |
360c39 |
log_err( _("Bad block count for #%llu (0x%llx"
|
|
Packit Service |
360c39 |
") not fixed\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
bad_dinode:
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void check_i_goal(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if (sdp->gfs1 || ip->i_di.di_flags & GFS2_DIF_SYSTEM)
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (ip->i_di.di_goal_meta <= LGFS2_SB_ADDR(sdp) ||
|
|
Packit Service |
360c39 |
ip->i_di.di_goal_meta > sdp->fssize) {
|
|
Packit Service |
360c39 |
log_err(_("Inode #%llu (0x%llx): Bad allocation goal block "
|
|
Packit Service |
360c39 |
"found: %llu (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_goal_meta,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_goal_meta);
|
|
Packit Service |
360c39 |
if (query( _("Fix goal block in inode #%llu (0x%llx)? (y/n) "),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr)) {
|
|
Packit Service |
360c39 |
ip->i_di.di_goal_meta = ip->i_di.di_num.no_addr;
|
|
Packit Service |
360c39 |
bmodified(ip->i_bh);
|
|
Packit Service |
360c39 |
} else
|
|
Packit Service |
360c39 |
log_err(_("Allocation goal block in inode #%lld "
|
|
Packit Service |
360c39 |
"(0x%llx) not fixed\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* handle_di - This is now a wrapper function that takes a gfs2_buffer_head
|
|
Packit Service |
360c39 |
* and calls handle_ip, which takes an in-code dinode structure.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int handle_di(struct gfs2_sbd *sdp, struct rgrp_tree *rgd,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int error = 0;
|
|
Packit Service |
360c39 |
uint64_t block = bh->b_blocknr;
|
|
Packit Service |
360c39 |
struct gfs2_inode *ip;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ip = fsck_inode_get(sdp, rgd, bh);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (ip->i_di.di_num.no_addr != block) {
|
|
Packit Service |
360c39 |
log_err( _("Inode #%llu (0x%llx): Bad inode address found: %llu "
|
|
Packit Service |
360c39 |
"(0x%llx)\n"), (unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if (query( _("Fix address in inode at block #%llu"
|
|
Packit Service |
360c39 |
" (0x%llx)? (y/n) "),
|
|
Packit Service |
360c39 |
(unsigned long long)block, (unsigned long long)block)) {
|
|
Packit Service |
360c39 |
ip->i_di.di_num.no_addr = ip->i_di.di_num.no_formal_ino = block;
|
|
Packit Service |
360c39 |
bmodified(ip->i_bh);
|
|
Packit Service |
360c39 |
} else
|
|
Packit Service |
360c39 |
log_err( _("Address in inode at block #%llu"
|
|
Packit Service |
360c39 |
" (0x%llx) not fixed\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (sdp->gfs1 && ip->i_di.di_num.no_formal_ino != block) {
|
|
Packit Service |
360c39 |
log_err( _("Inode #%llu (0x%llx): GFS1 formal inode number "
|
|
Packit Service |
360c39 |
"mismatch: was %llu (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block, (unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_formal_ino,
|
|
Packit Service |
360c39 |
(unsigned long long)ip->i_di.di_num.no_formal_ino);
|
|
Packit Service |
360c39 |
if (query( _("Fix formal inode number in inode #%llu"
|
|
Packit Service |
360c39 |
" (0x%llx)? (y/n) "), (unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block)) {
|
|
Packit Service |
360c39 |
ip->i_di.di_num.no_formal_ino = block;
|
|
Packit Service |
360c39 |
bmodified(ip->i_bh);
|
|
Packit Service |
360c39 |
} else
|
|
Packit Service |
360c39 |
log_err( _("Inode number in inode at block #%lld "
|
|
Packit Service |
360c39 |
"(0x%llx) not fixed\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
check_i_goal(sdp, ip);
|
|
Packit Service |
360c39 |
error = handle_ip(sdp, ip);
|
|
Packit Service |
360c39 |
fsck_inode_put(&ip);
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Check system inode and verify it's marked "in use" in the bitmap: */
|
|
Packit Service |
360c39 |
/* Should work for all system inodes: root, master, jindex, per_node, etc. */
|
|
Packit Service |
360c39 |
/* We have to pass the sysinode as ** because the pointer may change out from
|
|
Packit Service |
360c39 |
under the reference by way of the builder() function. */
|
|
Packit Service |
360c39 |
static int check_system_inode(struct gfs2_sbd *sdp,
|
|
Packit Service |
360c39 |
struct gfs2_inode **sysinode,
|
|
Packit Service |
360c39 |
const char *filename,
|
|
Packit Service |
360c39 |
int builder(struct gfs2_sbd *sdp), int isdir,
|
|
Packit Service |
360c39 |
struct gfs2_inode *sysdir, int needs_sysbit)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t iblock = 0;
|
|
Packit Service |
360c39 |
struct dir_status ds = {0};
|
|
Packit Service |
360c39 |
int error, err = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_info( _("Checking system inode '%s'\n"), filename);
|
|
Packit Service |
360c39 |
if (*sysinode) {
|
|
Packit Service |
360c39 |
/* Read in the system inode, look at its dentries, and start
|
|
Packit Service |
360c39 |
* reading through them */
|
|
Packit Service |
360c39 |
iblock = (*sysinode)->i_di.di_num.no_addr;
|
|
Packit Service |
360c39 |
log_info( _("System inode for '%s' is located at block %llu"
|
|
Packit Service |
360c39 |
" (0x%llx)\n"), filename,
|
|
Packit Service |
360c39 |
(unsigned long long)iblock,
|
|
Packit Service |
360c39 |
(unsigned long long)iblock);
|
|
Packit Service |
360c39 |
if (gfs2_check_meta((*sysinode)->i_bh, GFS2_METATYPE_DI)) {
|
|
Packit Service |
360c39 |
log_err( _("Found invalid system dinode at block #"
|
|
Packit Service |
360c39 |
"%llu (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)iblock,
|
|
Packit Service |
360c39 |
(unsigned long long)iblock);
|
|
Packit Service |
360c39 |
gfs2_blockmap_set(bl, iblock, GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
check_n_fix_bitmap(sdp, (*sysinode)->i_rgd, iblock, 0,
|
|
Packit Service |
360c39 |
GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
inode_put(sysinode);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (*sysinode) {
|
|
Packit Service |
360c39 |
ds.q = block_type(bl, iblock);
|
|
Packit Service |
360c39 |
/* If the inode exists but the block is marked free, we might
|
|
Packit Service |
360c39 |
be recovering from a corrupt bitmap. In that case, don't
|
|
Packit Service |
360c39 |
rebuild the inode. Just reuse the inode and fix the
|
|
Packit Service |
360c39 |
bitmap. */
|
|
Packit Service |
360c39 |
if (ds.q == GFS2_BLKST_FREE) {
|
|
Packit Service |
360c39 |
log_info( _("The inode exists but the block is not "
|
|
Packit Service |
360c39 |
"marked 'in use'; fixing it.\n"));
|
|
Packit Service |
360c39 |
fsck_blockmap_set(*sysinode,
|
|
Packit Service |
360c39 |
(*sysinode)->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
filename, GFS2_BLKST_DINODE);
|
|
Packit Service |
360c39 |
ds.q = GFS2_BLKST_DINODE;
|
|
Packit Service |
360c39 |
if (isdir)
|
|
Packit Service |
360c39 |
dirtree_insert((*sysinode)->i_di.di_num);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Make sure it's marked as a system file/directory */
|
|
Packit Service |
360c39 |
if (needs_sysbit &&
|
|
Packit Service |
360c39 |
!((*sysinode)->i_di.di_flags & GFS2_DIF_SYSTEM)) {
|
|
Packit Service |
360c39 |
log_err( _("System inode %s is missing the 'system' "
|
|
Packit Service |
360c39 |
"flag. It should be rebuilt.\n"), filename);
|
|
Packit Service |
360c39 |
if (sysdir && query(_("Delete the corrupt %s system "
|
|
Packit Service |
360c39 |
"inode? (y/n) "), filename)) {
|
|
Packit Service |
360c39 |
inode_put(sysinode);
|
|
Packit Service |
360c39 |
gfs2_dirent_del(sysdir, filename,
|
|
Packit Service |
360c39 |
strlen(filename));
|
|
Packit Service |
360c39 |
/* Set the blockmap (but not bitmap) back to
|
|
Packit Service |
360c39 |
'free' so that it gets checked like any
|
|
Packit Service |
360c39 |
normal dinode. */
|
|
Packit Service |
360c39 |
gfs2_blockmap_set(bl, iblock, GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
log_err( _("Removed system inode \"%s\".\n"),
|
|
Packit Service |
360c39 |
filename);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
} else
|
|
Packit Service |
360c39 |
log_info( _("System inode for '%s' is corrupt or missing.\n"),
|
|
Packit Service |
360c39 |
filename);
|
|
Packit Service |
360c39 |
/* If there are errors with the inode here, we need to create a new
|
|
Packit Service |
360c39 |
inode and get it all setup - of course, everything will be in
|
|
Packit Service |
360c39 |
lost+found then, but we *need* our system inodes before we can
|
|
Packit Service |
360c39 |
do any of that. */
|
|
Packit Service |
360c39 |
if (!(*sysinode) || ds.q != GFS2_BLKST_DINODE) {
|
|
Packit Service |
360c39 |
log_err(_("Invalid or missing %s system inode (is '%s', "
|
|
Packit Service |
360c39 |
"should be '%s').\n"), filename,
|
|
Packit Service |
360c39 |
block_type_string(ds.q),
|
|
Packit Service |
360c39 |
block_type_string(GFS2_BLKST_DINODE));
|
|
Packit Service |
360c39 |
if (query(_("Create new %s system inode? (y/n) "), filename)) {
|
|
Packit Service |
360c39 |
log_err( _("Rebuilding system file \"%s\"\n"),
|
|
Packit Service |
360c39 |
filename);
|
|
Packit Service |
360c39 |
error = builder(sdp);
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
log_err( _("Error rebuilding system "
|
|
Packit Service |
360c39 |
"inode %s: Cannot continue\n"),
|
|
Packit Service |
360c39 |
filename);
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (*sysinode == sdp->md.jiinode)
|
|
Packit Service |
360c39 |
ji_update(sdp);
|
|
Packit Service |
360c39 |
fsck_blockmap_set(*sysinode,
|
|
Packit Service |
360c39 |
(*sysinode)->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
filename, GFS2_BLKST_DINODE);
|
|
Packit Service |
360c39 |
ds.q = GFS2_BLKST_DINODE;
|
|
Packit Service |
360c39 |
if (isdir)
|
|
Packit Service |
360c39 |
dirtree_insert((*sysinode)->i_di.di_num);
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
log_err( _("Cannot continue without valid %s inode\n"),
|
|
Packit Service |
360c39 |
filename);
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (is_dir(&(*sysinode)->i_di, sdp->gfs1)) {
|
|
Packit Service |
360c39 |
struct block_count bc = {0};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
sysdir_fxns.private = &bc;
|
|
Packit Service |
360c39 |
if ((*sysinode)->i_di.di_flags & GFS2_DIF_EXHASH)
|
|
Packit Service |
360c39 |
pass1_check_metatree(*sysinode, &sysdir_fxns);
|
|
Packit Service |
360c39 |
else {
|
|
Packit Service |
360c39 |
err = check_linear_dir(*sysinode, (*sysinode)->i_bh,
|
|
Packit Service |
360c39 |
&sysdir_fxns);
|
|
Packit Service |
360c39 |
/* If we encountered an error in our directory check
|
|
Packit Service |
360c39 |
we should still call handle_ip, but return the
|
|
Packit Service |
360c39 |
error later. */
|
|
Packit Service |
360c39 |
if (err)
|
|
Packit Service |
360c39 |
log_err(_("Error found in %s while checking "
|
|
Packit Service |
360c39 |
"directory entries.\n"), filename);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
check_i_goal(sdp, *sysinode);
|
|
Packit Service |
360c39 |
error = handle_ip(sdp, *sysinode);
|
|
Packit Service |
360c39 |
return error ? error : err;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int build_a_journal(struct gfs2_sbd *sdp)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
char name[256];
|
|
Packit Service |
360c39 |
int err = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* First, try to delete the journal if it's in jindex */
|
|
Packit Service |
360c39 |
sprintf(name, "journal%u", sdp->md.journals);
|
|
Packit Service |
360c39 |
gfs2_dirent_del(sdp->md.jiinode, name, strlen(name));
|
|
Packit Service |
360c39 |
/* Now rebuild it */
|
|
Packit Service |
360c39 |
err = build_journal(sdp, sdp->md.journals, sdp->md.jiinode);
|
|
Packit Service |
360c39 |
if (err) {
|
|
Packit Service |
360c39 |
log_crit(_("Error %d building journal\n"), err);
|
|
Packit Service |
360c39 |
exit(FSCK_ERROR);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int check_system_inodes(struct gfs2_sbd *sdp)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int journal_count;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*******************************************************************
|
|
Packit Service |
360c39 |
******* Check the system inode integrity *************
|
|
Packit Service |
360c39 |
*******************************************************************/
|
|
Packit Service |
360c39 |
/* Mark the master system dinode as a "dinode" in the block map.
|
|
Packit Service |
360c39 |
All other system dinodes in master will be taken care of by function
|
|
Packit Service |
360c39 |
resuscitate_metalist. But master won't since it has no parent.*/
|
|
Packit Service |
360c39 |
if (!sdp->gfs1) {
|
|
Packit Service |
360c39 |
fsck_blockmap_set(sdp->master_dir,
|
|
Packit Service |
360c39 |
sdp->master_dir->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
"master", GFS2_BLKST_DINODE);
|
|
Packit Service |
360c39 |
if (check_system_inode(sdp, &sdp->master_dir, "master",
|
|
Packit Service |
360c39 |
build_master, 1, NULL, 1)) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Mark the root dinode as a "dinode" in the block map as we did
|
|
Packit Service |
360c39 |
for master, since it has no parent. */
|
|
Packit Service |
360c39 |
fsck_blockmap_set(sdp->md.rooti, sdp->md.rooti->i_di.di_num.no_addr,
|
|
Packit Service |
360c39 |
"root", GFS2_BLKST_DINODE);
|
|
Packit Service |
360c39 |
if (check_system_inode(sdp, &sdp->md.rooti, "root", build_root, 1,
|
|
Packit Service |
360c39 |
NULL, 0)) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!sdp->gfs1 &&
|
|
Packit Service |
360c39 |
check_system_inode(sdp, &sdp->md.inum, "inum", build_inum, 0,
|
|
Packit Service |
360c39 |
sdp->master_dir, 1)) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (check_system_inode(sdp, &sdp->md.statfs, "statfs", build_statfs, 0,
|
|
Packit Service |
360c39 |
sdp->master_dir, !sdp->gfs1)) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (check_system_inode(sdp, &sdp->md.jiinode, "jindex", build_jindex,
|
|
Packit Service |
360c39 |
(sdp->gfs1 ? 0 : 1), sdp->master_dir,
|
|
Packit Service |
360c39 |
!sdp->gfs1)) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (check_system_inode(sdp, &sdp->md.riinode, "rindex", build_rindex,
|
|
Packit Service |
360c39 |
0, sdp->master_dir, !sdp->gfs1)) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (check_system_inode(sdp, &sdp->md.qinode, "quota", build_quota,
|
|
Packit Service |
360c39 |
0, sdp->master_dir, !sdp->gfs1)) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!sdp->gfs1 &&
|
|
Packit Service |
360c39 |
check_system_inode(sdp, &sdp->md.pinode, "per_node",
|
|
Packit Service |
360c39 |
build_per_node, 1, sdp->master_dir, 1)) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* We have to play a trick on build_journal: We swap md.journals
|
|
Packit Service |
360c39 |
in order to keep a count of which journal we need to build. */
|
|
Packit Service |
360c39 |
journal_count = sdp->md.journals;
|
|
Packit Service |
360c39 |
/* gfs1's journals aren't dinode, they're just a bunch of blocks. */
|
|
Packit Service |
360c39 |
if (sdp->gfs1) {
|
|
Packit Service |
360c39 |
/* gfs1 has four dinodes that are set in the superblock and
|
|
Packit Service |
360c39 |
therefore not linked to anything else. We need to adjust
|
|
Packit Service |
360c39 |
the link counts so pass4 doesn't get confused. */
|
|
Packit Service |
360c39 |
incr_link_count(sdp->md.statfs->i_di.di_num, NULL,
|
|
Packit Service |
360c39 |
_("gfs1 statfs inode"));
|
|
Packit Service |
360c39 |
incr_link_count(sdp->md.jiinode->i_di.di_num, NULL,
|
|
Packit Service |
360c39 |
_("gfs1 jindex inode"));
|
|
Packit Service |
360c39 |
incr_link_count(sdp->md.riinode->i_di.di_num, NULL,
|
|
Packit Service |
360c39 |
_("gfs1 rindex inode"));
|
|
Packit Service |
360c39 |
incr_link_count(sdp->md.qinode->i_di.di_num, NULL,
|
|
Packit Service |
360c39 |
_("gfs1 quota inode"));
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
for (sdp->md.journals = 0; sdp->md.journals < journal_count;
|
|
Packit Service |
360c39 |
sdp->md.journals++) {
|
|
Packit Service |
360c39 |
char jname[16];
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
sprintf(jname, "journal%d", sdp->md.journals);
|
|
Packit Service |
360c39 |
if (check_system_inode(sdp, &sdp->md.journal[sdp->md.journals],
|
|
Packit Service |
360c39 |
jname, build_a_journal, 0,
|
|
Packit Service |
360c39 |
sdp->md.jiinode, 1)) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int pass1_process_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, uint64_t *ibuf, unsigned n)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
unsigned i;
|
|
Packit Service |
360c39 |
uint64_t block;
|
|
Packit Service |
360c39 |
struct gfs2_inode *ip;
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
/* Readahead numbers arrived at by experiment */
|
|
Packit Service |
360c39 |
unsigned rawin = 50;
|
|
Packit Service |
360c39 |
unsigned ralen = 100 * sdp->bsize;
|
|
Packit Service |
360c39 |
unsigned r = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (i = 0; i < n; i++) {
|
|
Packit Service |
360c39 |
int is_inode;
|
|
Packit Service |
360c39 |
uint32_t check_magic;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
block = ibuf[i];
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (r++ == rawin) {
|
|
Packit Service |
360c39 |
posix_fadvise(sdp->device_fd, block * sdp->bsize, ralen, POSIX_FADV_WILLNEED);
|
|
Packit Service |
360c39 |
r = 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* skip gfs1 rindex indirect blocks */
|
|
Packit Service |
360c39 |
if (sdp->gfs1 && blockfind(&gfs1_rindex_blks, block)) {
|
|
Packit Service |
360c39 |
log_debug(_("Skipping rindex indir block "
|
|
Packit Service |
360c39 |
"%lld (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
warm_fuzzy_stuff(block);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (fsck_abort) { /* if asked to abort */
|
|
Packit Service |
360c39 |
gfs2_special_free(&gfs1_rindex_blks);
|
|
Packit Service |
360c39 |
return FSCK_OK;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (skip_this_pass) {
|
|
Packit Service |
360c39 |
printf( _("Skipping pass 1 is not a good idea.\n"));
|
|
Packit Service |
360c39 |
skip_this_pass = FALSE;
|
|
Packit Service |
360c39 |
fflush(stdout);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (fsck_system_inode(sdp, block)) {
|
|
Packit Service |
360c39 |
log_debug(_("Already processed system inode "
|
|
Packit Service |
360c39 |
"%lld (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bh = bread(sdp, block);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
is_inode = 0;
|
|
Packit Service |
360c39 |
if (gfs2_check_meta(bh, GFS2_METATYPE_DI) == 0)
|
|
Packit Service |
360c39 |
is_inode = 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
check_magic = ((struct gfs2_meta_header *)
|
|
Packit Service |
360c39 |
(bh->b_data))->mh_magic;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
q = block_type(bl, block);
|
|
Packit Service |
360c39 |
if (q != GFS2_BLKST_FREE) {
|
|
Packit Service |
360c39 |
if (be32_to_cpu(check_magic) == GFS2_MAGIC &&
|
|
Packit Service |
360c39 |
sdp->gfs1 && !is_inode) {
|
|
Packit Service |
360c39 |
log_debug(_("Block 0x%llx assumed to be "
|
|
Packit Service |
360c39 |
"previously processed GFS1 "
|
|
Packit Service |
360c39 |
"non-dinode metadata.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_err( _("Found a duplicate inode block at #%llu "
|
|
Packit Service |
360c39 |
"(0x%llx) previously marked as a %s\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
block_type_string(q));
|
|
Packit Service |
360c39 |
ip = fsck_inode_get(sdp, rgd, bh);
|
|
Packit Service |
360c39 |
if (is_inode && ip->i_di.di_num.no_addr == block)
|
|
Packit Service |
360c39 |
add_duplicate_ref(ip, block, ref_is_inode, 0,
|
|
Packit Service |
360c39 |
INODE_VALID);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
log_info(_("dinum.no_addr is wrong, so I "
|
|
Packit Service |
360c39 |
"assume the bitmap is just "
|
|
Packit Service |
360c39 |
"wrong.\n"));
|
|
Packit Service |
360c39 |
fsck_inode_put(&ip);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!is_inode) {
|
|
Packit Service |
360c39 |
if (be32_to_cpu(check_magic) == GFS2_MAGIC) {
|
|
Packit Service |
360c39 |
/* In gfs2, a bitmap mark of 2 means an inode,
|
|
Packit Service |
360c39 |
but in gfs1 it means any metadata. So if
|
|
Packit Service |
360c39 |
this is gfs1 and not an inode, it may be
|
|
Packit Service |
360c39 |
okay. If it's non-dinode metadata, it will
|
|
Packit Service |
360c39 |
be referenced by an inode, so we need to
|
|
Packit Service |
360c39 |
skip it here and it will be sorted out
|
|
Packit Service |
360c39 |
when the referencing inode is checked. */
|
|
Packit Service |
360c39 |
if (sdp->gfs1) {
|
|
Packit Service |
360c39 |
log_debug( _("Deferring GFS1 "
|
|
Packit Service |
360c39 |
"metadata block #"
|
|
Packit Service |
360c39 |
"%" PRIu64" (0x%"
|
|
Packit Service |
360c39 |
PRIx64 ")\n"),
|
|
Packit Service |
360c39 |
block, block);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_err( _("Found invalid inode at block #"
|
|
Packit Service |
360c39 |
"%llu (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
check_n_fix_bitmap(sdp, rgd, block, 0,
|
|
Packit Service |
360c39 |
GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
} else if (handle_di(sdp, rgd, bh) < 0) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
gfs2_special_free(&gfs1_rindex_blks);
|
|
Packit Service |
360c39 |
return FSCK_ERROR;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Ignore everything else - they should be hit by the
|
|
Packit Service |
360c39 |
handle_di step. Don't check NONE either, because
|
|
Packit Service |
360c39 |
check_meta passes everything if GFS2_METATYPE_NONE
|
|
Packit Service |
360c39 |
is specified. Hopefully, other metadata types such
|
|
Packit Service |
360c39 |
as indirect blocks will be handled when the inode
|
|
Packit Service |
360c39 |
itself is processed, and if it's not, it should be
|
|
Packit Service |
360c39 |
caught in pass5. */
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int pass1_process_rgrp(struct gfs2_sbd *sdp, struct rgrp_tree *rgd)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
unsigned k, n, i;
|
|
Packit Service |
360c39 |
uint64_t *ibuf = malloc(sdp->bsize * GFS2_NBBY * sizeof(uint64_t));
|
|
Packit Service |
360c39 |
int ret = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (ibuf == NULL)
|
|
Packit Service |
360c39 |
return FSCK_ERROR;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (k = 0; k < rgd->ri.ri_length; k++) {
|
|
Packit Service |
360c39 |
n = lgfs2_bm_scan(rgd, k, ibuf, GFS2_BLKST_DINODE);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (n) {
|
|
Packit Service |
360c39 |
ret = pass1_process_bitmap(sdp, rgd, ibuf, n);
|
|
Packit Service |
360c39 |
if (ret)
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (fsck_abort)
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
For GFS1, we have to count the "free meta" blocks in the
|
|
Packit Service |
360c39 |
resource group and mark them specially so we can count them
|
|
Packit Service |
360c39 |
properly in pass5.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
if (!sdp->gfs1)
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
n = lgfs2_bm_scan(rgd, k, ibuf, GFS2_BLKST_UNLINKED);
|
|
Packit Service |
360c39 |
for (i = 0; i < n; i++) {
|
|
Packit Service |
360c39 |
gfs2_blockmap_set(bl, ibuf[i], GFS2_BLKST_UNLINKED);
|
|
Packit Service |
360c39 |
if (fsck_abort)
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
out:
|
|
Packit Service |
360c39 |
free(ibuf);
|
|
Packit Service |
360c39 |
return ret;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int gfs2_blockmap_create(struct gfs2_bmap *bmap, uint64_t size)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
bmap->size = size;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Have to add 1 to BLOCKMAP_SIZE since it's 0-based and mallocs
|
|
Packit Service |
360c39 |
* must be 1-based */
|
|
Packit Service |
360c39 |
bmap->mapsize = BLOCKMAP_SIZE2(size) + 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!(bmap->map = calloc(bmap->mapsize, sizeof(char))))
|
|
Packit Service |
360c39 |
return -ENOMEM;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int link1_create(struct gfs2_bmap *bmap, uint64_t size)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
bmap->size = size;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Have to add 1 to BLOCKMAP_SIZE since it's 0-based and mallocs
|
|
Packit Service |
360c39 |
* must be 1-based */
|
|
Packit Service |
360c39 |
bmap->mapsize = BLOCKMAP_SIZE1(size) + 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!(bmap->map = calloc(bmap->mapsize, sizeof(char))))
|
|
Packit Service |
360c39 |
return -ENOMEM;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size,
|
|
Packit Service |
360c39 |
uint64_t *addl_mem_needed)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_bmap *il;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*addl_mem_needed = 0L;
|
|
Packit Service |
360c39 |
il = calloc(1, sizeof(*il));
|
|
Packit Service |
360c39 |
if (!il)
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (gfs2_blockmap_create(il, size)) {
|
|
Packit Service |
360c39 |
*addl_mem_needed = il->mapsize;
|
|
Packit Service |
360c39 |
free(il);
|
|
Packit Service |
360c39 |
il = NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return il;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void gfs2_blockmap_destroy(struct gfs2_bmap *bmap)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if (bmap->map)
|
|
Packit Service |
360c39 |
free(bmap->map);
|
|
Packit Service |
360c39 |
bmap->size = 0;
|
|
Packit Service |
360c39 |
bmap->mapsize = 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void *gfs2_bmap_destroy(struct gfs2_sbd *sdp, struct gfs2_bmap *il)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if (il) {
|
|
Packit Service |
360c39 |
gfs2_blockmap_destroy(il);
|
|
Packit Service |
360c39 |
free(il);
|
|
Packit Service |
360c39 |
il = NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return il;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void enomem(uint64_t addl_mem_needed)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
log_crit( _("This system doesn't have enough memory and swap space to fsck this file system.\n"));
|
|
Packit Service |
360c39 |
log_crit( _("Additional memory needed is approximately: %lluMB\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)(addl_mem_needed / 1048576ULL));
|
|
Packit Service |
360c39 |
log_crit( _("Please increase your swap space by that amount and run fsck.gfs2 again.\n"));
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* pass1 - walk through inodes and check inode state
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* this walk can be done using root inode and depth first search,
|
|
Packit Service |
360c39 |
* watching for repeat inode numbers
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* format & type
|
|
Packit Service |
360c39 |
* link count
|
|
Packit Service |
360c39 |
* duplicate blocks
|
|
Packit Service |
360c39 |
* bad blocks
|
|
Packit Service |
360c39 |
* inodes size
|
|
Packit Service |
360c39 |
* dir info
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int pass1(struct gfs2_sbd *sdp)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct osi_node *n, *next = NULL;
|
|
Packit Service |
360c39 |
struct rgrp_tree *rgd;
|
|
Packit Service |
360c39 |
uint64_t i;
|
|
Packit Service |
360c39 |
uint64_t rg_count = 0;
|
|
Packit Service |
360c39 |
struct timeval timer;
|
|
Packit Service |
360c39 |
int ret = FSCK_OK;
|
|
Packit Service |
360c39 |
uint64_t addl_mem_needed;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bl = gfs2_bmap_create(sdp, last_fs_block+1, &addl_mem_needed);
|
|
Packit Service |
360c39 |
if (!bl) {
|
|
Packit Service |
360c39 |
enomem(addl_mem_needed);
|
|
Packit Service |
360c39 |
return FSCK_ERROR;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
addl_mem_needed = link1_create(&nlink1map, last_fs_block+1);
|
|
Packit Service |
360c39 |
if (addl_mem_needed) {
|
|
Packit Service |
360c39 |
enomem(addl_mem_needed);
|
|
Packit Service |
360c39 |
gfs2_bmap_destroy(sdp, bl);
|
|
Packit Service |
360c39 |
return FSCK_ERROR;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
addl_mem_needed = link1_create(&clink1map, last_fs_block+1);
|
|
Packit Service |
360c39 |
if (addl_mem_needed) {
|
|
Packit Service |
360c39 |
enomem(addl_mem_needed);
|
|
Packit Service |
360c39 |
link1_destroy(&nlink1map);
|
|
Packit Service |
360c39 |
gfs2_bmap_destroy(sdp, bl);
|
|
Packit Service |
360c39 |
return FSCK_ERROR;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
osi_list_init(&gfs1_rindex_blks.list);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* FIXME: In the gfs fsck, we had to mark things like the
|
|
Packit Service |
360c39 |
* journals and indices and such as 'other_meta' - in gfs2,
|
|
Packit Service |
360c39 |
* the journals are files and are found in the normal file
|
|
Packit Service |
360c39 |
* sweep - is there any metadata we need to mark here before
|
|
Packit Service |
360c39 |
* the sweeps start that we won't find otherwise? */
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Make sure the system inodes are okay & represented in the bitmap. */
|
|
Packit Service |
360c39 |
check_system_inodes(sdp);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* So, do we do a depth first search starting at the root
|
|
Packit Service |
360c39 |
* inode, or use the rg bitmaps, or just read every fs block
|
|
Packit Service |
360c39 |
* to find the inodes? If we use the depth first search, why
|
|
Packit Service |
360c39 |
* have pass3 at all - if we use the rg bitmaps, pass5 is at
|
|
Packit Service |
360c39 |
* least partially invalidated - if we read every fs block,
|
|
Packit Service |
360c39 |
* things will probably be intolerably slow. The current fsck
|
|
Packit Service |
360c39 |
* uses the rg bitmaps, so maybe that's the best way to start
|
|
Packit Service |
360c39 |
* things - we can change the method later if necessary.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
for (n = osi_first(&sdp->rgtree); n; n = next, rg_count++) {
|
|
Packit Service |
360c39 |
if (fsck_abort) {
|
|
Packit Service |
360c39 |
ret = FSCK_CANCELED;
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
next = osi_next(n);
|
|
Packit Service |
360c39 |
log_debug( _("Checking metadata in Resource Group #%llu\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)rg_count);
|
|
Packit Service |
360c39 |
rgd = (struct rgrp_tree *)n;
|
|
Packit Service |
360c39 |
for (i = 0; i < rgd->ri.ri_length; i++) {
|
|
Packit Service |
360c39 |
log_debug( _("rgrp block %lld (0x%llx) "
|
|
Packit Service |
360c39 |
"is now marked as 'rgrp data'\n"),
|
|
Packit Service |
360c39 |
rgd->ri.ri_addr + i, rgd->ri.ri_addr + i);
|
|
Packit Service |
360c39 |
if (gfs2_blockmap_set(bl, rgd->ri.ri_addr + i,
|
|
Packit Service |
360c39 |
GFS2_BLKST_USED)) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
gfs2_special_free(&gfs1_rindex_blks);
|
|
Packit Service |
360c39 |
ret = FSCK_ERROR;
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* rgrps and bitmaps don't have bits to represent
|
|
Packit Service |
360c39 |
their blocks, so don't do this:
|
|
Packit Service |
360c39 |
check_n_fix_bitmap(sdp, rgd, rgd->ri.ri_addr + i, 0,
|
|
Packit Service |
360c39 |
gfs2_meta_rgrp);*/
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ret = pass1_process_rgrp(sdp, rgd);
|
|
Packit Service |
360c39 |
if (ret)
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_notice(_("Reconciling bitmaps.\n"));
|
|
Packit Service |
360c39 |
gettimeofday(&timer, NULL);
|
|
Packit Service |
360c39 |
pass5(sdp, bl);
|
|
Packit Service |
360c39 |
print_pass_duration("reconcile_bitmaps", &timer;;
|
|
Packit Service |
360c39 |
out:
|
|
Packit Service |
360c39 |
gfs2_special_free(&gfs1_rindex_blks);
|
|
Packit Service |
360c39 |
if (bl)
|
|
Packit Service |
360c39 |
gfs2_bmap_destroy(sdp, bl);
|
|
Packit Service |
360c39 |
return ret;
|
|
Packit Service |
360c39 |
}
|