diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-04 23:09:42 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-04 23:09:42 +0300 |
commit | 2bd99df54f43b659ddaab8922adbaf3bcf3753ed (patch) | |
tree | 5a12962375b3b755f3b8b8420490f0275858dcf2 /fs | |
parent | 94514bbe9e5c402c4232af158a295a8fdfd72a2c (diff) | |
parent | 5e86d9d122d0d6fae00d9dff41c22d6f4d09f566 (diff) | |
download | linux-2bd99df54f43b659ddaab8922adbaf3bcf3753ed.tar.xz |
Merge tag 'gfs2-4.17.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2
Pull gfs2 updates from Bob Peterson:
"We've only got nine GFS2 patches for this merge window:
- report journal recovery times more accurately during journal replay
(Abhi Das)
- fix fallocate chunk size (Andreas Gruenbacher)
- correctly dirty inodes during rename (Andreas Gruenbacher)
- improve the comment for function gfs2_block_map (Andreas
Gruenbacher)
- improve kernel trace point iomap end: The physical block address
was added (Andreas Gruenbacher)
- fix a nasty file system corruption bug that surfaced in xfstests
476 in punch-hole/truncate (Andreas Gruenbacher)
- fix a problem Christoph Helwig pointed out, namely, that GFS2 was
misusing the IOMAP_ZERO flag. The zeroing of new blocks was moved
to the proper fallocate code (Andreas Gruenbacher)
- declare function gfs2_remove_from_ail as static (Bob Peterson)
- only set PageChecked for jdata page writes (Bob Peterson)"
* tag 'gfs2-4.17.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
gfs2: time journal recovery steps accurately
gfs2: Zero out fallocated blocks in fallocate_chunk
gfs2: Check for the end of metadata in punch_hole
gfs2: gfs2_iomap_end tracepoint: log block address
gfs2: Improve gfs2_block_map comment
GFS2: Only set PageChecked for jdata pages
GFS2: Make function gfs2_remove_from_ail static
gfs2: Dirty source inode during rename
gfs2: Fix fallocate chunk size
Diffstat (limited to 'fs')
-rw-r--r-- | fs/gfs2/aops.c | 8 | ||||
-rw-r--r-- | fs/gfs2/bmap.c | 38 | ||||
-rw-r--r-- | fs/gfs2/dir.c | 13 | ||||
-rw-r--r-- | fs/gfs2/file.c | 34 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 3 | ||||
-rw-r--r-- | fs/gfs2/inode.c | 10 | ||||
-rw-r--r-- | fs/gfs2/log.c | 2 | ||||
-rw-r--r-- | fs/gfs2/log.h | 1 | ||||
-rw-r--r-- | fs/gfs2/quota.h | 2 | ||||
-rw-r--r-- | fs/gfs2/recovery.c | 20 | ||||
-rw-r--r-- | fs/gfs2/trace_gfs2.h | 9 |
11 files changed, 68 insertions, 72 deletions
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 2f725b4a386b..f58716567972 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -940,13 +940,13 @@ failed: } /** - * gfs2_set_page_dirty - Page dirtying function + * jdata_set_page_dirty - Page dirtying function * @page: The page to dirty * * Returns: 1 if it dirtyed the page, or 0 otherwise */ -static int gfs2_set_page_dirty(struct page *page) +static int jdata_set_page_dirty(struct page *page) { SetPageChecked(page); return __set_page_dirty_buffers(page); @@ -1214,7 +1214,7 @@ static const struct address_space_operations gfs2_ordered_aops = { .readpages = gfs2_readpages, .write_begin = gfs2_write_begin, .write_end = gfs2_write_end, - .set_page_dirty = gfs2_set_page_dirty, + .set_page_dirty = __set_page_dirty_buffers, .bmap = gfs2_bmap, .invalidatepage = gfs2_invalidatepage, .releasepage = gfs2_releasepage, @@ -1231,7 +1231,7 @@ static const struct address_space_operations gfs2_jdata_aops = { .readpages = gfs2_readpages, .write_begin = gfs2_write_begin, .write_end = gfs2_write_end, - .set_page_dirty = gfs2_set_page_dirty, + .set_page_dirty = jdata_set_page_dirty, .bmap = gfs2_bmap, .invalidatepage = gfs2_invalidatepage, .releasepage = gfs2_releasepage, diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 51f940e76c5e..685c305cbeb6 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -491,14 +491,12 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, { struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); - struct super_block *sb = sdp->sd_vfs; struct buffer_head *dibh = mp->mp_bh[0]; u64 bn; unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0; unsigned dblks = 0; unsigned ptrs_per_blk; const unsigned end_of_metadata = mp->mp_fheight - 1; - int ret; enum alloc_state state; __be64 *ptr; __be64 zero_bn = 0; @@ -607,15 +605,6 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, iomap->flags |= IOMAP_F_NEW; while (n-- > 0) *ptr++ = cpu_to_be64(bn++); - if (flags & IOMAP_ZERO) { - ret = sb_issue_zeroout(sb, iomap->addr >> inode->i_blkbits, - dblks, GFP_NOFS); - if (ret) { - fs_err(sdp, - "Failed to zero data buffers\n"); - flags &= ~IOMAP_ZERO; - } - } break; } } while (iomap->addr == IOMAP_NULL_ADDR); @@ -812,15 +801,22 @@ do_alloc: } /** - * gfs2_block_map - Map a block from an inode to a disk block + * gfs2_block_map - Map one or more blocks of an inode to a disk block * @inode: The inode * @lblock: The logical block number * @bh_map: The bh to be mapped * @create: True if its ok to alloc blocks to satify the request * - * Sets buffer_mapped() if successful, sets buffer_boundary() if a - * read of metadata will be required before the next block can be - * mapped. Sets buffer_new() if new blocks were allocated. + * The size of the requested mapping is defined in bh_map->b_size. + * + * Clears buffer_mapped(bh_map) and leaves bh_map->b_size unchanged + * when @lblock is not mapped. Sets buffer_mapped(bh_map) and + * bh_map->b_size to indicate the size of the mapping when @lblock and + * successive blocks are mapped, up to the requested size. + * + * Sets buffer_boundary() if a read of metadata will be required + * before the next block can be mapped. Sets buffer_new() if new + * blocks were allocated. * * Returns: errno */ @@ -839,8 +835,6 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, if (create) flags |= IOMAP_WRITE; - if (buffer_zeronew(bh_map)) - flags |= IOMAP_ZERO; ret = gfs2_iomap_begin(inode, (loff_t)lblock << inode->i_blkbits, bh_map->b_size, flags, &iomap); if (ret) { @@ -1344,6 +1338,7 @@ static inline bool walk_done(struct gfs2_sbd *sdp, static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + u64 maxsize = sdp->sd_heightsize[ip->i_height]; struct metapath mp = {}; struct buffer_head *dibh, *bh; struct gfs2_holder rd_gh; @@ -1359,6 +1354,14 @@ static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length) u64 prev_bnr = 0; __be64 *start, *end; + if (offset >= maxsize) { + /* + * The starting point lies beyond the allocated meta-data; + * there are no blocks do deallocate. + */ + return 0; + } + /* * The start position of the hole is defined by lblock, start_list, and * start_aligned. The end position of the hole is defined by lend, @@ -1372,7 +1375,6 @@ static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length) */ if (length) { - u64 maxsize = sdp->sd_heightsize[ip->i_height]; u64 end_offset = offset + length; u64 lend; diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 7c21aea0266b..d9fb0ad6cc30 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1940,7 +1940,6 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, { struct buffer_head *bh; struct gfs2_dirent *dent; - int error; dent = gfs2_dirent_search(&dip->i_inode, filename, gfs2_dirent_find, &bh); if (!dent) { @@ -1953,18 +1952,10 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, gfs2_trans_add_meta(dip->i_gl, bh); gfs2_inum_out(nip, dent); dent->de_type = cpu_to_be16(new_type); - - if (dip->i_diskflags & GFS2_DIF_EXHASH) { - brelse(bh); - error = gfs2_meta_inode_buffer(dip, &bh); - if (error) - return error; - gfs2_trans_add_meta(dip->i_gl, bh); - } + brelse(bh); dip->i_inode.i_mtime = dip->i_inode.i_ctime = current_time(&dip->i_inode); - gfs2_dinode_out(dip, bh->b_data); - brelse(bh); + mark_inode_dirty_sync(&dip->i_inode); return 0; } diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 4f88e201b3f0..4b71f021a9e2 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -729,11 +729,12 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, int mode) { + struct super_block *sb = inode->i_sb; struct gfs2_inode *ip = GFS2_I(inode); + loff_t end = offset + len; struct buffer_head *dibh; + struct iomap iomap; int error; - unsigned int nr_blks; - sector_t lblock = offset >> inode->i_blkbits; error = gfs2_meta_inode_buffer(ip, &dibh); if (unlikely(error)) @@ -747,21 +748,19 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, goto out; } - while (len) { - struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 }; - bh_map.b_size = len; - set_buffer_zeronew(&bh_map); - - error = gfs2_block_map(inode, lblock, &bh_map, 1); - if (unlikely(error)) + while (offset < end) { + error = gfs2_iomap_begin(inode, offset, end - offset, + IOMAP_WRITE, &iomap); + if (error) goto out; - len -= bh_map.b_size; - nr_blks = bh_map.b_size >> inode->i_blkbits; - lblock += nr_blks; - if (!buffer_new(&bh_map)) + offset = iomap.offset + iomap.length; + if (iomap.type != IOMAP_HOLE) continue; - if (unlikely(!buffer_zeronew(&bh_map))) { - error = -EIO; + error = sb_issue_zeroout(sb, iomap.addr >> inode->i_blkbits, + iomap.length >> inode->i_blkbits, + GFP_NOFS); + if (error) { + fs_err(GFS2_SB(inode), "Failed to zero data buffers\n"); goto out; } } @@ -809,7 +808,7 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_alloc_parms ap = { .aflags = 0, }; unsigned int data_blocks = 0, ind_blocks = 0, rblocks; - loff_t bytes, max_bytes, max_blks = UINT_MAX; + loff_t bytes, max_bytes, max_blks; int error; const loff_t pos = offset; const loff_t count = len; @@ -861,7 +860,8 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t return error; /* ap.allowed tells us how many blocks quota will allow * us to write. Check if this reduces max_blks */ - if (ap.allowed && ap.allowed < max_blks) + max_blks = UINT_MAX; + if (ap.allowed) max_blks = ap.allowed; error = gfs2_inplace_reserve(ip, &ap); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index e0557b8a590a..1b6b1e3f5caf 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -130,15 +130,12 @@ static inline bool gfs2_rbm_eq(const struct gfs2_rbm *rbm1, enum gfs2_state_bits { BH_Pinned = BH_PrivateStart, BH_Escaped = BH_PrivateStart + 1, - BH_Zeronew = BH_PrivateStart + 2, }; BUFFER_FNS(Pinned, pinned) TAS_BUFFER_FNS(Pinned, pinned) BUFFER_FNS(Escaped, escaped) TAS_BUFFER_FNS(Escaped, escaped) -BUFFER_FNS(Zeronew, zeronew) -TAS_BUFFER_FNS(Zeronew, zeronew) struct gfs2_bufdata { struct buffer_head *bd_bh; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 59e0560180ec..8700eb815638 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1326,19 +1326,11 @@ static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) static int update_moved_ino(struct gfs2_inode *ip, struct gfs2_inode *ndip, int dir_rename) { - int error; - struct buffer_head *dibh; - if (dir_rename) return gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR); - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - return error; ip->i_inode.i_ctime = current_time(&ip->i_inode); - gfs2_trans_add_meta(ip->i_gl, dibh); - gfs2_dinode_out(ip, dibh->b_data); - brelse(dibh); + mark_inode_dirty_sync(&ip->i_inode); return 0; } diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index cf6b46247df4..0248835625f1 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -73,7 +73,7 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, * */ -void gfs2_remove_from_ail(struct gfs2_bufdata *bd) +static void gfs2_remove_from_ail(struct gfs2_bufdata *bd) { bd->bd_tr = NULL; list_del_init(&bd->bd_ail_st_list); diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index 93b52ac1ca1f..1862e310a067 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -70,7 +70,6 @@ extern void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, 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); -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_log_shutdown(struct gfs2_sbd *sdp); diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index 5e47c935a515..836f29480be6 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -45,6 +45,8 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip, { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); int ret; + + ap->allowed = UINT_MAX; /* Assume we are permitted a whole lot */ if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) return 0; ret = gfs2_quota_lock(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE); diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index b6b258998bcd..d8b622c375ab 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -15,6 +15,7 @@ #include <linux/gfs2_ondisk.h> #include <linux/crc32.h> #include <linux/crc32c.h> +#include <linux/ktime.h> #include "gfs2.h" #include "incore.h" @@ -409,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", @@ -446,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); @@ -455,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, @@ -495,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++) { @@ -509,9 +512,14 @@ void gfs2_recover_func(struct work_struct *work) 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); diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h index b9318b49ff8f..cb10b95efe0f 100644 --- a/fs/gfs2/trace_gfs2.h +++ b/fs/gfs2/trace_gfs2.h @@ -515,6 +515,7 @@ TRACE_EVENT(gfs2_iomap_end, __field( u64, inum ) __field( loff_t, offset ) __field( ssize_t, length ) + __field( sector_t, pblock ) __field( u16, flags ) __field( u16, type ) __field( int, ret ) @@ -525,16 +526,20 @@ TRACE_EVENT(gfs2_iomap_end, __entry->inum = ip->i_no_addr; __entry->offset = iomap->offset; __entry->length = iomap->length; + __entry->pblock = iomap->addr == IOMAP_NULL_ADDR ? 0 : + (iomap->addr >> ip->i_inode.i_blkbits); __entry->flags = iomap->flags; __entry->type = iomap->type; __entry->ret = ret; ), - TP_printk("%u,%u bmap %llu iomap end %llu/%lu ty:%d flags:%08x rc:%d", + TP_printk("%u,%u bmap %llu iomap end %llu/%lu to %llu ty:%d flags:%08x rc:%d", MAJOR(__entry->dev), MINOR(__entry->dev), (unsigned long long)__entry->inum, (unsigned long long)__entry->offset, - (unsigned long)__entry->length, (u16)__entry->type, + (unsigned long)__entry->length, + (long long)__entry->pblock, + (u16)__entry->type, (u16)__entry->flags, __entry->ret) ); |