|
Packit Service |
360c39 |
#include "clusterautoconfig.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include <errno.h>
|
|
Packit Service |
360c39 |
#include <inttypes.h>
|
|
Packit Service |
360c39 |
#include <stdlib.h>
|
|
Packit Service |
360c39 |
#include <string.h>
|
|
Packit Service |
360c39 |
#include <time.h>
|
|
Packit Service |
360c39 |
#include <unistd.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 "fsck.h"
|
|
Packit Service |
360c39 |
#include "fs_recovery.h"
|
|
Packit Service |
360c39 |
#include "libgfs2.h"
|
|
Packit Service |
360c39 |
#include "metawalk.h"
|
|
Packit Service |
360c39 |
#include "util.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#define JOURNAL_NAME_SIZE 18
|
|
Packit Service |
360c39 |
#define JOURNAL_SEQ_TOLERANCE 10
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
unsigned int sd_found_jblocks = 0, sd_replayed_jblocks = 0;
|
|
Packit Service |
360c39 |
unsigned int sd_found_metablocks = 0, sd_replayed_metablocks = 0;
|
|
Packit Service |
360c39 |
unsigned int sd_found_revokes = 0;
|
|
Packit Service |
360c39 |
osi_list_t sd_revoke_list;
|
|
Packit Service |
360c39 |
unsigned int sd_replay_tail;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct gfs2_revoke_replay {
|
|
Packit Service |
360c39 |
osi_list_t rr_list;
|
|
Packit Service |
360c39 |
uint64_t rr_blkno;
|
|
Packit Service |
360c39 |
unsigned int rr_where;
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int gfs2_revoke_add(struct gfs2_sbd *sdp, uint64_t blkno, unsigned int where)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
osi_list_t *tmp, *head = &sd_revoke_list;
|
|
Packit Service |
360c39 |
struct gfs2_revoke_replay *rr;
|
|
Packit Service |
360c39 |
int found = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
osi_list_foreach(tmp, head) {
|
|
Packit Service |
360c39 |
rr = osi_list_entry(tmp, struct gfs2_revoke_replay, rr_list);
|
|
Packit Service |
360c39 |
if (rr->rr_blkno == blkno) {
|
|
Packit Service |
360c39 |
found = 1;
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (found) {
|
|
Packit Service |
360c39 |
rr->rr_where = where;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rr = malloc(sizeof(struct gfs2_revoke_replay));
|
|
Packit Service |
360c39 |
if (!rr)
|
|
Packit Service |
360c39 |
return -ENOMEM;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rr->rr_blkno = blkno;
|
|
Packit Service |
360c39 |
rr->rr_where = where;
|
|
Packit Service |
360c39 |
osi_list_add(&rr->rr_list, head);
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int gfs2_revoke_check(struct gfs2_sbd *sdp, uint64_t blkno, unsigned int where)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
osi_list_t *tmp;
|
|
Packit Service |
360c39 |
struct gfs2_revoke_replay *rr;
|
|
Packit Service |
360c39 |
int wrap, a, b;
|
|
Packit Service |
360c39 |
int found = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
osi_list_foreach(tmp, &sd_revoke_list) {
|
|
Packit Service |
360c39 |
rr = osi_list_entry(tmp, struct gfs2_revoke_replay, rr_list);
|
|
Packit Service |
360c39 |
if (rr->rr_blkno == blkno) {
|
|
Packit Service |
360c39 |
found = 1;
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!found)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
wrap = (rr->rr_where < sd_replay_tail);
|
|
Packit Service |
360c39 |
a = (sd_replay_tail < where);
|
|
Packit Service |
360c39 |
b = (where < rr->rr_where);
|
|
Packit Service |
360c39 |
return (wrap) ? (a || b) : (a && b);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void gfs2_revoke_clean(struct gfs2_sbd *sdp)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
osi_list_t *head = &sd_revoke_list;
|
|
Packit Service |
360c39 |
struct gfs2_revoke_replay *rr;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (!osi_list_empty(head)) {
|
|
Packit Service |
360c39 |
rr = osi_list_entry(head->next, struct gfs2_revoke_replay, rr_list);
|
|
Packit Service |
360c39 |
osi_list_del(&rr->rr_list);
|
|
Packit Service |
360c39 |
free(rr);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void refresh_rgrp(struct gfs2_sbd *sdp, struct rgrp_tree *rgd,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh, uint64_t blkno)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int i;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_debug(_("Block is part of rgrp 0x%llx; refreshing the rgrp.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)rgd->ri.ri_addr);
|
|
Packit Service |
360c39 |
for (i = 0; i < rgd->ri.ri_length; i++) {
|
|
Packit Service |
360c39 |
if (rgd->bits[i].bi_bh->b_blocknr != blkno)
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
memcpy(rgd->bits[i].bi_bh->b_data, bh->b_data, sdp->bsize);
|
|
Packit Service |
360c39 |
bmodified(rgd->bits[i].bi_bh);
|
|
Packit Service |
360c39 |
if (i == 0) { /* this is the rgrp itself */
|
|
Packit Service |
360c39 |
if (sdp->gfs1)
|
|
Packit Service |
360c39 |
gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg,
|
|
Packit Service |
360c39 |
rgd->bits[0].bi_bh);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
gfs2_rgrp_in(&rgd->rg, rgd->bits[0].bi_bh->b_data);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int buf_lo_scan_elements(struct gfs2_inode *ip, unsigned int start,
|
|
Packit Service |
360c39 |
struct gfs2_log_descriptor *ld, __be64 *ptr,
|
|
Packit Service |
360c39 |
int pass)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
unsigned int blks = be32_to_cpu(ld->ld_data1);
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh_log, *bh_ip;
|
|
Packit Service |
360c39 |
uint64_t blkno;
|
|
Packit Service |
360c39 |
int error = 0;
|
|
Packit Service |
360c39 |
struct rgrp_tree *rgd;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_METADATA)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_replay_incr_blk(ip, &start;;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (; blks; gfs2_replay_incr_blk(ip, &start), blks--) {
|
|
Packit Service |
360c39 |
uint32_t check_magic;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
sd_found_metablocks++;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
blkno = be64_to_cpu(*ptr);
|
|
Packit Service |
360c39 |
ptr++;
|
|
Packit Service |
360c39 |
if (gfs2_revoke_check(sdp, blkno, start))
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = gfs2_replay_read_block(ip, start, &bh_log);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_info( _("Journal replay writing metadata block #"
|
|
Packit Service |
360c39 |
"%lld (0x%llx) for journal+0x%x\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)blkno, (unsigned long long)blkno,
|
|
Packit Service |
360c39 |
start);
|
|
Packit Service |
360c39 |
bh_ip = bget(sdp, blkno);
|
|
Packit Service |
360c39 |
if (!bh_ip) {
|
|
Packit Service |
360c39 |
log_err(_("Out of memory when replaying journals.\n"));
|
|
Packit Service |
360c39 |
return FSCK_ERROR;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
memcpy(bh_ip->b_data, bh_log->b_data, sdp->bsize);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
check_magic = ((struct gfs2_meta_header *)
|
|
Packit Service |
360c39 |
(bh_ip->b_data))->mh_magic;
|
|
Packit Service |
360c39 |
check_magic = be32_to_cpu(check_magic);
|
|
Packit Service |
360c39 |
if (check_magic != GFS2_MAGIC) {
|
|
Packit Service |
360c39 |
log_err(_("Journal corruption detected at block #"
|
|
Packit Service |
360c39 |
"%lld (0x%llx) for journal+0x%x.\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)blkno, (unsigned long long)blkno,
|
|
Packit Service |
360c39 |
start);
|
|
Packit Service |
360c39 |
error = -EIO;
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
bmodified(bh_ip);
|
|
Packit Service |
360c39 |
rgd = gfs2_blk2rgrpd(sdp, blkno);
|
|
Packit Service |
360c39 |
if (rgd && blkno < rgd->ri.ri_data0)
|
|
Packit Service |
360c39 |
refresh_rgrp(sdp, rgd, bh_ip, blkno);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
brelse(bh_log);
|
|
Packit Service |
360c39 |
brelse(bh_ip);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
sd_replayed_metablocks++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int revoke_lo_scan_elements(struct gfs2_inode *ip, unsigned int start,
|
|
Packit Service |
360c39 |
struct gfs2_log_descriptor *ld, __be64 *ptr,
|
|
Packit Service |
360c39 |
int pass)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
unsigned int blks = be32_to_cpu(ld->ld_length);
|
|
Packit Service |
360c39 |
unsigned int revokes = be32_to_cpu(ld->ld_data1);
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
unsigned int offset;
|
|
Packit Service |
360c39 |
uint64_t blkno;
|
|
Packit Service |
360c39 |
int first = 1;
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (pass != 0 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_REVOKE)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
offset = sizeof(struct gfs2_log_descriptor);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (; blks; gfs2_replay_incr_blk(ip, &start), blks--) {
|
|
Packit Service |
360c39 |
error = gfs2_replay_read_block(ip, start, &bh;;
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!first) {
|
|
Packit Service |
360c39 |
if (gfs2_check_meta(bh, GFS2_METATYPE_LB))
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
while (offset + sizeof(uint64_t) <= sdp->sd_sb.sb_bsize) {
|
|
Packit Service |
360c39 |
blkno = be64_to_cpu(*(__be64 *)(bh->b_data + offset));
|
|
Packit Service |
360c39 |
log_info( _("Journal replay processing revoke for "
|
|
Packit Service |
360c39 |
"block #%lld (0x%llx) for journal+0x%x\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)blkno,
|
|
Packit Service |
360c39 |
(unsigned long long)blkno,
|
|
Packit Service |
360c39 |
start);
|
|
Packit Service |
360c39 |
error = gfs2_revoke_add(sdp, blkno, start);
|
|
Packit Service |
360c39 |
if (error < 0)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
else if (error)
|
|
Packit Service |
360c39 |
sd_found_revokes++;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!--revokes)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
offset += sizeof(uint64_t);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
offset = sizeof(struct gfs2_meta_header);
|
|
Packit Service |
360c39 |
first = 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int databuf_lo_scan_elements(struct gfs2_inode *ip, unsigned int start,
|
|
Packit Service |
360c39 |
struct gfs2_log_descriptor *ld,
|
|
Packit Service |
360c39 |
__be64 *ptr, int pass)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
unsigned int blks = be32_to_cpu(ld->ld_data1);
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh_log, *bh_ip;
|
|
Packit Service |
360c39 |
uint64_t blkno;
|
|
Packit Service |
360c39 |
uint64_t esc;
|
|
Packit Service |
360c39 |
int error = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_JDATA)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_replay_incr_blk(ip, &start;;
|
|
Packit Service |
360c39 |
for (; blks; gfs2_replay_incr_blk(ip, &start), blks--) {
|
|
Packit Service |
360c39 |
blkno = be64_to_cpu(*ptr);
|
|
Packit Service |
360c39 |
ptr++;
|
|
Packit Service |
360c39 |
esc = be64_to_cpu(*ptr);
|
|
Packit Service |
360c39 |
ptr++;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
sd_found_jblocks++;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (gfs2_revoke_check(sdp, blkno, start))
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = gfs2_replay_read_block(ip, start, &bh_log);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_info( _("Journal replay writing data block #%lld (0x%llx)"
|
|
Packit Service |
360c39 |
" for journal+0x%x\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)blkno, (unsigned long long)blkno,
|
|
Packit Service |
360c39 |
start);
|
|
Packit Service |
360c39 |
bh_ip = bget(sdp, blkno);
|
|
Packit Service |
360c39 |
if (!bh_ip) {
|
|
Packit Service |
360c39 |
log_err(_("Out of memory when replaying journals.\n"));
|
|
Packit Service |
360c39 |
return FSCK_ERROR;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
memcpy(bh_ip->b_data, bh_log->b_data, sdp->bsize);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Unescape */
|
|
Packit Service |
360c39 |
if (esc) {
|
|
Packit Service |
360c39 |
__be32 *eptr = (__be32 *)bh_ip->b_data;
|
|
Packit Service |
360c39 |
*eptr = cpu_to_be32(GFS2_MAGIC);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
brelse(bh_log);
|
|
Packit Service |
360c39 |
bmodified(bh_ip);
|
|
Packit Service |
360c39 |
brelse(bh_ip);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
sd_replayed_jblocks++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* foreach_descriptor - go through the active part of the log
|
|
Packit Service |
360c39 |
* @ip: the journal incore inode
|
|
Packit Service |
360c39 |
* @start: the first log header in the active region
|
|
Packit Service |
360c39 |
* @end: the last log header (don't process the contents of this entry))
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Call a given function once for every log descriptor in the active
|
|
Packit Service |
360c39 |
* portion of the log.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: errno
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int foreach_descriptor(struct gfs2_inode *ip, unsigned int start,
|
|
Packit Service |
360c39 |
unsigned int end, int pass)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
struct gfs2_log_descriptor *ld;
|
|
Packit Service |
360c39 |
int error = 0;
|
|
Packit Service |
360c39 |
uint32_t length;
|
|
Packit Service |
360c39 |
__be64 *ptr;
|
|
Packit Service |
360c39 |
unsigned int offset = sizeof(struct gfs2_log_descriptor);
|
|
Packit Service |
360c39 |
offset += sizeof(__be64) - 1;
|
|
Packit Service |
360c39 |
offset &= ~(sizeof(__be64) - 1);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (start != end) {
|
|
Packit Service |
360c39 |
uint32_t check_magic;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = gfs2_replay_read_block(ip, start, &bh;;
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
check_magic = ((struct gfs2_meta_header *)
|
|
Packit Service |
360c39 |
(bh->b_data))->mh_magic;
|
|
Packit Service |
360c39 |
check_magic = be32_to_cpu(check_magic);
|
|
Packit Service |
360c39 |
if (check_magic != GFS2_MAGIC) {
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
return -EIO;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
ld = (struct gfs2_log_descriptor *)bh->b_data;
|
|
Packit Service |
360c39 |
length = be32_to_cpu(ld->ld_length);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (be32_to_cpu(ld->ld_header.mh_type) == GFS2_METATYPE_LH) {
|
|
Packit Service |
360c39 |
struct gfs2_log_header lh;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = get_log_header(ip, start, &lh);
|
|
Packit Service |
360c39 |
if (!error) {
|
|
Packit Service |
360c39 |
gfs2_replay_incr_blk(ip, &start;;
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (error == 1) {
|
|
Packit Service |
360c39 |
log_err(_("Journal corruption detected at "
|
|
Packit Service |
360c39 |
"journal+0x%x.\n"), start);
|
|
Packit Service |
360c39 |
error = -EIO;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
} else if (gfs2_check_meta(bh, GFS2_METATYPE_LD)) {
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
return -EIO;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
ptr = (__be64 *)(bh->b_data + offset);
|
|
Packit Service |
360c39 |
error = databuf_lo_scan_elements(ip, start, ld, ptr, pass);
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
error = buf_lo_scan_elements(ip, start, ld, ptr, pass);
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
error = revoke_lo_scan_elements(ip, start, ld, ptr, pass);
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (length--)
|
|
Packit Service |
360c39 |
gfs2_replay_incr_blk(ip, &start;;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
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 |
/**
|
|
Packit Service |
360c39 |
* check_journal_seq_no - Check and Fix log header sequencing problems
|
|
Packit Service |
360c39 |
* @ip: the journal incore inode
|
|
Packit Service |
360c39 |
* @fix: if 1, fix the sequence numbers, otherwise just report the problem
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: The number of sequencing errors (hopefully none).
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int check_journal_seq_no(struct gfs2_inode *ip, int fix)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int error = 0, wrapped = 0;
|
|
Packit Service |
360c39 |
uint32_t jd_blocks = ip->i_di.di_size / ip->i_sbd->sd_sb.sb_bsize;
|
|
Packit Service |
360c39 |
uint32_t blk;
|
|
Packit Service |
360c39 |
struct gfs2_log_header lh;
|
|
Packit Service |
360c39 |
uint64_t highest_seq = 0, lowest_seq = 0, prev_seq = 0;
|
|
Packit Service |
360c39 |
int new = 0;
|
|
Packit Service |
360c39 |
uint64_t dblock;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
int seq_errors = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
memset(&lh, 0, sizeof(lh));
|
|
Packit Service |
360c39 |
for (blk = 0; blk < jd_blocks; blk++) {
|
|
Packit Service |
360c39 |
error = get_log_header(ip, blk, &lh);
|
|
Packit Service |
360c39 |
if (error == 1) /* if not a log header */
|
|
Packit Service |
360c39 |
continue; /* just journal data--ignore it */
|
|
Packit Service |
360c39 |
if (!lowest_seq || lh.lh_sequence < lowest_seq)
|
|
Packit Service |
360c39 |
lowest_seq = lh.lh_sequence;
|
|
Packit Service |
360c39 |
if (!highest_seq || lh.lh_sequence > highest_seq)
|
|
Packit Service |
360c39 |
highest_seq = lh.lh_sequence;
|
|
Packit Service |
360c39 |
if (lh.lh_sequence > prev_seq) {
|
|
Packit Service |
360c39 |
prev_seq = lh.lh_sequence;
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* The sequence number is not higher than the previous one,
|
|
Packit Service |
360c39 |
so it's either wrap-around or a sequencing problem. */
|
|
Packit Service |
360c39 |
if (!wrapped && lh.lh_sequence == lowest_seq) {
|
|
Packit Service |
360c39 |
wrapped = 1;
|
|
Packit Service |
360c39 |
prev_seq = lh.lh_sequence;
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_err( _("Journal block %u (0x%x): sequence no. 0x%llx "
|
|
Packit Service |
360c39 |
"out of order.\n"), blk, blk, lh.lh_sequence);
|
|
Packit Service |
360c39 |
log_info( _("Low: 0x%llx, High: 0x%llx, Prev: 0x%llx\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)lowest_seq,
|
|
Packit Service |
360c39 |
(unsigned long long)highest_seq,
|
|
Packit Service |
360c39 |
(unsigned long long)prev_seq);
|
|
Packit Service |
360c39 |
seq_errors++;
|
|
Packit Service |
360c39 |
if (!fix)
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
highest_seq++;
|
|
Packit Service |
360c39 |
lh.lh_sequence = highest_seq;
|
|
Packit Service |
360c39 |
prev_seq = lh.lh_sequence;
|
|
Packit Service |
360c39 |
log_warn( _("Renumbering it as 0x%llx\n"), lh.lh_sequence);
|
|
Packit Service |
360c39 |
block_map(ip, blk, &new, &dblock, NULL, FALSE);
|
|
Packit Service |
360c39 |
bh = bread(ip->i_sbd, dblock);
|
|
Packit Service |
360c39 |
gfs2_log_header_out(&lh, bh->b_data);
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (seq_errors && fix) {
|
|
Packit Service |
360c39 |
log_err(_("%d sequence errors fixed.\n"), seq_errors);
|
|
Packit Service |
360c39 |
seq_errors = 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return seq_errors;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* preen_is_safe - Can we safely preen the file system?
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* If a preen option was specified (-a or -p) we're likely to have been
|
|
Packit Service |
360c39 |
* called from rc.sysinit. We need to determine whether this is shared
|
|
Packit Service |
360c39 |
* storage or not. If it's local storage (locking protocol==lock_nolock)
|
|
Packit Service |
360c39 |
* it's safe to preen the file system. If it's lock_dlm, it's likely
|
|
Packit Service |
360c39 |
* mounted by other nodes in the cluster, which is dangerous and therefore,
|
|
Packit Service |
360c39 |
* we should warn the user to run fsck.gfs2 manually when it's safe.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int preen_is_safe(struct gfs2_sbd *sdp, int preen, int force_check)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if (!preen) /* If preen was not specified */
|
|
Packit Service |
360c39 |
return 1; /* not called by rc.sysinit--we're okay to preen */
|
|
Packit Service |
360c39 |
if (force_check) /* If check was forced by the user? */
|
|
Packit Service |
360c39 |
return 1; /* user's responsibility--we're okay to preen */
|
|
Packit Service |
360c39 |
if (!memcmp(sdp->sd_sb.sb_lockproto + 5, "nolock", 6))
|
|
Packit Service |
360c39 |
return 1; /* local file system--preen is okay */
|
|
Packit Service |
360c39 |
return 0; /* might be mounted on another node--not guaranteed safe */
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* gfs2_recover_journal - recovery a given journal
|
|
Packit Service |
360c39 |
* @ip: the journal incore inode
|
|
Packit Service |
360c39 |
* j: which journal to check
|
|
Packit Service |
360c39 |
* preen: Was preen (-a or -p) specified?
|
|
Packit Service |
360c39 |
* force_check: Was -f specified to force the check?
|
|
Packit Service |
360c39 |
* @was_clean: if the journal was originally clean, this is set to 1.
|
|
Packit Service |
360c39 |
* if the journal was dirty from the start, this is set to 0.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Acquire the journal's lock, check to see if the journal is clean, and
|
|
Packit Service |
360c39 |
* do recovery if necessary.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: errno
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int gfs2_recover_journal(struct gfs2_inode *ip, int j, int preen,
|
|
Packit Service |
360c39 |
int force_check, int *was_clean)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
struct gfs2_log_header head;
|
|
Packit Service |
360c39 |
unsigned int pass;
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*was_clean = 0;
|
|
Packit Service |
360c39 |
log_info( _("jid=%u: Looking at journal...\n"), j);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
osi_list_init(&sd_revoke_list);
|
|
Packit Service |
360c39 |
error = gfs2_find_jhead(ip, &head;;
|
|
Packit Service |
360c39 |
if (!error) {
|
|
Packit Service |
360c39 |
error = check_journal_seq_no(ip, 0);
|
|
Packit Service |
360c39 |
if (error > JOURNAL_SEQ_TOLERANCE) {
|
|
Packit Service |
360c39 |
log_err( _("Journal #%d (\"journal%d\") has %d "
|
|
Packit Service |
360c39 |
"sequencing errors; tolerance is %d.\n"),
|
|
Packit Service |
360c39 |
j+1, j, error, JOURNAL_SEQ_TOLERANCE);
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
if (opts.no) {
|
|
Packit Service |
360c39 |
log_err( _("Journal #%d (\"journal%d\") is corrupt\n"),j+1, j);
|
|
Packit Service |
360c39 |
log_err( _("Not fixing it due to the -n option.\n"));
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!preen_is_safe(sdp, preen, force_check)) {
|
|
Packit Service |
360c39 |
log_err(_("Journal #%d (\"journal%d\") is corrupt.\n"),
|
|
Packit Service |
360c39 |
j+1, j);
|
|
Packit Service |
360c39 |
log_err(_("I'm not fixing it because it may be unsafe:\n"
|
|
Packit Service |
360c39 |
"Locking protocol is not lock_nolock and "
|
|
Packit Service |
360c39 |
"the -a or -p option was specified.\n"));
|
|
Packit Service |
360c39 |
log_err(_("Please make sure no node has the file system "
|
|
Packit Service |
360c39 |
"mounted then rerun fsck.gfs2 manually "
|
|
Packit Service |
360c39 |
"without -a or -p.\n"));
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!query( _("\nJournal #%d (\"journal%d\") is "
|
|
Packit Service |
360c39 |
"corrupt. Okay to repair it? (y/n)"),
|
|
Packit Service |
360c39 |
j+1, j)) {
|
|
Packit Service |
360c39 |
log_err( _("jid=%u: The journal was not repaired.\n"),
|
|
Packit Service |
360c39 |
j);
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_info( _("jid=%u: Repairing journal...\n"), j);
|
|
Packit Service |
360c39 |
error = check_journal_seq_no(ip, 1);
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
log_err( _("jid=%u: Unable to fix the bad journal.\n"),
|
|
Packit Service |
360c39 |
j);
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
error = gfs2_find_jhead(ip, &head;;
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
log_err( _("jid=%u: Unable to fix the bad journal.\n"),
|
|
Packit Service |
360c39 |
j);
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_err( _("jid=%u: The journal was successfully fixed.\n"),
|
|
Packit Service |
360c39 |
j);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (head.lh_flags & GFS2_LOG_HEAD_UNMOUNT) {
|
|
Packit Service |
360c39 |
log_info( _("jid=%u: Journal is clean.\n"), j);
|
|
Packit Service |
360c39 |
*was_clean = 1;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (opts.no) {
|
|
Packit Service |
360c39 |
log_err(_("Journal #%d (\"journal%d\") is dirty\n"),j+1, j);
|
|
Packit Service |
360c39 |
log_err(_("not replaying due to the -n option.\n"));
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!preen_is_safe(sdp, preen, force_check)) {
|
|
Packit Service |
360c39 |
log_err( _("Journal #%d (\"journal%d\") is dirty\n"), j+1, j);
|
|
Packit Service |
360c39 |
log_err( _("I'm not replaying it because it may be unsafe:\n"
|
|
Packit Service |
360c39 |
"Locking protocol is not lock_nolock and "
|
|
Packit Service |
360c39 |
"the -a or -p option was specified.\n"));
|
|
Packit Service |
360c39 |
log_err( _("Please make sure no node has the file system "
|
|
Packit Service |
360c39 |
"mounted then rerun fsck.gfs2 manually "
|
|
Packit Service |
360c39 |
"without -a or -p.\n"));
|
|
Packit Service |
360c39 |
error = FSCK_ERROR;
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!query( _("\nJournal #%d (\"journal%d\") is dirty. Okay to "
|
|
Packit Service |
360c39 |
"replay it? (y/n)"), j+1, j))
|
|
Packit Service |
360c39 |
goto reinit;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_info( _("jid=%u: Replaying journal...\n"), j);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
sd_found_jblocks = sd_replayed_jblocks = 0;
|
|
Packit Service |
360c39 |
sd_found_metablocks = sd_replayed_metablocks = 0;
|
|
Packit Service |
360c39 |
sd_found_revokes = 0;
|
|
Packit Service |
360c39 |
sd_replay_tail = head.lh_tail;
|
|
Packit Service |
360c39 |
for (pass = 0; pass < 2; pass++) {
|
|
Packit Service |
360c39 |
error = foreach_descriptor(ip, head.lh_tail,
|
|
Packit Service |
360c39 |
head.lh_blkno, pass);
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
log_err(_("Error found during journal replay.\n"));
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_info( _("jid=%u: Found %u revoke tags\n"), j, sd_found_revokes);
|
|
Packit Service |
360c39 |
gfs2_revoke_clean(sdp);
|
|
Packit Service |
360c39 |
error = clean_journal(ip, &head;;
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
log_err( _("jid=%u: Replayed %u of %u journaled data blocks\n"),
|
|
Packit Service |
360c39 |
j, sd_replayed_jblocks, sd_found_jblocks);
|
|
Packit Service |
360c39 |
log_err( _("jid=%u: Replayed %u of %u metadata blocks\n"),
|
|
Packit Service |
360c39 |
j, sd_replayed_metablocks, sd_found_metablocks);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Check for errors and give them the option to reinitialize the
|
|
Packit Service |
360c39 |
journal. */
|
|
Packit Service |
360c39 |
out:
|
|
Packit Service |
360c39 |
if (!error) {
|
|
Packit Service |
360c39 |
log_info( _("jid=%u: Done\n"), j);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_err( _("jid=%u: Failed\n"), j);
|
|
Packit Service |
360c39 |
reinit:
|
|
Packit Service |
360c39 |
if (query( _("Do you want to clear the journal instead? (y/n)"))) {
|
|
Packit Service |
360c39 |
error = write_journal(sdp->md.journal[j], sdp->bsize,
|
|
Packit Service |
360c39 |
sdp->md.journal[j]->i_di.di_size /
|
|
Packit Service |
360c39 |
sdp->sd_sb.sb_bsize);
|
|
Packit Service |
360c39 |
log_err(_("jid=%u: journal was cleared.\n"), j);
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
log_err( _("jid=%u: journal not cleared.\n"), j);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* We can't use the rangecheck function from pass1 because we haven't gone
|
|
Packit Service |
360c39 |
* through initialization properly yet. */
|
|
Packit Service |
360c39 |
static int rangecheck_jblock(struct gfs2_inode *ip, uint64_t block)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if((block > ip->i_sbd->fssize) || (block <= LGFS2_SB_ADDR(ip->i_sbd))) {
|
|
Packit Service |
360c39 |
log_info( _("Bad block pointer (out of range) found in "
|
|
Packit Service |
360c39 |
"journal 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 |
return meta_error; /* Exits check_metatree quicker */
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return meta_is_good;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int rangecheck_jmeta(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 |
int rc;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*bh = NULL;
|
|
Packit Service |
360c39 |
*was_duplicate = 0;
|
|
Packit Service |
360c39 |
*is_valid = 0;
|
|
Packit Service |
360c39 |
rc = rangecheck_jblock(ip, block);
|
|
Packit Service |
360c39 |
if (rc == meta_is_good) {
|
|
Packit Service |
360c39 |
*bh = bread(ip->i_sbd, block);
|
|
Packit Service |
360c39 |
*is_valid = (gfs2_check_meta(*bh, GFS2_METATYPE_IN) == 0);
|
|
Packit Service |
360c39 |
if (!(*is_valid)) {
|
|
Packit Service |
360c39 |
log_err( _("Journal at block %lld (0x%llx) has a bad "
|
|
Packit Service |
360c39 |
"indirect block pointer %lld (0x%llx) "
|
|
Packit Service |
360c39 |
"(points to something that is not an "
|
|
Packit Service |
360c39 |
"indirect 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 |
(unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block);
|
|
Packit Service |
360c39 |
brelse(*bh);
|
|
Packit Service |
360c39 |
*bh = NULL;
|
|
Packit Service |
360c39 |
return meta_skip_further;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return rc;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int rangecheck_jdata(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_jblock(ip, block);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct metawalk_fxns rangecheck_journal = {
|
|
Packit Service |
360c39 |
.private = NULL,
|
|
Packit Service |
360c39 |
.invalid_meta_is_fatal = 1,
|
|
Packit Service |
360c39 |
.check_metalist = rangecheck_jmeta,
|
|
Packit Service |
360c39 |
.check_data = rangecheck_jdata,
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* replay_journals - replay the journals
|
|
Packit Service |
360c39 |
* sdp: the super block
|
|
Packit Service |
360c39 |
* preen: Was preen (-a or -p) specified?
|
|
Packit Service |
360c39 |
* force_check: Was -f specified to force the check?
|
|
Packit Service |
360c39 |
* @clean_journals - set to the number of clean journals we find
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* There should be a flag to the fsck to enable/disable this
|
|
Packit Service |
360c39 |
* feature. The fsck falls back to clearing the journal if an
|
|
Packit Service |
360c39 |
* inconsistency is found, but only for the bad journal.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 on success, -1 on failure
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int replay_journals(struct gfs2_sbd *sdp, int preen, int force_check,
|
|
Packit Service |
360c39 |
int *clean_journals)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int i;
|
|
Packit Service |
360c39 |
int clean = 0, dirty_journals = 0, error = 0, gave_msg = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*clean_journals = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
sdp->jsize = GFS2_DEFAULT_JSIZE;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for(i = 0; i < sdp->md.journals; i++) {
|
|
Packit Service |
360c39 |
if (sdp->md.journal[i]) {
|
|
Packit Service |
360c39 |
error = check_metatree(sdp->md.journal[i],
|
|
Packit Service |
360c39 |
&rangecheck_journal);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
/* Don't use fsck_inode_put here because it's a
|
|
Packit Service |
360c39 |
system file and we need to dismantle it. */
|
|
Packit Service |
360c39 |
inode_put(&sdp->md.journal[i]);
|
|
Packit Service |
360c39 |
error = 0; /* bad journal is non-fatal */
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!sdp->md.journal[i]) {
|
|
Packit Service |
360c39 |
log_err(_("File system journal \"journal%d\" is "
|
|
Packit Service |
360c39 |
"missing or corrupt: pass1 will try to "
|
|
Packit Service |
360c39 |
"recreate it.\n"), i);
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!error) {
|
|
Packit Service |
360c39 |
uint64_t jsize = sdp->md.journal[i]->i_di.di_size /
|
|
Packit Service |
360c39 |
(1024 * 1024);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (sdp->jsize == GFS2_DEFAULT_JSIZE && jsize &&
|
|
Packit Service |
360c39 |
jsize != sdp->jsize)
|
|
Packit Service |
360c39 |
sdp->jsize = jsize;
|
|
Packit Service |
360c39 |
error = gfs2_recover_journal(sdp->md.journal[i], i,
|
|
Packit Service |
360c39 |
preen, force_check,
|
|
Packit Service |
360c39 |
&clean);
|
|
Packit Service |
360c39 |
if (!clean)
|
|
Packit Service |
360c39 |
dirty_journals++;
|
|
Packit Service |
360c39 |
if (!gave_msg && dirty_journals == 1 && !opts.no &&
|
|
Packit Service |
360c39 |
preen_is_safe(sdp, preen, force_check)) {
|
|
Packit Service |
360c39 |
gave_msg = 1;
|
|
Packit Service |
360c39 |
log_notice( _("Recovering journals (this may "
|
|
Packit Service |
360c39 |
"take a while)\n"));
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
*clean_journals += clean;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Sync the buffers to disk so we get a fresh start. */
|
|
Packit Service |
360c39 |
fsync(sdp->device_fd);
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* ji_update - fill in journal info
|
|
Packit Service |
360c39 |
* sdp: the incore superblock pointer
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Given the inode for the journal index, read in all
|
|
Packit Service |
360c39 |
* the journal inodes.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 on success, -1 on failure
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int ji_update(struct gfs2_sbd *sdp)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_inode *jip, *ip = sdp->md.jiinode;
|
|
Packit Service |
360c39 |
char journal_name[JOURNAL_NAME_SIZE];
|
|
Packit Service |
360c39 |
int i, error;
|
|
Packit Service |
360c39 |
char buf[sizeof(struct gfs_jindex)];
|
|
Packit Service |
360c39 |
struct gfs_jindex ji;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!ip) {
|
|
Packit Service |
360c39 |
log_crit(_("Journal index inode not found.\n"));
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* The per_node directory will have 3 directory entries per node,
|
|
Packit Service |
360c39 |
plus two for "." and "..". So we subtract the 2 and divide by 3.
|
|
Packit Service |
360c39 |
If per_node is missing or damaged, we have to trust jindex has
|
|
Packit Service |
360c39 |
the correct number of entries. */
|
|
Packit Service |
360c39 |
if (sdp->gfs1)
|
|
Packit Service |
360c39 |
sdp->md.journals = ip->i_di.di_size / sizeof(struct gfs_jindex);
|
|
Packit Service |
360c39 |
else if (sdp->md.pinode) /* if per_node was read in properly */
|
|
Packit Service |
360c39 |
sdp->md.journals = (sdp->md.pinode->i_di.di_entries - 2) / 3;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
sdp->md.journals = ip->i_di.di_entries - 2;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!(sdp->md.journal = calloc(sdp->md.journals,
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_inode *)))) {
|
|
Packit Service |
360c39 |
log_err(_("Unable to allocate journal index\n"));
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
memset(journal_name, 0, sizeof(*journal_name));
|
|
Packit Service |
360c39 |
for (i = 0; i < sdp->md.journals; i++) {
|
|
Packit Service |
360c39 |
if (sdp->gfs1) {
|
|
Packit Service |
360c39 |
error = gfs2_readi(ip,
|
|
Packit Service |
360c39 |
buf, i * sizeof(struct gfs_jindex),
|
|
Packit Service |
360c39 |
sizeof(struct gfs_jindex));
|
|
Packit Service |
360c39 |
if (!error)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
if (error != sizeof(struct gfs_jindex)){
|
|
Packit Service |
360c39 |
log_err(_("An error occurred while reading the"
|
|
Packit Service |
360c39 |
" journal index file.\n"));
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
gfs_jindex_in(&ji, buf);
|
|
Packit Service |
360c39 |
sdp->md.journal[i] = lgfs2_inode_read(sdp, ji.ji_addr);
|
|
Packit Service |
360c39 |
if (sdp->md.journal[i] == NULL)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
/* FIXME check snprintf return code */
|
|
Packit Service |
360c39 |
snprintf(journal_name, JOURNAL_NAME_SIZE,
|
|
Packit Service |
360c39 |
"journal%u", i);
|
|
Packit Service |
360c39 |
gfs2_lookupi(sdp->md.jiinode, journal_name,
|
|
Packit Service |
360c39 |
strlen(journal_name), &jip);
|
|
Packit Service |
360c39 |
sdp->md.journal[i] = jip;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void bad_journalname(const char *filename, int len)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if (len >= 64)
|
|
Packit Service |
360c39 |
len = 63;
|
|
Packit Service |
360c39 |
log_debug(_("Journal index entry '%.*s' has an invalid filename.\n"),
|
|
Packit Service |
360c39 |
len, filename);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* check_jindex_dent - check the jindex directory entries
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* This function makes sure the directory entries of the jindex are valid.
|
|
Packit Service |
360c39 |
* If they're not '.' or '..' they better have the form journalXXX.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int check_jindex_dent(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_dirent dentry, *de;
|
|
Packit Service |
360c39 |
int i;
|
|
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 |
|
|
Packit Service |
360c39 |
if (de->de_name_len == 1 && filename[0] == '.')
|
|
Packit Service |
360c39 |
goto dirent_good;
|
|
Packit Service |
360c39 |
if (de->de_name_len == 2 && filename[0] == '.' && filename[1] == '.')
|
|
Packit Service |
360c39 |
goto dirent_good;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if ((de->de_name_len >= 11) || /* "journal9999" */
|
|
Packit Service |
360c39 |
(de->de_name_len <= 7) ||
|
|
Packit Service |
360c39 |
(strncmp(filename, "journal", 7))) {
|
|
Packit Service |
360c39 |
bad_journalname(filename, de->de_name_len);
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
for (i = 7; i < de->de_name_len; i++) {
|
|
Packit Service |
360c39 |
if (filename[i] < '0' || filename[i] > '9') {
|
|
Packit Service |
360c39 |
bad_journalname(filename, de->de_name_len);
|
|
Packit Service |
360c39 |
return -2;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
dirent_good:
|
|
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 jindex_check_fxns = {
|
|
Packit Service |
360c39 |
.private = NULL,
|
|
Packit Service |
360c39 |
.check_dentry = check_jindex_dent,
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* init_jindex - read in the rindex file
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int init_jindex(struct gfs2_sbd *sdp, int allow_ji_rebuild)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
/*******************************************************************
|
|
Packit Service |
360c39 |
****************** Fill in journal information ******************
|
|
Packit Service |
360c39 |
*******************************************************************/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_debug(_("Validating the journal index.\n"));
|
|
Packit Service |
360c39 |
/* rgrepair requires the journals be read in in order to distinguish
|
|
Packit Service |
360c39 |
"real" rgrps from rgrps that are just copies left in journals. */
|
|
Packit Service |
360c39 |
if (sdp->gfs1)
|
|
Packit Service |
360c39 |
sdp->md.jiinode = lgfs2_inode_read(sdp, sbd1->sb_jindex_di.no_addr);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
gfs2_lookupi(sdp->master_dir, "jindex", 6, &sdp->md.jiinode);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!sdp->md.jiinode) {
|
|
Packit Service |
360c39 |
int err;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!allow_ji_rebuild) {
|
|
Packit Service |
360c39 |
log_crit(_("Error: jindex and rindex files are both "
|
|
Packit Service |
360c39 |
"corrupt.\n"));
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!query( _("The gfs2 system jindex inode is missing. "
|
|
Packit Service |
360c39 |
"Okay to rebuild it? (y/n) "))) {
|
|
Packit Service |
360c39 |
log_crit(_("Error: cannot proceed without a valid "
|
|
Packit Service |
360c39 |
"jindex file.\n"));
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
err = build_jindex(sdp);
|
|
Packit Service |
360c39 |
if (err) {
|
|
Packit Service |
360c39 |
log_crit(_("Error %d rebuilding jindex\n"), err);
|
|
Packit Service |
360c39 |
return err;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
gfs2_lookupi(sdp->master_dir, "jindex", 6, &sdp->md.jiinode);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* check for irrelevant entries in jindex. Can't use check_dir because
|
|
Packit Service |
360c39 |
that creates and destroys the inode, which we don't want. */
|
|
Packit Service |
360c39 |
if (!sdp->gfs1) {
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_debug(_("Checking the integrity of the journal index.\n"));
|
|
Packit Service |
360c39 |
if (sdp->md.jiinode->i_di.di_flags & GFS2_DIF_EXHASH)
|
|
Packit Service |
360c39 |
error = check_leaf_blks(sdp->md.jiinode,
|
|
Packit Service |
360c39 |
&jindex_check_fxns);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
error = check_linear_dir(sdp->md.jiinode,
|
|
Packit Service |
360c39 |
sdp->md.jiinode->i_bh,
|
|
Packit Service |
360c39 |
&jindex_check_fxns);
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
log_err(_("The system journal index is damaged.\n"));
|
|
Packit Service |
360c39 |
if (!query( _("Okay to rebuild it? (y/n) "))) {
|
|
Packit Service |
360c39 |
log_crit(_("Error: cannot proceed without a "
|
|
Packit Service |
360c39 |
"valid jindex file.\n"));
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
inode_put(&sdp->md.jiinode);
|
|
Packit Service |
360c39 |
gfs2_dirent_del(sdp->master_dir, "jindex", 6);
|
|
Packit Service |
360c39 |
log_err(_("Corrupt journal index was removed.\n"));
|
|
Packit Service |
360c39 |
error = build_jindex(sdp);
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
log_err(_("Error rebuilding journal "
|
|
Packit Service |
360c39 |
"index: Cannot continue.\n"));
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
gfs2_lookupi(sdp->master_dir, "jindex", 6,
|
|
Packit Service |
360c39 |
&sdp->md.jiinode);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* read in the ji data */
|
|
Packit Service |
360c39 |
if (ji_update(sdp)){
|
|
Packit Service |
360c39 |
log_err( _("Unable to read jindex inode.\n"));
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|