diff options
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/bmap.c | 26 | ||||
-rw-r--r-- | fs/gfs2/bmap.h | 1 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 2 | ||||
-rw-r--r-- | fs/gfs2/log.c | 24 | ||||
-rw-r--r-- | fs/gfs2/log.h | 3 | ||||
-rw-r--r-- | fs/gfs2/lops.c | 6 | ||||
-rw-r--r-- | fs/gfs2/lops.h | 2 | ||||
-rw-r--r-- | fs/gfs2/recovery.c | 10 | ||||
-rw-r--r-- | fs/gfs2/recovery.h | 2 |
9 files changed, 57 insertions, 19 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 2f9290f69610..59334e2edffb 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -925,6 +925,32 @@ do_alloc: 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) { struct gfs2_inode *ip = GFS2_I(inode); diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index 6b18fb323f0a..19a1fd772c61 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -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 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_lblk_to_dblk(struct inode *inode, u32 lblock, u64 *dblock); #endif /* __BMAP_DOT_H__ */ diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index cdf07b408f54..86840a70ee1a 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -535,7 +535,7 @@ struct gfs2_jdesc { unsigned long jd_flags; #define JDF_RECOVERY 1 unsigned int jd_jid; - unsigned int jd_blocks; + u32 jd_blocks; int jd_recover_error; /* Replay stuff */ diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index b8830fda51e8..ebbc68dca145 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -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 * @jd: journal descriptor of the journal to which we are writing * @seq: sequence number * @tail: tail of the log + * @lblock: value for lh_blkno (block number relative to start of journal) * @flags: log header flags GFS2_LOG_HEAD_* * @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, - 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; 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 timespec64 tv; struct super_block *sb = sdp->sd_vfs; - u64 addr; + u64 dblock; lh = page_address(page); 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_flags = cpu_to_be32(flags); 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); lh->lh_hash = cpu_to_be32(hash); ktime_get_coarse_real_ts64(&tv); 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); + if (!list_empty(&jd->extent_list)) + 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); /* 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); 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); 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); 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) log_pull_tail(sdp, tail); diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index 1bc9bd444b28..86d07d436cdf 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -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 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, - 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, u32 type); extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 8722c60b11fe..aef21b6a608f 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -530,7 +530,7 @@ static void buf_lo_before_scan(struct gfs2_jdesc *jd, 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, int pass) { @@ -685,7 +685,7 @@ static void revoke_lo_before_scan(struct gfs2_jdesc *jd, 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, 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); } -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, __be64 *ptr, int pass) { diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h index 711c4d89c063..4e81742de7a0 100644 --- a/fs/gfs2/lops.h +++ b/fs/gfs2/lops.h @@ -77,7 +77,7 @@ static inline void lops_before_scan(struct gfs2_jdesc *jd, 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, __be64 *ptr, unsigned int pass) diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 2dac43065382..fa575d1676b9 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -316,7 +316,7 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head) * 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) { 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_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, &sdp->sd_log_flush_head); - gfs2_write_log_header(sdp, jd, head->lh_sequence + 1, 0, + gfs2_replay_incr_blk(jd, &lblock); + if (jd->jd_jid == sdp->sd_lockstruct.ls_jid) + 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, REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC); } diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h index 11d81248be85..5932d4b6f43e 100644 --- a/fs/gfs2/recovery.h +++ b/fs/gfs2/recovery.h @@ -14,7 +14,7 @@ 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) *blk = 0; |