diff options
Diffstat (limited to 'fs/gfs2/recovery.c')
-rw-r--r-- | fs/gfs2/recovery.c | 130 |
1 files changed, 45 insertions, 85 deletions
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 9395a3db1a60..d8b622c375ab 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -14,12 +14,15 @@ #include <linux/buffer_head.h> #include <linux/gfs2_ondisk.h> #include <linux/crc32.h> +#include <linux/crc32c.h> +#include <linux/ktime.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 +120,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 +137,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 +365,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); } @@ -455,12 +410,13 @@ void gfs2_recover_func(struct work_struct *work) struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); struct gfs2_log_header_host head; struct gfs2_holder j_gh, ji_gh, thaw_gh; - unsigned long t; + ktime_t t_start, t_jlck, t_jhd, t_tlck, t_rep; int ro = 0; unsigned int pass; int error; int jlocked = 0; + t_start = ktime_get(); if (sdp->sd_args.ar_spectator || (jd->jd_jid != sdp->sd_lockstruct.ls_jid)) { fs_info(sdp, "jid=%u: Trying to acquire journal lock...\n", @@ -492,6 +448,7 @@ void gfs2_recover_func(struct work_struct *work) fs_info(sdp, "jid=%u, already locked for use\n", jd->jd_jid); } + t_jlck = ktime_get(); fs_info(sdp, "jid=%u: Looking at journal...\n", jd->jd_jid); error = gfs2_jdesc_check(jd); @@ -501,13 +458,12 @@ void gfs2_recover_func(struct work_struct *work) error = gfs2_find_jhead(jd, &head); if (error) goto fail_gunlock_ji; + t_jhd = ktime_get(); if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) { fs_info(sdp, "jid=%u: Acquiring the transaction lock...\n", jd->jd_jid); - t = jiffies; - /* Acquire a shared hold on the freeze lock */ error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, @@ -541,6 +497,7 @@ void gfs2_recover_func(struct work_struct *work) goto fail_gunlock_thaw; } + t_tlck = ktime_get(); fs_info(sdp, "jid=%u: Replaying journal...\n", jd->jd_jid); for (pass = 0; pass < 2; pass++) { @@ -552,14 +509,17 @@ 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); - fs_info(sdp, "jid=%u: Journal replayed in %lus\n", - jd->jd_jid, t); + t_rep = ktime_get(); + fs_info(sdp, "jid=%u: Journal replayed in %lldms [jlck:%lldms, " + "jhead:%lldms, tlck:%lldms, replay:%lldms]\n", + jd->jd_jid, ktime_ms_delta(t_rep, t_start), + ktime_ms_delta(t_jlck, t_start), + ktime_ms_delta(t_jhd, t_jlck), + ktime_ms_delta(t_tlck, t_jhd), + ktime_ms_delta(t_rep, t_tlck)); } gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_SUCCESS); |