diff options
Diffstat (limited to 'fs/gfs2/recovery.c')
-rw-r--r-- | fs/gfs2/recovery.c | 110 |
1 files changed, 31 insertions, 79 deletions
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 9395a3db1a60..b6b258998bcd 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -14,12 +14,14 @@ #include <linux/buffer_head.h> #include <linux/gfs2_ondisk.h> #include <linux/crc32.h> +#include <linux/crc32c.h> #include "gfs2.h" #include "incore.h" #include "bmap.h" #include "glock.h" #include "glops.h" +#include "log.h" #include "lops.h" #include "meta_io.h" #include "recovery.h" @@ -117,22 +119,6 @@ void gfs2_revoke_clean(struct gfs2_jdesc *jd) } } -static int gfs2_log_header_in(struct gfs2_log_header_host *lh, const void *buf) -{ - const struct gfs2_log_header *str = buf; - - if (str->lh_header.mh_magic != cpu_to_be32(GFS2_MAGIC) || - str->lh_header.mh_type != cpu_to_be32(GFS2_METATYPE_LH)) - return 1; - - lh->lh_sequence = be64_to_cpu(str->lh_sequence); - lh->lh_flags = be32_to_cpu(str->lh_flags); - lh->lh_tail = be32_to_cpu(str->lh_tail); - lh->lh_blkno = be32_to_cpu(str->lh_blkno); - lh->lh_hash = be32_to_cpu(str->lh_hash); - return 0; -} - /** * get_log_header - read the log header for a given segment * @jd: the journal @@ -150,29 +136,37 @@ static int gfs2_log_header_in(struct gfs2_log_header_host *lh, const void *buf) static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, struct gfs2_log_header_host *head) { + struct gfs2_log_header *lh; struct buffer_head *bh; - struct gfs2_log_header_host uninitialized_var(lh); - const u32 nothing = 0; - u32 hash; + u32 hash, crc; int error; error = gfs2_replay_read_block(jd, blk, &bh); if (error) return error; + lh = (void *)bh->b_data; - hash = crc32_le((u32)~0, bh->b_data, sizeof(struct gfs2_log_header) - - sizeof(u32)); - hash = crc32_le(hash, (unsigned char const *)¬hing, sizeof(nothing)); - hash ^= (u32)~0; - error = gfs2_log_header_in(&lh, bh->b_data); - brelse(bh); + hash = crc32(~0, lh, LH_V1_SIZE - 4); + hash = ~crc32_le_shift(hash, 4); /* assume lh_hash is zero */ - if (error || lh.lh_blkno != blk || lh.lh_hash != hash) - return 1; + crc = crc32c(~0, (void *)lh + LH_V1_SIZE + 4, + bh->b_size - LH_V1_SIZE - 4); - *head = lh; + error = lh->lh_header.mh_magic != cpu_to_be32(GFS2_MAGIC) || + lh->lh_header.mh_type != cpu_to_be32(GFS2_METATYPE_LH) || + be32_to_cpu(lh->lh_blkno) != blk || + be32_to_cpu(lh->lh_hash) != hash || + (lh->lh_crc != 0 && be32_to_cpu(lh->lh_crc) != crc); - return 0; + brelse(bh); + + if (!error) { + head->lh_sequence = be64_to_cpu(lh->lh_sequence); + head->lh_flags = be32_to_cpu(lh->lh_flags); + head->lh_tail = be32_to_cpu(lh->lh_tail); + head->lh_blkno = be32_to_cpu(lh->lh_blkno); + } + return error; } /** @@ -370,62 +364,22 @@ static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, /** * clean_journal - mark a dirty journal as being clean - * @sdp: the filesystem * @jd: the journal - * @gl: the journal's glock * @head: the head journal to start from * * Returns: errno */ -static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head) +static void clean_journal(struct gfs2_jdesc *jd, + struct gfs2_log_header_host *head) { - struct gfs2_inode *ip = GFS2_I(jd->jd_inode); struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); - unsigned int lblock; - struct gfs2_log_header *lh; - u32 hash; - struct buffer_head *bh; - int error; - struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 }; - - lblock = head->lh_blkno; - gfs2_replay_incr_blk(jd, &lblock); - bh_map.b_size = 1 << ip->i_inode.i_blkbits; - error = gfs2_block_map(&ip->i_inode, lblock, &bh_map, 0); - if (error) - return error; - if (!bh_map.b_blocknr) { - gfs2_consist_inode(ip); - return -EIO; - } - - bh = sb_getblk(sdp->sd_vfs, bh_map.b_blocknr); - lock_buffer(bh); - memset(bh->b_data, 0, bh->b_size); - set_buffer_uptodate(bh); - clear_buffer_dirty(bh); - unlock_buffer(bh); - - lh = (struct gfs2_log_header *)bh->b_data; - memset(lh, 0, sizeof(struct gfs2_log_header)); - lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); - lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); - lh->lh_header.__pad0 = cpu_to_be64(0); - lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH); - lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid); - lh->lh_sequence = cpu_to_be64(head->lh_sequence + 1); - lh->lh_flags = cpu_to_be32(GFS2_LOG_HEAD_UNMOUNT); - lh->lh_blkno = cpu_to_be32(lblock); - hash = gfs2_disk_hash((const char *)lh, sizeof(struct gfs2_log_header)); - lh->lh_hash = cpu_to_be32(hash); - - set_buffer_dirty(bh); - if (sync_dirty_buffer(bh)) - gfs2_io_error_bh(sdp, bh); - brelse(bh); - return error; + sdp->sd_log_flush_head = head->lh_blkno; + gfs2_replay_incr_blk(jd, &sdp->sd_log_flush_head); + gfs2_write_log_header(sdp, jd, head->lh_sequence + 1, 0, + GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_RECOVERY, + REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC); } @@ -552,9 +506,7 @@ void gfs2_recover_func(struct work_struct *work) goto fail_gunlock_thaw; } - error = clean_journal(jd, &head); - if (error) - goto fail_gunlock_thaw; + clean_journal(jd, &head); gfs2_glock_dq_uninit(&thaw_gh); t = DIV_ROUND_UP(jiffies - t, HZ); |