gfs2: clean_journal improperly set sd_log_flush_head

This patch fixes regressions in 588bff95c9.
Due to that patch, function clean_journal was setting the value of
sd_log_flush_head, but that's only valid if it is replaying the node's
own journal. If it's replaying another node's journal, that's completely
wrong and will lead to multiple problems. This patch tries to clean up
the mess by passing the value of the logical journal block number into
gfs2_write_log_header so the function can treat non-owned journals
generically. For the local journal, the journal extent map is used for
best performance. For other nodes from other journals, new function
gfs2_lblk_to_dblk is called to figure it out using gfs2_iomap_get.

This patch also tries to establish more consistency when passing journal
block parameters by changing several unsigned int types to a consistent
u32.

Fixes: 588bff95c9 ("GFS2: Reduce code redundancy writing log headers")
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
This commit is contained in:
Bob Peterson 2019-03-25 09:34:19 -06:00 committed by Andreas Gruenbacher
parent 7881ef3f33
commit 7c70b89695
9 changed files with 57 additions and 19 deletions

View File

@ -925,6 +925,32 @@ do_alloc:
goto out; goto out;
} }
/**
* gfs2_lblk_to_dblk - convert logical block to disk block
* @inode: the inode of the file we're mapping
* @lblock: the block relative to the start of the file
* @dblock: the returned dblock, if no error
*
* This function maps a single block from a file logical block (relative to
* the start of the file) to a file system absolute block using iomap.
*
* Returns: the absolute file system block, or an error
*/
int gfs2_lblk_to_dblk(struct inode *inode, u32 lblock, u64 *dblock)
{
struct iomap iomap = { };
struct metapath mp = { .mp_aheight = 1, };
loff_t pos = (loff_t)lblock << inode->i_blkbits;
int ret;
ret = gfs2_iomap_get(inode, pos, i_blocksize(inode), 0, &iomap, &mp);
release_metapath(&mp);
if (ret == 0)
*dblock = iomap.addr >> inode->i_blkbits;
return ret;
}
static int gfs2_write_lock(struct inode *inode) static int gfs2_write_lock(struct inode *inode)
{ {
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);

View File

@ -64,5 +64,6 @@ extern int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
extern int gfs2_map_journal_extents(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd); extern int gfs2_map_journal_extents(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd);
extern void gfs2_free_journal_extents(struct gfs2_jdesc *jd); extern void gfs2_free_journal_extents(struct gfs2_jdesc *jd);
extern int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length); extern int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length);
extern int gfs2_lblk_to_dblk(struct inode *inode, u32 lblock, u64 *dblock);
#endif /* __BMAP_DOT_H__ */ #endif /* __BMAP_DOT_H__ */

View File

@ -535,7 +535,7 @@ struct gfs2_jdesc {
unsigned long jd_flags; unsigned long jd_flags;
#define JDF_RECOVERY 1 #define JDF_RECOVERY 1
unsigned int jd_jid; unsigned int jd_jid;
unsigned int jd_blocks; u32 jd_blocks;
int jd_recover_error; int jd_recover_error;
/* Replay stuff */ /* Replay stuff */

View File

@ -666,11 +666,12 @@ out_of_blocks:
} }
/** /**
* write_log_header - Write a journal log header buffer at sd_log_flush_head * gfs2_write_log_header - Write a journal log header buffer at lblock
* @sdp: The GFS2 superblock * @sdp: The GFS2 superblock
* @jd: journal descriptor of the journal to which we are writing * @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
* @lblock: value for lh_blkno (block number relative to start of journal)
* @flags: log header flags GFS2_LOG_HEAD_* * @flags: log header flags GFS2_LOG_HEAD_*
* @op_flags: flags to pass to the bio * @op_flags: flags to pass to the bio
* *
@ -678,7 +679,8 @@ out_of_blocks:
*/ */
void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
u64 seq, u32 tail, u32 flags, int op_flags) u64 seq, u32 tail, u32 lblock, u32 flags,
int op_flags)
{ {
struct gfs2_log_header *lh; struct gfs2_log_header *lh;
u32 hash, crc; u32 hash, crc;
@ -686,7 +688,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
struct timespec64 tv; struct timespec64 tv;
struct super_block *sb = sdp->sd_vfs; struct super_block *sb = sdp->sd_vfs;
u64 addr; u64 dblock;
lh = page_address(page); lh = page_address(page);
clear_page(lh); clear_page(lh);
@ -699,15 +701,21 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
lh->lh_sequence = cpu_to_be64(seq); lh->lh_sequence = cpu_to_be64(seq);
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(lblock);
hash = ~crc32(~0, lh, LH_V1_SIZE); hash = ~crc32(~0, lh, LH_V1_SIZE);
lh->lh_hash = cpu_to_be32(hash); lh->lh_hash = cpu_to_be32(hash);
ktime_get_coarse_real_ts64(&tv); ktime_get_coarse_real_ts64(&tv);
lh->lh_nsec = cpu_to_be32(tv.tv_nsec); lh->lh_nsec = cpu_to_be32(tv.tv_nsec);
lh->lh_sec = cpu_to_be64(tv.tv_sec); lh->lh_sec = cpu_to_be64(tv.tv_sec);
addr = gfs2_log_bmap(sdp); if (!list_empty(&jd->extent_list))
lh->lh_addr = cpu_to_be64(addr); dblock = gfs2_log_bmap(sdp);
else {
int ret = gfs2_lblk_to_dblk(jd->jd_inode, lblock, &dblock);
if (gfs2_assert_withdraw(sdp, ret == 0))
return;
}
lh->lh_addr = cpu_to_be64(dblock);
lh->lh_jinode = cpu_to_be64(GFS2_I(jd->jd_inode)->i_no_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 /* We may only write local statfs, quota, etc., when writing to our
@ -732,7 +740,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
sb->s_blocksize - LH_V1_SIZE - 4); sb->s_blocksize - LH_V1_SIZE - 4);
lh->lh_crc = cpu_to_be32(crc); lh->lh_crc = cpu_to_be32(crc);
gfs2_log_write(sdp, page, sb->s_blocksize, 0, addr); gfs2_log_write(sdp, page, sb->s_blocksize, 0, dblock);
gfs2_log_submit_bio(&sdp->sd_log_bio, REQ_OP_WRITE, op_flags); gfs2_log_submit_bio(&sdp->sd_log_bio, REQ_OP_WRITE, op_flags);
log_flush_wait(sdp); log_flush_wait(sdp);
} }
@ -761,7 +769,7 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
} }
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_jdesc, sdp->sd_log_sequence++, tail, gfs2_write_log_header(sdp, sdp->sd_jdesc, sdp->sd_log_sequence++, tail,
flags, op_flags); sdp->sd_log_flush_head, 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);

View File

@ -70,7 +70,8 @@ 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);
extern void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, extern void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
u64 seq, u32 tail, u32 flags, int op_flags); u64 seq, u32 tail, u32 lblock, 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,
u32 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);

View File

@ -530,7 +530,7 @@ static void buf_lo_before_scan(struct gfs2_jdesc *jd,
jd->jd_replayed_blocks = 0; jd->jd_replayed_blocks = 0;
} }
static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, static int buf_lo_scan_elements(struct gfs2_jdesc *jd, u32 start,
struct gfs2_log_descriptor *ld, __be64 *ptr, struct gfs2_log_descriptor *ld, __be64 *ptr,
int pass) int pass)
{ {
@ -685,7 +685,7 @@ static void revoke_lo_before_scan(struct gfs2_jdesc *jd,
jd->jd_replay_tail = head->lh_tail; jd->jd_replay_tail = head->lh_tail;
} }
static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, u32 start,
struct gfs2_log_descriptor *ld, __be64 *ptr, struct gfs2_log_descriptor *ld, __be64 *ptr,
int pass) int pass)
{ {
@ -767,7 +767,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr
gfs2_before_commit(sdp, limit, nbuf, &tr->tr_databuf, 1); gfs2_before_commit(sdp, limit, nbuf, &tr->tr_databuf, 1);
} }
static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, u32 start,
struct gfs2_log_descriptor *ld, struct gfs2_log_descriptor *ld,
__be64 *ptr, int pass) __be64 *ptr, int pass)
{ {

View File

@ -77,7 +77,7 @@ static inline void lops_before_scan(struct gfs2_jdesc *jd,
gfs2_log_ops[x]->lo_before_scan(jd, head, pass); gfs2_log_ops[x]->lo_before_scan(jd, head, pass);
} }
static inline int lops_scan_elements(struct gfs2_jdesc *jd, unsigned int start, static inline int lops_scan_elements(struct gfs2_jdesc *jd, u32 start,
struct gfs2_log_descriptor *ld, struct gfs2_log_descriptor *ld,
__be64 *ptr, __be64 *ptr,
unsigned int pass) unsigned int pass)

View File

@ -316,7 +316,7 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
* Returns: errno * Returns: errno
*/ */
static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, static int foreach_descriptor(struct gfs2_jdesc *jd, u32 start,
unsigned int end, int pass) unsigned int end, int pass)
{ {
struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
@ -386,10 +386,12 @@ static void clean_journal(struct gfs2_jdesc *jd,
struct gfs2_log_header_host *head) struct gfs2_log_header_host *head)
{ {
struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
u32 lblock = head->lh_blkno;
sdp->sd_log_flush_head = head->lh_blkno; gfs2_replay_incr_blk(jd, &lblock);
gfs2_replay_incr_blk(jd, &sdp->sd_log_flush_head); if (jd->jd_jid == sdp->sd_lockstruct.ls_jid)
gfs2_write_log_header(sdp, jd, head->lh_sequence + 1, 0, sdp->sd_log_flush_head = lblock;
gfs2_write_log_header(sdp, jd, head->lh_sequence + 1, 0, lblock,
GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_RECOVERY, GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_RECOVERY,
REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC); REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC);
} }

View File

@ -14,7 +14,7 @@
extern struct workqueue_struct *gfs_recovery_wq; extern struct workqueue_struct *gfs_recovery_wq;
static inline void gfs2_replay_incr_blk(struct gfs2_jdesc *jd, unsigned int *blk) static inline void gfs2_replay_incr_blk(struct gfs2_jdesc *jd, u32 *blk)
{ {
if (++*blk == jd->jd_blocks) if (++*blk == jd->jd_blocks)
*blk = 0; *blk = 0;