Commit c1696fb8 authored by Bob Peterson's avatar Bob Peterson

GFS2: Introduce new gfs2_log_header_v2

This patch adds a new structure called gfs2_log_header_v2 which is used
to store expanded fields into previously unused areas of the log headers
(i.e., this change is backwards compatible).  Some of these are used for
debug purposes so we can backtrack when problems occur.  Others are
reserved for future expansion.

This patch is based on a prototype from Steve Whitehouse.
Signed-off-by: default avatarBob Peterson <rpeterso@redhat.com>
Signed-off-by: default avatarAndreas Gruenbacher <agruenba@redhat.com>
parent 0ff5916a
...@@ -3,6 +3,8 @@ config GFS2_FS ...@@ -3,6 +3,8 @@ config GFS2_FS
depends on (64BIT || LBDAF) depends on (64BIT || LBDAF)
select FS_POSIX_ACL select FS_POSIX_ACL
select CRC32 select CRC32
select CRYPTO
select CRYPTO_CRC32C
select QUOTACTL select QUOTACTL
select FS_IOMAP select FS_IOMAP
help help
......
...@@ -448,7 +448,7 @@ static int gfs2_jdata_writepages(struct address_space *mapping, ...@@ -448,7 +448,7 @@ static int gfs2_jdata_writepages(struct address_space *mapping,
ret = gfs2_write_cache_jdata(mapping, wbc); ret = gfs2_write_cache_jdata(mapping, wbc);
if (ret == 0 && wbc->sync_mode == WB_SYNC_ALL) { if (ret == 0 && wbc->sync_mode == WB_SYNC_ALL) {
gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH); gfs2_log_flush(sdp, ip->i_gl, GFS2_LOG_HEAD_FLUSH_NORMAL);
ret = gfs2_write_cache_jdata(mapping, wbc); ret = gfs2_write_cache_jdata(mapping, wbc);
} }
return ret; return ret;
......
...@@ -246,7 +246,8 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) ...@@ -246,7 +246,8 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
} }
if ((flags ^ new_flags) & GFS2_DIF_JDATA) { if ((flags ^ new_flags) & GFS2_DIF_JDATA) {
if (new_flags & GFS2_DIF_JDATA) if (new_flags & GFS2_DIF_JDATA)
gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH); gfs2_log_flush(sdp, ip->i_gl,
GFS2_LOG_HEAD_FLUSH_NORMAL);
error = filemap_fdatawrite(inode->i_mapping); error = filemap_fdatawrite(inode->i_mapping);
if (error) if (error)
goto out; goto out;
......
...@@ -107,7 +107,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) ...@@ -107,7 +107,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
__gfs2_ail_flush(gl, 0, tr.tr_revokes); __gfs2_ail_flush(gl, 0, tr.tr_revokes);
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL);
} }
void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
...@@ -128,7 +128,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) ...@@ -128,7 +128,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
return; return;
__gfs2_ail_flush(gl, fsync, max_revokes); __gfs2_ail_flush(gl, fsync, max_revokes);
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL);
} }
/** /**
...@@ -157,7 +157,7 @@ static void rgrp_go_sync(struct gfs2_glock *gl) ...@@ -157,7 +157,7 @@ static void rgrp_go_sync(struct gfs2_glock *gl)
return; return;
GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE); GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE);
gfs2_log_flush(sdp, gl, NORMAL_FLUSH); gfs2_log_flush(sdp, gl, GFS2_LOG_HEAD_FLUSH_NORMAL);
filemap_fdatawrite_range(mapping, gl->gl_vm.start, gl->gl_vm.end); filemap_fdatawrite_range(mapping, gl->gl_vm.start, gl->gl_vm.end);
error = filemap_fdatawait_range(mapping, gl->gl_vm.start, gl->gl_vm.end); error = filemap_fdatawait_range(mapping, gl->gl_vm.start, gl->gl_vm.end);
mapping_set_error(mapping, error); mapping_set_error(mapping, error);
...@@ -252,7 +252,7 @@ static void inode_go_sync(struct gfs2_glock *gl) ...@@ -252,7 +252,7 @@ static void inode_go_sync(struct gfs2_glock *gl)
GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE); GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE);
gfs2_log_flush(gl->gl_name.ln_sbd, gl, NORMAL_FLUSH); gfs2_log_flush(gl->gl_name.ln_sbd, gl, GFS2_LOG_HEAD_FLUSH_NORMAL);
filemap_fdatawrite(metamapping); filemap_fdatawrite(metamapping);
if (isreg) { if (isreg) {
struct address_space *mapping = ip->i_inode.i_mapping; struct address_space *mapping = ip->i_inode.i_mapping;
...@@ -303,7 +303,8 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) ...@@ -303,7 +303,8 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)
} }
if (ip == GFS2_I(gl->gl_name.ln_sbd->sd_rindex)) { if (ip == GFS2_I(gl->gl_name.ln_sbd->sd_rindex)) {
gfs2_log_flush(gl->gl_name.ln_sbd, NULL, NORMAL_FLUSH); gfs2_log_flush(gl->gl_name.ln_sbd, NULL,
GFS2_LOG_HEAD_FLUSH_NORMAL);
gl->gl_name.ln_sbd->sd_rindex_uptodate = 0; gl->gl_name.ln_sbd->sd_rindex_uptodate = 0;
} }
if (ip && S_ISREG(ip->i_inode.i_mode)) if (ip && S_ISREG(ip->i_inode.i_mode))
...@@ -495,7 +496,7 @@ static void freeze_go_sync(struct gfs2_glock *gl) ...@@ -495,7 +496,7 @@ static void freeze_go_sync(struct gfs2_glock *gl)
gfs2_assert_withdraw(sdp, 0); gfs2_assert_withdraw(sdp, 0);
} }
queue_work(gfs2_freeze_wq, &sdp->sd_freeze_work); queue_work(gfs2_freeze_wq, &sdp->sd_freeze_work);
gfs2_log_flush(sdp, NULL, FREEZE_FLUSH); gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_FREEZE);
} }
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/crc32c.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/freezer.h> #include <linux/freezer.h>
...@@ -653,20 +654,25 @@ void gfs2_write_revokes(struct gfs2_sbd *sdp) ...@@ -653,20 +654,25 @@ void gfs2_write_revokes(struct gfs2_sbd *sdp)
/** /**
* write_log_header - Write a journal log header buffer at sd_log_flush_head * write_log_header - Write a journal log header buffer at sd_log_flush_head
* @sdp: The GFS2 superblock * @sdp: The GFS2 superblock
* @jd: journal descriptor of the journal to which we are writing
* @seq: sequence number * @seq: sequence number
* @tail: tail of the log * @tail: tail of the log
* @flags: log header flags * @flags: log header flags GFS2_LOG_HEAD_*
* @op_flags: flags to pass to the bio * @op_flags: flags to pass to the bio
* *
* Returns: the initialized log buffer descriptor * Returns: the initialized log buffer descriptor
*/ */
void gfs2_write_log_header(struct gfs2_sbd *sdp, u64 seq, u32 tail, void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
u32 flags, int op_flags) u64 seq, u32 tail, u32 flags, int op_flags)
{ {
struct gfs2_log_header *lh; struct gfs2_log_header *lh;
u32 hash; u32 hash, crc;
struct page *page = mempool_alloc(gfs2_page_pool, GFP_NOIO); struct page *page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
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); lh = page_address(page);
clear_page(lh); clear_page(lh);
...@@ -680,10 +686,39 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, u64 seq, u32 tail, ...@@ -680,10 +686,39 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, u64 seq, u32 tail,
lh->lh_flags = cpu_to_be32(flags); lh->lh_flags = cpu_to_be32(flags);
lh->lh_tail = cpu_to_be32(tail); lh->lh_tail = cpu_to_be32(tail);
lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head); lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head);
hash = ~crc32(~0, lh, sizeof(*lh)); hash = ~crc32(~0, lh, LH_V1_SIZE);
lh->lh_hash = cpu_to_be32(hash); lh->lh_hash = cpu_to_be32(hash);
gfs2_log_write_page(sdp, page); 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); gfs2_log_flush_bio(sdp, REQ_OP_WRITE, op_flags);
log_flush_wait(sdp); log_flush_wait(sdp);
} }
...@@ -691,6 +726,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, u64 seq, u32 tail, ...@@ -691,6 +726,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, u64 seq, u32 tail,
/** /**
* log_write_header - Get and initialize a journal header buffer * log_write_header - Get and initialize a journal header buffer
* @sdp: The GFS2 superblock * @sdp: The GFS2 superblock
* @flags: The log header flags, including log header origin
* *
* Returns: the initialized log buffer descriptor * Returns: the initialized log buffer descriptor
*/ */
...@@ -710,8 +746,8 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags) ...@@ -710,8 +746,8 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
op_flags = REQ_SYNC | REQ_META | REQ_PRIO; op_flags = REQ_SYNC | REQ_META | REQ_PRIO;
} }
sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
gfs2_write_log_header(sdp, sdp->sd_log_sequence++, tail, flags, gfs2_write_log_header(sdp, sdp->sd_jdesc, sdp->sd_log_sequence++, tail,
op_flags); flags, op_flags);
if (sdp->sd_log_tail != tail) if (sdp->sd_log_tail != tail)
log_pull_tail(sdp, tail); log_pull_tail(sdp, tail);
...@@ -721,11 +757,11 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags) ...@@ -721,11 +757,11 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
* gfs2_log_flush - flush incore transaction(s) * gfs2_log_flush - flush incore transaction(s)
* @sdp: the filesystem * @sdp: the filesystem
* @gl: The glock structure to flush. If NULL, flush the whole incore log * @gl: The glock structure to flush. If NULL, flush the whole incore log
* @flags: The log header flags: GFS2_LOG_HEAD_FLUSH_*
* *
*/ */
void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
enum gfs2_flush_type type)
{ {
struct gfs2_trans *tr; struct gfs2_trans *tr;
enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state); enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
...@@ -739,7 +775,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, ...@@ -739,7 +775,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
} }
trace_gfs2_log_flush(sdp, 1); trace_gfs2_log_flush(sdp, 1);
if (type == SHUTDOWN_FLUSH) if (flags & GFS2_LOG_HEAD_FLUSH_SHUTDOWN)
clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
sdp->sd_log_flush_head = sdp->sd_log_head; sdp->sd_log_flush_head = sdp->sd_log_head;
...@@ -764,11 +800,11 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, ...@@ -764,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) { if (sdp->sd_log_head != sdp->sd_log_flush_head) {
log_flush_wait(sdp); 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){ } else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */ atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */
trace_gfs2_log_blocks(sdp, -1); trace_gfs2_log_blocks(sdp, -1);
log_write_header(sdp, 0); log_write_header(sdp, flags);
} }
lops_after_commit(sdp, tr); lops_after_commit(sdp, tr);
...@@ -785,7 +821,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, ...@@ -785,7 +821,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
spin_unlock(&sdp->sd_ail_lock); spin_unlock(&sdp->sd_ail_lock);
gfs2_log_unlock(sdp); gfs2_log_unlock(sdp);
if (type != NORMAL_FLUSH) { if (!(flags & GFS2_LOG_HEAD_FLUSH_NORMAL)) {
if (!sdp->sd_log_idle) { if (!sdp->sd_log_idle) {
for (;;) { for (;;) {
gfs2_ail1_start(sdp); gfs2_ail1_start(sdp);
...@@ -795,12 +831,13 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, ...@@ -795,12 +831,13 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
} }
atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */ atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */
trace_gfs2_log_blocks(sdp, -1); 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; 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); gfs2_log_shutdown(sdp);
if (type == FREEZE_FLUSH) if (flags & GFS2_LOG_HEAD_FLUSH_FREEZE)
atomic_set(&sdp->sd_freeze_state, SFS_FROZEN); atomic_set(&sdp->sd_freeze_state, SFS_FROZEN);
} }
...@@ -956,7 +993,7 @@ int gfs2_logd(void *data) ...@@ -956,7 +993,7 @@ int gfs2_logd(void *data)
did_flush = false; did_flush = false;
if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { if (gfs2_jrnl_flush_reqd(sdp) || t == 0) {
gfs2_ail1_empty(sdp); gfs2_ail1_empty(sdp);
gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL);
did_flush = true; did_flush = true;
} }
...@@ -964,7 +1001,7 @@ int gfs2_logd(void *data) ...@@ -964,7 +1001,7 @@ int gfs2_logd(void *data)
gfs2_ail1_start(sdp); gfs2_ail1_start(sdp);
gfs2_ail1_wait(sdp); gfs2_ail1_wait(sdp);
gfs2_ail1_empty(sdp); gfs2_ail1_empty(sdp);
gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL);
did_flush = true; did_flush = true;
} }
......
...@@ -65,16 +65,10 @@ extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, ...@@ -65,16 +65,10 @@ extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
extern void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks); extern void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks);
extern int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks); extern int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
enum gfs2_flush_type { extern void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
NORMAL_FLUSH = 0, u64 seq, u32 tail, u32 flags, int op_flags);
SYNC_FLUSH,
SHUTDOWN_FLUSH,
FREEZE_FLUSH
};
extern void gfs2_write_log_header(struct gfs2_sbd *sdp, u64 seq, u32 tail,
u32 flags, int op_flags);
extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
enum gfs2_flush_type type); u32 type);
extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans); extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd); extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
extern void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc); extern void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/list_sort.h> #include <linux/list_sort.h>
#include "dir.h"
#include "gfs2.h" #include "gfs2.h"
#include "incore.h" #include "incore.h"
#include "inode.h" #include "inode.h"
...@@ -138,7 +139,7 @@ static void gfs2_log_incr_head(struct gfs2_sbd *sdp) ...@@ -138,7 +139,7 @@ static void gfs2_log_incr_head(struct gfs2_sbd *sdp)
sdp->sd_log_flush_head = 0; sdp->sd_log_flush_head = 0;
} }
static u64 gfs2_log_bmap(struct gfs2_sbd *sdp) u64 gfs2_log_bmap(struct gfs2_sbd *sdp)
{ {
unsigned int lbn = sdp->sd_log_flush_head; unsigned int lbn = sdp->sd_log_flush_head;
struct gfs2_journal_extent *je; struct gfs2_journal_extent *je;
...@@ -306,23 +307,22 @@ static struct bio *gfs2_log_get_bio(struct gfs2_sbd *sdp, u64 blkno) ...@@ -306,23 +307,22 @@ static struct bio *gfs2_log_get_bio(struct gfs2_sbd *sdp, u64 blkno)
return gfs2_log_alloc_bio(sdp, blkno); return gfs2_log_alloc_bio(sdp, blkno);
} }
/** /**
* gfs2_log_write - write to log * gfs2_log_write - write to log
* @sdp: the filesystem * @sdp: the filesystem
* @page: the page to write * @page: the page to write
* @size: the size of the data to write * @size: the size of the data to write
* @offset: the offset within the page * @offset: the offset within the page
* @blkno: block number of the log entry
* *
* Try and add the page segment to the current bio. If that fails, * Try and add the page segment to the current bio. If that fails,
* submit the current bio to the device and create a new one, and * submit the current bio to the device and create a new one, and
* then add the page segment to that. * then add the page segment to that.
*/ */
static void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page, void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page,
unsigned size, unsigned offset) unsigned size, unsigned offset, u64 blkno)
{ {
u64 blkno = gfs2_log_bmap(sdp);
struct bio *bio; struct bio *bio;
int ret; int ret;
...@@ -348,7 +348,8 @@ static void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page, ...@@ -348,7 +348,8 @@ static void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page,
static void gfs2_log_write_bh(struct gfs2_sbd *sdp, struct buffer_head *bh) static void gfs2_log_write_bh(struct gfs2_sbd *sdp, struct buffer_head *bh)
{ {
gfs2_log_write(sdp, bh->b_page, bh->b_size, bh_offset(bh)); gfs2_log_write(sdp, bh->b_page, bh->b_size, bh_offset(bh),
gfs2_log_bmap(sdp));
} }
/** /**
...@@ -365,7 +366,8 @@ static void gfs2_log_write_bh(struct gfs2_sbd *sdp, struct buffer_head *bh) ...@@ -365,7 +366,8 @@ static void gfs2_log_write_bh(struct gfs2_sbd *sdp, struct buffer_head *bh)
void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page) void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page)
{ {
struct super_block *sb = sdp->sd_vfs; struct super_block *sb = sdp->sd_vfs;
gfs2_log_write(sdp, page, sb->s_blocksize, 0); gfs2_log_write(sdp, page, sb->s_blocksize, 0,
gfs2_log_bmap(sdp));
} }
static struct page *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type, static struct page *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type,
......
...@@ -26,6 +26,9 @@ extern const struct gfs2_log_operations gfs2_revoke_lops; ...@@ -26,6 +26,9 @@ extern const struct gfs2_log_operations gfs2_revoke_lops;
extern const struct gfs2_log_operations gfs2_databuf_lops; extern const struct gfs2_log_operations gfs2_databuf_lops;
extern const struct gfs2_log_operations *gfs2_log_ops[]; extern const struct gfs2_log_operations *gfs2_log_ops[];
extern u64 gfs2_log_bmap(struct gfs2_sbd *sdp);
extern void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page,
unsigned size, unsigned offset, u64 blkno);
extern void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page); extern void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page);
extern void gfs2_log_flush_bio(struct gfs2_sbd *sdp, int op, int op_flags); extern void gfs2_log_flush_bio(struct gfs2_sbd *sdp, int op, int op_flags);
extern void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh); extern void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh);
......
...@@ -1382,7 +1382,7 @@ static void gfs2_kill_sb(struct super_block *sb) ...@@ -1382,7 +1382,7 @@ static void gfs2_kill_sb(struct super_block *sb)
return; return;
} }
gfs2_log_flush(sdp, NULL, SYNC_FLUSH); gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_SYNC);
dput(sdp->sd_root_dir); dput(sdp->sd_root_dir);
dput(sdp->sd_master_dir); dput(sdp->sd_master_dir);
sdp->sd_root_dir = NULL; sdp->sd_root_dir = NULL;
......
...@@ -955,7 +955,8 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) ...@@ -955,7 +955,8 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
gfs2_glock_dq_uninit(&ghs[qx]); gfs2_glock_dq_uninit(&ghs[qx]);
inode_unlock(&ip->i_inode); inode_unlock(&ip->i_inode);
kfree(ghs); kfree(ghs);
gfs2_log_flush(ip->i_gl->gl_name.ln_sbd, ip->i_gl, NORMAL_FLUSH); gfs2_log_flush(ip->i_gl->gl_name.ln_sbd, ip->i_gl,
GFS2_LOG_HEAD_FLUSH_NORMAL);
return error; return error;
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/crc32c.h>
#include "gfs2.h" #include "gfs2.h"
#include "incore.h" #include "incore.h"
...@@ -137,7 +138,7 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, ...@@ -137,7 +138,7 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk,
{ {
struct gfs2_log_header *lh; struct gfs2_log_header *lh;
struct buffer_head *bh; struct buffer_head *bh;
u32 hash; u32 hash, crc;
int error; int error;
error = gfs2_replay_read_block(jd, blk, &bh); error = gfs2_replay_read_block(jd, blk, &bh);
...@@ -145,13 +146,17 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, ...@@ -145,13 +146,17 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk,
return error; return error;
lh = (void *)bh->b_data; lh = (void *)bh->b_data;
hash = crc32(~0, lh, sizeof(*lh) - 4); hash = crc32(~0, lh, LH_V1_SIZE - 4);
hash = ~crc32_le_shift(hash, 4); /* assume lh_hash is zero */ hash = ~crc32_le_shift(hash, 4); /* assume lh_hash is zero */
crc = crc32c(~0, (void *)lh + LH_V1_SIZE + 4,
bh->b_size - LH_V1_SIZE - 4);
error = lh->lh_header.mh_magic != cpu_to_be32(GFS2_MAGIC) || error = lh->lh_header.mh_magic != cpu_to_be32(GFS2_MAGIC) ||
lh->lh_header.mh_type != cpu_to_be32(GFS2_METATYPE_LH) || lh->lh_header.mh_type != cpu_to_be32(GFS2_METATYPE_LH) ||
be32_to_cpu(lh->lh_blkno) != blk || be32_to_cpu(lh->lh_blkno) != blk ||
be32_to_cpu(lh->lh_hash) != hash; be32_to_cpu(lh->lh_hash) != hash ||
(lh->lh_crc != 0 && be32_to_cpu(lh->lh_crc) != crc);
brelse(bh); brelse(bh);
...@@ -372,9 +377,9 @@ static void clean_journal(struct gfs2_jdesc *jd, ...@@ -372,9 +377,9 @@ static void clean_journal(struct gfs2_jdesc *jd,
sdp->sd_log_flush_head = head->lh_blkno; sdp->sd_log_flush_head = head->lh_blkno;
gfs2_replay_incr_blk(jd, &sdp->sd_log_flush_head); gfs2_replay_incr_blk(jd, &sdp->sd_log_flush_head);
gfs2_write_log_header(sdp, head->lh_sequence + 1, 0, gfs2_write_log_header(sdp, jd, head->lh_sequence + 1, 0,
GFS2_LOG_HEAD_UNMOUNT, REQ_PREFLUSH | GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_RECOVERY,
REQ_FUA | REQ_META | REQ_SYNC); REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC);
} }
......
...@@ -2093,7 +2093,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap) ...@@ -2093,7 +2093,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap)
} }
/* Flushing the log may release space */ /* Flushing the log may release space */
if (loops == 2) if (loops == 2)
gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL);
} }
return -ENOSPC; return -ENOSPC;
......
...@@ -757,7 +757,8 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -757,7 +757,8 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
bool flush_all = (wbc->sync_mode == WB_SYNC_ALL || gfs2_is_jdata(ip)); bool flush_all = (wbc->sync_mode == WB_SYNC_ALL || gfs2_is_jdata(ip));
if (flush_all) if (flush_all)
gfs2_log_flush(GFS2_SB(inode), ip->i_gl, NORMAL_FLUSH); gfs2_log_flush(GFS2_SB(inode), ip->i_gl,
GFS2_LOG_HEAD_FLUSH_NORMAL);
if (bdi->wb.dirty_exceeded) if (bdi->wb.dirty_exceeded)
gfs2_ail1_flush(sdp, wbc); gfs2_ail1_flush(sdp, wbc);
else else
...@@ -853,7 +854,7 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) ...@@ -853,7 +854,7 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
gfs2_quota_sync(sdp->sd_vfs, 0); gfs2_quota_sync(sdp->sd_vfs, 0);
gfs2_statfs_sync(sdp->sd_vfs, 0); gfs2_statfs_sync(sdp->sd_vfs, 0);
gfs2_log_flush(sdp, NULL, SHUTDOWN_FLUSH); gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_SHUTDOWN);
wait_event(sdp->sd_reserving_log_wait, atomic_read(&sdp->sd_reserving_log) == 0); wait_event(sdp->sd_reserving_log_wait, atomic_read(&sdp->sd_reserving_log) == 0);
gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks); gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks);
...@@ -946,7 +947,7 @@ static int gfs2_sync_fs(struct super_block *sb, int wait) ...@@ -946,7 +947,7 @@ static int gfs2_sync_fs(struct super_block *sb, int wait)
gfs2_quota_sync(sb, -1); gfs2_quota_sync(sb, -1);
if (wait) if (wait)
gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL);
return sdp->sd_log_error; return sdp->sd_log_error;
} }
...@@ -1650,7 +1651,7 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1650,7 +1651,7 @@ static void gfs2_evict_inode(struct inode *inode)
goto out_unlock; goto out_unlock;
out_truncate: out_truncate:
gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH); gfs2_log_flush(sdp, ip->i_gl, GFS2_LOG_HEAD_FLUSH_NORMAL);
metamapping = gfs2_glock2aspace(ip->i_gl); metamapping = gfs2_glock2aspace(ip->i_gl);
if (test_bit(GLF_DIRTY, &ip->i_gl->gl_flags)) { if (test_bit(GLF_DIRTY, &ip->i_gl->gl_flags)) {
filemap_fdatawrite(metamapping); filemap_fdatawrite(metamapping);
......
...@@ -117,7 +117,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) ...@@ -117,7 +117,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
up_read(&sdp->sd_log_flush_lock); up_read(&sdp->sd_log_flush_lock);
if (sdp->sd_vfs->s_flags & SB_SYNCHRONOUS) if (sdp->sd_vfs->s_flags & SB_SYNCHRONOUS)
gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL);
if (alloced) if (alloced)
sb_end_intwrite(sdp->sd_vfs); sb_end_intwrite(sdp->sd_vfs);
} }
......
...@@ -403,7 +403,15 @@ struct gfs2_ea_header { ...@@ -403,7 +403,15 @@ struct gfs2_ea_header {
* Log header structure * Log header structure
*/ */
#define GFS2_LOG_HEAD_UNMOUNT 0x00000001 /* log is clean */ #define GFS2_LOG_HEAD_UNMOUNT 0x00000001 /* log is clean */
#define GFS2_LOG_HEAD_FLUSH_NORMAL 0x00000002 /* normal log flush */
#define GFS2_LOG_HEAD_FLUSH_SYNC 0x00000004 /* Sync log flush */
#define GFS2_LOG_HEAD_FLUSH_SHUTDOWN 0x00000008 /* Shutdown log flush */
#define GFS2_LOG_HEAD_FLUSH_FREEZE 0x00000010 /* Freeze flush */
#define GFS2_LOG_HEAD_RECOVERY 0x00000020 /* Journal recovery */
#define GFS2_LOG_HEAD_USERSPACE 0x80000000 /* Written by gfs2-utils */
#define LH_V1_SIZE (offsetofend(struct gfs2_log_header, lh_hash))
struct gfs2_log_header { struct gfs2_log_header {
struct gfs2_meta_header lh_header; struct gfs2_meta_header lh_header;
...@@ -412,7 +420,21 @@ struct gfs2_log_header { ...@@ -412,7 +420,21 @@ struct gfs2_log_header {
__be32 lh_flags; /* GFS2_LOG_HEAD_... */ __be32 lh_flags; /* GFS2_LOG_HEAD_... */
__be32 lh_tail; /* Block number of log tail */ __be32 lh_tail; /* Block number of log tail */
__be32 lh_blkno; __be32 lh_blkno;
__be32 lh_hash; __be32 lh_hash; /* crc up to here with this field 0 */
/* Version 2 additional fields start here */
__be32 lh_crc; /* crc32c from lh_nsec to end of block */
__be32 lh_nsec; /* Nanoseconds of timestamp */
__be64 lh_sec; /* Seconds of timestamp */
__be64 lh_addr; /* Block addr of this log header (absolute) */
__be64 lh_jinode; /* Journal inode number */
__be64 lh_statfs_addr; /* Local statfs inode number */
__be64 lh_quota_addr; /* Local quota change inode number */
/* Statfs local changes (i.e. diff from global statfs) */
__be64 lh_local_total;
__be64 lh_local_free;
__be64 lh_local_dinodes;
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment