diff options
Diffstat (limited to 'fs/gfs2/log.c')
-rw-r--r-- | fs/gfs2/log.c | 124 |
1 files changed, 92 insertions, 32 deletions
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index f72c44231406..cf6b46247df4 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -14,6 +14,7 @@ #include <linux/buffer_head.h> #include <linux/gfs2_ondisk.h> #include <linux/crc32.h> +#include <linux/crc32c.h> #include <linux/delay.h> #include <linux/kthread.h> #include <linux/freezer.h> @@ -538,9 +539,12 @@ static void gfs2_ordered_write(struct gfs2_sbd *sdp) list_sort(NULL, &sdp->sd_log_le_ordered, &ip_cmp); while (!list_empty(&sdp->sd_log_le_ordered)) { ip = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_inode, i_ordered); - list_move(&ip->i_ordered, &written); - if (ip->i_inode.i_mapping->nrpages == 0) + if (ip->i_inode.i_mapping->nrpages == 0) { + test_and_clear_bit(GIF_ORDERED, &ip->i_flags); + list_del(&ip->i_ordered); continue; + } + list_move(&ip->i_ordered, &written); spin_unlock(&sdp->sd_ordered_lock); filemap_fdatawrite(ip->i_inode.i_mapping); spin_lock(&sdp->sd_ordered_lock); @@ -648,49 +652,102 @@ out_of_blocks: } /** - * log_write_header - Get and initialize a journal header buffer + * write_log_header - Write a journal log header buffer at sd_log_flush_head * @sdp: The GFS2 superblock + * @jd: journal descriptor of the journal to which we are writing + * @seq: sequence number + * @tail: tail of the log + * @flags: log header flags GFS2_LOG_HEAD_* + * @op_flags: flags to pass to the bio * * Returns: the initialized log buffer descriptor */ -static void log_write_header(struct gfs2_sbd *sdp, u32 flags) +void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, + u64 seq, u32 tail, u32 flags, int op_flags) { struct gfs2_log_header *lh; - unsigned int tail; - u32 hash; - int op_flags = REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC; + u32 hash, crc; struct page *page = mempool_alloc(gfs2_page_pool, GFP_NOIO); - enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state); + struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; + struct timespec64 tv; + struct super_block *sb = sdp->sd_vfs; + u64 addr; + lh = page_address(page); clear_page(lh); - gfs2_assert_withdraw(sdp, (state != SFS_FROZEN)); - - tail = current_tail(sdp); - 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(sdp->sd_log_sequence++); + lh->lh_sequence = cpu_to_be64(seq); lh->lh_flags = cpu_to_be32(flags); lh->lh_tail = cpu_to_be32(tail); lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head); - hash = gfs2_disk_hash(page_address(page), sizeof(struct gfs2_log_header)); + hash = ~crc32(~0, lh, LH_V1_SIZE); lh->lh_hash = cpu_to_be32(hash); + tv = current_kernel_time64(); + lh->lh_nsec = cpu_to_be32(tv.tv_nsec); + lh->lh_sec = cpu_to_be64(tv.tv_sec); + addr = gfs2_log_bmap(sdp); + lh->lh_addr = cpu_to_be64(addr); + lh->lh_jinode = cpu_to_be64(GFS2_I(jd->jd_inode)->i_no_addr); + + /* We may only write local statfs, quota, etc., when writing to our + own journal. The values are left 0 when recovering a journal + different from our own. */ + if (!(flags & GFS2_LOG_HEAD_RECOVERY)) { + lh->lh_statfs_addr = + cpu_to_be64(GFS2_I(sdp->sd_sc_inode)->i_no_addr); + lh->lh_quota_addr = + cpu_to_be64(GFS2_I(sdp->sd_qc_inode)->i_no_addr); + + spin_lock(&sdp->sd_statfs_spin); + lh->lh_local_total = cpu_to_be64(l_sc->sc_total); + lh->lh_local_free = cpu_to_be64(l_sc->sc_free); + lh->lh_local_dinodes = cpu_to_be64(l_sc->sc_dinodes); + spin_unlock(&sdp->sd_statfs_spin); + } + + BUILD_BUG_ON(offsetof(struct gfs2_log_header, lh_crc) != LH_V1_SIZE); + + crc = crc32c(~0, (void *)lh + LH_V1_SIZE + 4, + sb->s_blocksize - LH_V1_SIZE - 4); + lh->lh_crc = cpu_to_be32(crc); + + gfs2_log_write(sdp, page, sb->s_blocksize, 0, addr); + gfs2_log_flush_bio(sdp, REQ_OP_WRITE, op_flags); + log_flush_wait(sdp); +} + +/** + * log_write_header - Get and initialize a journal header buffer + * @sdp: The GFS2 superblock + * @flags: The log header flags, including log header origin + * + * Returns: the initialized log buffer descriptor + */ + +static void log_write_header(struct gfs2_sbd *sdp, u32 flags) +{ + unsigned int tail; + int op_flags = REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC; + enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state); + + gfs2_assert_withdraw(sdp, (state != SFS_FROZEN)); + tail = current_tail(sdp); + if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) { gfs2_ordered_wait(sdp); log_flush_wait(sdp); op_flags = REQ_SYNC | REQ_META | REQ_PRIO; } - sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); - gfs2_log_write_page(sdp, page); - gfs2_log_flush_bio(sdp, REQ_OP_WRITE, op_flags); - log_flush_wait(sdp); + gfs2_write_log_header(sdp, sdp->sd_jdesc, sdp->sd_log_sequence++, tail, + flags, op_flags); if (sdp->sd_log_tail != tail) log_pull_tail(sdp, tail); @@ -700,11 +757,11 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags) * gfs2_log_flush - flush incore transaction(s) * @sdp: the filesystem * @gl: The glock structure to flush. If NULL, flush the whole incore log + * @flags: The log header flags: GFS2_LOG_HEAD_FLUSH_* and debug flags * */ -void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, - enum gfs2_flush_type type) +void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) { struct gfs2_trans *tr; enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state); @@ -716,9 +773,9 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, up_write(&sdp->sd_log_flush_lock); return; } - trace_gfs2_log_flush(sdp, 1); + trace_gfs2_log_flush(sdp, 1, flags); - if (type == SHUTDOWN_FLUSH) + if (flags & GFS2_LOG_HEAD_FLUSH_SHUTDOWN) clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); sdp->sd_log_flush_head = sdp->sd_log_head; @@ -743,11 +800,11 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, if (sdp->sd_log_head != sdp->sd_log_flush_head) { log_flush_wait(sdp); - log_write_header(sdp, 0); + log_write_header(sdp, flags); } else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */ trace_gfs2_log_blocks(sdp, -1); - log_write_header(sdp, 0); + log_write_header(sdp, flags); } lops_after_commit(sdp, tr); @@ -764,7 +821,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, spin_unlock(&sdp->sd_ail_lock); gfs2_log_unlock(sdp); - if (type != NORMAL_FLUSH) { + if (!(flags & GFS2_LOG_HEAD_FLUSH_NORMAL)) { if (!sdp->sd_log_idle) { for (;;) { gfs2_ail1_start(sdp); @@ -774,16 +831,17 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, } atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */ trace_gfs2_log_blocks(sdp, -1); - log_write_header(sdp, 0); + log_write_header(sdp, flags); sdp->sd_log_head = sdp->sd_log_flush_head; } - if (type == SHUTDOWN_FLUSH || type == FREEZE_FLUSH) + if (flags & (GFS2_LOG_HEAD_FLUSH_SHUTDOWN | + GFS2_LOG_HEAD_FLUSH_FREEZE)) gfs2_log_shutdown(sdp); - if (type == FREEZE_FLUSH) + if (flags & GFS2_LOG_HEAD_FLUSH_FREEZE) atomic_set(&sdp->sd_freeze_state, SFS_FROZEN); } - trace_gfs2_log_flush(sdp, 0); + trace_gfs2_log_flush(sdp, 0, flags); up_write(&sdp->sd_log_flush_lock); kfree(tr); @@ -879,7 +937,7 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) sdp->sd_log_flush_head = sdp->sd_log_head; - log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT); + log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT | GFS2_LFC_SHUTDOWN); gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail); gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list)); @@ -935,7 +993,8 @@ int gfs2_logd(void *data) did_flush = false; if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { gfs2_ail1_empty(sdp); - gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_LOGD_JFLUSH_REQD); did_flush = true; } @@ -943,7 +1002,8 @@ int gfs2_logd(void *data) gfs2_ail1_start(sdp); gfs2_ail1_wait(sdp); gfs2_ail1_empty(sdp); - gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_LOGD_AIL_FLUSH_REQD); did_flush = true; } |