|
Packit Service |
360c39 |
#include "clusterautoconfig.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* NOTE:
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* This code was pilfered from the gfs2 kernel and adapted to userland.
|
|
Packit Service |
360c39 |
* If you change this part, you should evaluate whether the upstream kernel
|
|
Packit Service |
360c39 |
* version of recovery.c should be changed as well. Likewise, if the
|
|
Packit Service |
360c39 |
* upstream version changes, this part should be kept in sync.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include <errno.h>
|
|
Packit Service |
360c39 |
#include <string.h>
|
|
Packit Service |
360c39 |
#include "libgfs2.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void gfs2_replay_incr_blk(struct gfs2_inode *ip, unsigned int *blk)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint32_t jd_blocks = ip->i_di.di_size / ip->i_sbd->sd_sb.sb_bsize;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (++*blk == jd_blocks)
|
|
Packit Service |
360c39 |
*blk = 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int gfs2_replay_read_block(struct gfs2_inode *ip, unsigned int blk,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int new = 0;
|
|
Packit Service |
360c39 |
uint64_t dblock;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
block_map(ip, blk, &new, &dblock, NULL, FALSE);
|
|
Packit Service |
360c39 |
if (!dblock)
|
|
Packit Service |
360c39 |
return -EIO;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*bh = bread(ip->i_sbd, dblock);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* get_log_header - read the log header for a given segment
|
|
Packit Service |
360c39 |
* @ip: the journal incore inode
|
|
Packit Service |
360c39 |
* @blk: the block to look at
|
|
Packit Service |
360c39 |
* @lh: the log header to return
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Read the log header for a given segement in a given journal. Do a few
|
|
Packit Service |
360c39 |
* sanity checks on it.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 on success,
|
|
Packit Service |
360c39 |
* 1 if the header was invalid or incomplete,
|
|
Packit Service |
360c39 |
* errno on error
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int get_log_header(struct gfs2_inode *ip, unsigned int blk,
|
|
Packit Service |
360c39 |
struct gfs2_log_header *head)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
struct gfs2_log_header lh, *tmp;
|
|
Packit Service |
360c39 |
uint32_t hash, saved_hash;
|
|
Packit Service |
360c39 |
uint32_t lh_crc = 0;
|
|
Packit Service |
360c39 |
uint32_t crc;
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = gfs2_replay_read_block(ip, blk, &bh;;
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
tmp = (struct gfs2_log_header *)bh->b_data;
|
|
Packit Service |
360c39 |
saved_hash = tmp->lh_hash;
|
|
Packit Service |
360c39 |
tmp->lh_hash = 0;
|
|
Packit Service |
360c39 |
hash = lgfs2_log_header_hash(bh->b_data);
|
|
Packit Service |
360c39 |
tmp->lh_hash = saved_hash;
|
|
Packit Service |
360c39 |
crc = lgfs2_log_header_crc(bh->b_data, ip->i_sbd->bsize);
|
|
Packit Service |
360c39 |
gfs2_log_header_in(&lh, bh->b_data);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
#ifdef GFS2_HAS_LH_V2
|
|
Packit Service |
360c39 |
lh_crc = lh.lh_crc;
|
|
Packit Service |
360c39 |
#endif
|
|
Packit Service |
360c39 |
if (error || lh.lh_blkno != blk || lh.lh_hash != hash)
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
/* Don't check the crc if it's zero, as it is in pre-v2 log headers */
|
|
Packit Service |
360c39 |
if (lh_crc != 0 && lh_crc != crc)
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*head = lh;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* find_good_lh - find a good log header
|
|
Packit Service |
360c39 |
* @ip: the journal incore inode
|
|
Packit Service |
360c39 |
* @blk: the segment to start searching from
|
|
Packit Service |
360c39 |
* @lh: the log header to fill in
|
|
Packit Service |
360c39 |
* @forward: if true search forward in the log, else search backward
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Call get_log_header() to get a log header for a segment, but if the
|
|
Packit Service |
360c39 |
* segment is bad, either scan forward or backward until we find a good one.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: errno
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int find_good_lh(struct gfs2_inode *ip, unsigned int *blk, struct gfs2_log_header *head)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
unsigned int orig_blk = *blk;
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
uint32_t jd_blocks = ip->i_di.di_size / ip->i_sbd->sd_sb.sb_bsize;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (;;) {
|
|
Packit Service |
360c39 |
error = get_log_header(ip, *blk, head);
|
|
Packit Service |
360c39 |
if (error <= 0)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (++*blk == jd_blocks)
|
|
Packit Service |
360c39 |
*blk = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (*blk == orig_blk)
|
|
Packit Service |
360c39 |
return -EIO;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* jhead_scan - make sure we've found the head of the log
|
|
Packit Service |
360c39 |
* @jd: the journal
|
|
Packit Service |
360c39 |
* @head: this is filled in with the log descriptor of the head
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* At this point, seg and lh should be either the head of the log or just
|
|
Packit Service |
360c39 |
* before. Scan forward until we find the head.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: errno
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int jhead_scan(struct gfs2_inode *ip, struct gfs2_log_header *head)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
unsigned int blk = head->lh_blkno;
|
|
Packit Service |
360c39 |
uint32_t jd_blocks = ip->i_di.di_size / ip->i_sbd->sd_sb.sb_bsize;
|
|
Packit Service |
360c39 |
struct gfs2_log_header lh;
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (;;) {
|
|
Packit Service |
360c39 |
if (++blk == jd_blocks)
|
|
Packit Service |
360c39 |
blk = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = get_log_header(ip, blk, &lh);
|
|
Packit Service |
360c39 |
if (error < 0)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
if (error == 1)
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (lh.lh_sequence == head->lh_sequence)
|
|
Packit Service |
360c39 |
return -EIO;
|
|
Packit Service |
360c39 |
if (lh.lh_sequence < head->lh_sequence)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*head = lh;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* gfs2_find_jhead - find the head of a log
|
|
Packit Service |
360c39 |
* @jd: the journal
|
|
Packit Service |
360c39 |
* @head: the log descriptor for the head of the log is returned here
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Do a binary search of a journal and find the valid log entry with the
|
|
Packit Service |
360c39 |
* highest sequence number. (i.e. the log head)
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: errno
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int gfs2_find_jhead(struct gfs2_inode *ip, struct gfs2_log_header *head)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_log_header lh_1, lh_m;
|
|
Packit Service |
360c39 |
uint32_t blk_1, blk_2, blk_m;
|
|
Packit Service |
360c39 |
uint32_t jd_blocks = ip->i_di.di_size / ip->i_sbd->sd_sb.sb_bsize;
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
blk_1 = 0;
|
|
Packit Service |
360c39 |
blk_2 = jd_blocks - 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (;;) {
|
|
Packit Service |
360c39 |
blk_m = (blk_1 + blk_2) / 2;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = find_good_lh(ip, &blk_1, &lh_1);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = find_good_lh(ip, &blk_m, &lh_m);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (blk_1 == blk_m || blk_m == blk_2)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (lh_1.lh_sequence <= lh_m.lh_sequence)
|
|
Packit Service |
360c39 |
blk_1 = blk_m;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
blk_2 = blk_m;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = jhead_scan(ip, &lh_1);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*head = lh_1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* clean_journal - mark a dirty journal as being clean
|
|
Packit Service |
360c39 |
* @sdp: the filesystem
|
|
Packit Service |
360c39 |
* @jd: the journal
|
|
Packit Service |
360c39 |
* @head: the head journal to start from
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: errno
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int clean_journal(struct gfs2_inode *ip, struct gfs2_log_header *head)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
unsigned int lblock;
|
|
Packit Service |
360c39 |
struct gfs2_log_header *lh;
|
|
Packit Service |
360c39 |
uint32_t hash;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
int new = 0;
|
|
Packit Service |
360c39 |
uint64_t dblock;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
lblock = head->lh_blkno;
|
|
Packit Service |
360c39 |
gfs2_replay_incr_blk(ip, &lblock);
|
|
Packit Service |
360c39 |
block_map(ip, lblock, &new, &dblock, NULL, 0);
|
|
Packit Service |
360c39 |
if (!dblock)
|
|
Packit Service |
360c39 |
return -EIO;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bh = bread(ip->i_sbd, dblock);
|
|
Packit Service |
360c39 |
memset(bh->b_data, 0, ip->i_sbd->bsize);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
lh = (struct gfs2_log_header *)bh->b_data;
|
|
Packit Service |
360c39 |
memset(lh, 0, sizeof(struct gfs2_log_header));
|
|
Packit Service |
360c39 |
lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
|
|
Packit Service |
360c39 |
lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
|
|
Packit Service |
360c39 |
lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
|
|
Packit Service |
360c39 |
lh->lh_sequence = cpu_to_be64(head->lh_sequence + 1);
|
|
Packit Service |
360c39 |
lh->lh_flags = cpu_to_be32(GFS2_LOG_HEAD_UNMOUNT);
|
|
Packit Service |
360c39 |
lh->lh_blkno = cpu_to_be32(lblock);
|
|
Packit Service |
360c39 |
hash = gfs2_disk_hash((const char *)lh, sizeof(struct gfs2_log_header));
|
|
Packit Service |
360c39 |
lh->lh_hash = cpu_to_be32(hash);
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|