From 65adc27375a85beb57c3869cedb2a410fad9c288 Mon Sep 17 00:00:00 2001 From: Andrew Price Date: Tue, 12 Dec 2017 11:37:15 -0600 Subject: gfs2: Add a next-resource-group pointer to resource groups Add a new rg_skip field to struct gfs2_rgrp, replacing __pad. The rg_skip field has the following meaning: - If rg_skip is zero, it is considered unset and not useful. - If rg_skip is non-zero, its value will be the number of blocks between this rgrp's address and the next rgrp's address. This can be used as a hint by fsck.gfs2 when rebuilding a bad rindex, for example. This will provide less dependency on the rindex in future, and allow tools such as fsck.gfs2 to iterate the resource groups without keeping the rindex around. The field is updated in gfs2_rgrp_out() so that existing file systems will have it set. This means that any resource groups that aren't ever written will not be updated. The final rgrp is a special case as there is no next rgrp, so it will always have a rg_skip of 0 (unless the fs is extended). Before this patch, gfs2_rgrp_out() zeroes the __pad field explicitly, so the rg_skip field can get set back to 0 in cases where nodes with and without this patch are mixed in a cluster. In some cases, the field may bounce between being set by one node and then zeroed by another which may harm performance slightly, e.g. when two nodes create many small files. In testing this situation is rare but it becomes more likely as the filesystem fills up and there are fewer resource groups to choose from. The problem goes away when all nodes are running with this patch. Dipping into the space currently occupied by the rg_reserved field would have resulted in the same problem as it is also explicitly zeroed, so unfortunately there is no other way around it. Signed-off-by: Andrew Price Signed-off-by: Bob Peterson --- include/uapi/linux/gfs2_ondisk.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'include/uapi/linux') diff --git a/include/uapi/linux/gfs2_ondisk.h b/include/uapi/linux/gfs2_ondisk.h index 5156bad77b47..da7a30ddef72 100644 --- a/include/uapi/linux/gfs2_ondisk.h +++ b/include/uapi/linux/gfs2_ondisk.h @@ -187,7 +187,10 @@ struct gfs2_rgrp { __be32 rg_flags; __be32 rg_free; __be32 rg_dinodes; - __be32 __pad; + union { + __be32 __pad; + __be32 rg_skip; /* Distance to the next rgrp in fs blocks */ + }; __be64 rg_igeneration; __u8 rg_reserved[80]; /* Several fields from gfs1 now reserved */ -- cgit v1.2.3 From 166725d96322473305e35f9d580591a01697ab29 Mon Sep 17 00:00:00 2001 From: Andrew Price Date: Tue, 12 Dec 2017 11:40:05 -0600 Subject: gfs2: Add rindex fields to rgrp headers Add rg_data0, rg_data and rg_bitbytes to struct gfs2_rgrp. The fields are identical to their counterparts in struct gfs2_rindex and are intended to reduce the use of the rindex. For now the fields are only written back as the in-memory equivalents in struct gfs2_rgrpd are set using values from the rindex. However, they are needed at this point so that userspace can make use of them, allowing a migration away from the rindex over time. The new fields take up previously reserved space which was explicitly zeroed on write so, in clusters with mixed kernels, these fields could get zeroed after being set and this should not be treated as an error. Signed-off-by: Andrew Price Signed-off-by: Bob Peterson --- fs/gfs2/rgrp.c | 5 +++++ include/uapi/linux/gfs2_ondisk.h | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'include/uapi/linux') diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index be2fc26029e4..a9184903a9f5 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1040,6 +1040,7 @@ static void gfs2_rgrp_in(struct gfs2_rgrpd *rgd, const void *buf) rgd->rd_free = be32_to_cpu(str->rg_free); rgd->rd_dinodes = be32_to_cpu(str->rg_dinodes); rgd->rd_igeneration = be64_to_cpu(str->rg_igeneration); + /* rd_data0, rd_data and rd_bitbytes already set from rindex */ } static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf) @@ -1055,6 +1056,10 @@ static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf) else if (next->rd_addr > rgd->rd_addr) str->rg_skip = cpu_to_be32(next->rd_addr - rgd->rd_addr); str->rg_igeneration = cpu_to_be64(rgd->rd_igeneration); + str->rg_data0 = cpu_to_be64(rgd->rd_data0); + str->rg_data = cpu_to_be32(rgd->rd_data); + str->rg_bitbytes = cpu_to_be32(rgd->rd_bitbytes); + memset(&str->rg_reserved, 0, sizeof(str->rg_reserved)); } diff --git a/include/uapi/linux/gfs2_ondisk.h b/include/uapi/linux/gfs2_ondisk.h index da7a30ddef72..648e0cbca574 100644 --- a/include/uapi/linux/gfs2_ondisk.h +++ b/include/uapi/linux/gfs2_ondisk.h @@ -192,8 +192,13 @@ struct gfs2_rgrp { __be32 rg_skip; /* Distance to the next rgrp in fs blocks */ }; __be64 rg_igeneration; + /* The following 3 fields are duplicated from gfs2_rindex to reduce + reliance on the rindex */ + __be64 rg_data0; /* First data location */ + __be32 rg_data; /* Number of data blocks in rgrp */ + __be32 rg_bitbytes; /* Number of bytes in data bitmaps */ - __u8 rg_reserved[80]; /* Several fields from gfs1 now reserved */ + __u8 rg_reserved[64]; /* Several fields from gfs1 now reserved */ }; /* -- cgit v1.2.3 From 850d2d915fa69011bef9bd668499cce889fdd8b3 Mon Sep 17 00:00:00 2001 From: Andrew Price Date: Tue, 12 Dec 2017 11:42:30 -0600 Subject: gfs2: Add a crc field to resource group headers Add the rg_crc field to store a crc32 of the gfs2_rgrp structure. This allows us to check resource group headers' integrity and removes the requirement to check them against the rindex entries in fsck. If this field is found to be zero, it should be ignored (or updated with an accurate value). Signed-off-by: Andrew Price Signed-off-by: Bob Peterson --- fs/gfs2/rgrp.c | 5 +++++ include/uapi/linux/gfs2_ondisk.h | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'include/uapi/linux') diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index a9184903a9f5..e8aba6fa1472 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -34,6 +34,7 @@ #include "log.h" #include "inode.h" #include "trace_gfs2.h" +#include "dir.h" #define BFITNOENT ((u32)~0) #define NO_BLOCK ((u64)~0) @@ -1047,6 +1048,7 @@ static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf) { struct gfs2_rgrpd *next = gfs2_rgrpd_get_next(rgd); struct gfs2_rgrp *str = buf; + u32 crc; str->rg_flags = cpu_to_be32(rgd->rd_flags & ~GFS2_RDF_MASK); str->rg_free = cpu_to_be32(rgd->rd_free); @@ -1059,6 +1061,9 @@ static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf) str->rg_data0 = cpu_to_be64(rgd->rd_data0); str->rg_data = cpu_to_be32(rgd->rd_data); str->rg_bitbytes = cpu_to_be32(rgd->rd_bitbytes); + str->rg_crc = 0; + crc = gfs2_disk_hash(buf, sizeof(struct gfs2_rgrp)); + str->rg_crc = cpu_to_be32(crc); memset(&str->rg_reserved, 0, sizeof(str->rg_reserved)); } diff --git a/include/uapi/linux/gfs2_ondisk.h b/include/uapi/linux/gfs2_ondisk.h index 648e0cbca574..09f0920f07e9 100644 --- a/include/uapi/linux/gfs2_ondisk.h +++ b/include/uapi/linux/gfs2_ondisk.h @@ -197,8 +197,9 @@ struct gfs2_rgrp { __be64 rg_data0; /* First data location */ __be32 rg_data; /* Number of data blocks in rgrp */ __be32 rg_bitbytes; /* Number of bytes in data bitmaps */ + __be32 rg_crc; /* crc32 of the structure with this field 0 */ - __u8 rg_reserved[64]; /* Several fields from gfs1 now reserved */ + __u8 rg_reserved[60]; /* Several fields from gfs1 now reserved */ }; /* -- cgit v1.2.3 From c1696fb85d33194cf65c7ebfc82a75696299c3a3 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Wed, 17 Jan 2018 00:01:33 +0100 Subject: 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: Bob Peterson Signed-off-by: Andreas Gruenbacher --- fs/gfs2/Kconfig | 2 ++ fs/gfs2/aops.c | 2 +- fs/gfs2/file.c | 3 +- fs/gfs2/glops.c | 13 +++---- fs/gfs2/log.c | 75 ++++++++++++++++++++++++++++++---------- fs/gfs2/log.h | 12 ++----- fs/gfs2/lops.c | 16 +++++---- fs/gfs2/lops.h | 3 ++ fs/gfs2/ops_fstype.c | 2 +- fs/gfs2/quota.c | 3 +- fs/gfs2/recovery.c | 17 +++++---- fs/gfs2/rgrp.c | 2 +- fs/gfs2/super.c | 9 ++--- fs/gfs2/trans.c | 2 +- include/uapi/linux/gfs2_ondisk.h | 26 ++++++++++++-- 15 files changed, 128 insertions(+), 59 deletions(-) (limited to 'include/uapi/linux') diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index 43c827a7cce5..c0225d4b5435 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig @@ -3,6 +3,8 @@ config GFS2_FS depends on (64BIT || LBDAF) select FS_POSIX_ACL select CRC32 + select CRYPTO + select CRYPTO_CRC32C select QUOTACTL select FS_IOMAP help diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index ac4a1e89da1e..462c3fd55929 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -448,7 +448,7 @@ static int gfs2_jdata_writepages(struct address_space *mapping, ret = gfs2_write_cache_jdata(mapping, wbc); 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); } return ret; diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index bd60dc682676..7a02b4e6e9f3 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -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 (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); if (error) goto out; diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index cdd1c5f06f45..2daab13a9e0b 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -107,7 +107,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) __gfs2_ail_flush(gl, 0, tr.tr_revokes); 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) @@ -128,7 +128,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) return; __gfs2_ail_flush(gl, fsync, max_revokes); 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) return; 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); error = filemap_fdatawait_range(mapping, gl->gl_vm.start, gl->gl_vm.end); mapping_set_error(mapping, error); @@ -252,7 +252,7 @@ static void inode_go_sync(struct gfs2_glock *gl) 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); if (isreg) { struct address_space *mapping = ip->i_inode.i_mapping; @@ -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)) { - 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; } if (ip && S_ISREG(ip->i_inode.i_mode)) @@ -495,7 +496,7 @@ static void freeze_go_sync(struct gfs2_glock *gl) gfs2_assert_withdraw(sdp, 0); } 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); } } diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index c27cbcebfe88..a2eb13c04591 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -653,20 +654,25 @@ out_of_blocks: /** * 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 + * @flags: log header flags GFS2_LOG_HEAD_* * @op_flags: flags to pass to the bio * * Returns: the initialized log buffer descriptor */ -void gfs2_write_log_header(struct gfs2_sbd *sdp, u64 seq, u32 tail, - u32 flags, int op_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; - u32 hash; + u32 hash, crc; 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); clear_page(lh); @@ -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_tail = cpu_to_be32(tail); 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); - 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); log_flush_wait(sdp); } @@ -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 * @sdp: The GFS2 superblock + * @flags: The log header flags, including log header origin * * Returns: the initialized log buffer descriptor */ @@ -710,8 +746,8 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags) op_flags = REQ_SYNC | REQ_META | REQ_PRIO; } sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); - gfs2_write_log_header(sdp, sdp->sd_log_sequence++, tail, flags, - op_flags); + 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); @@ -721,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_* * */ -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); @@ -739,7 +775,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, } 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); 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, 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); @@ -785,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); @@ -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 */ 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); } @@ -956,7 +993,7 @@ 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); did_flush = true; } @@ -964,7 +1001,7 @@ 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); did_flush = true; } diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index 619de9a1ff4f..93b52ac1ca1f 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -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 int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks); -enum gfs2_flush_type { - NORMAL_FLUSH = 0, - 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_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, + u64 seq, u32 tail, u32 flags, int op_flags); 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_remove_from_ail(struct gfs2_bufdata *bd); extern void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index c8ff7b7954f0..4a60221c678f 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -18,6 +18,7 @@ #include #include +#include "dir.h" #include "gfs2.h" #include "incore.h" #include "inode.h" @@ -138,7 +139,7 @@ static void gfs2_log_incr_head(struct gfs2_sbd *sdp) 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; struct gfs2_journal_extent *je; @@ -306,23 +307,22 @@ static struct bio *gfs2_log_get_bio(struct gfs2_sbd *sdp, u64 blkno) return gfs2_log_alloc_bio(sdp, blkno); } - /** * gfs2_log_write - write to log * @sdp: the filesystem * @page: the page to write * @size: the size of the data to write * @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, * submit the current bio to the device and create a new one, and * then add the page segment to that. */ -static void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page, - unsigned size, unsigned offset) +void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page, + unsigned size, unsigned offset, u64 blkno) { - u64 blkno = gfs2_log_bmap(sdp); struct bio *bio; int ret; @@ -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) { - 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) void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page) { 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, diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h index e529f536c117..e4949394f054 100644 --- a/fs/gfs2/lops.h +++ b/fs/gfs2/lops.h @@ -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_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_flush_bio(struct gfs2_sbd *sdp, int op, int op_flags); extern void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index ad55eb86a250..d6e620beb9db 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -1382,7 +1382,7 @@ static void gfs2_kill_sb(struct super_block *sb) 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_master_dir); sdp->sd_root_dir = NULL; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index e700fb162664..2092df19e433 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -955,7 +955,8 @@ out: gfs2_glock_dq_uninit(&ghs[qx]); inode_unlock(&ip->i_inode); 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; } diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 975f32166dfe..b6b258998bcd 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "gfs2.h" #include "incore.h" @@ -137,7 +138,7 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, { struct gfs2_log_header *lh; struct buffer_head *bh; - u32 hash; + u32 hash, crc; int error; error = gfs2_replay_read_block(jd, blk, &bh); @@ -145,13 +146,17 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, return error; 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 */ + 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) || lh->lh_header.mh_type != cpu_to_be32(GFS2_METATYPE_LH) || 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); @@ -372,9 +377,9 @@ static void clean_journal(struct gfs2_jdesc *jd, sdp->sd_log_flush_head = head->lh_blkno; gfs2_replay_incr_blk(jd, &sdp->sd_log_flush_head); - gfs2_write_log_header(sdp, head->lh_sequence + 1, 0, - GFS2_LOG_HEAD_UNMOUNT, REQ_PREFLUSH | - REQ_FUA | REQ_META | REQ_SYNC); + gfs2_write_log_header(sdp, jd, head->lh_sequence + 1, 0, + GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_RECOVERY, + REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC); } diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 6dea72f49316..00eab6c0525c 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -2093,7 +2093,7 @@ next_rgrp: } /* Flushing the log may release space */ if (loops == 2) - gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL); } return -ENOSPC; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index d81d46e19726..fa3a19eaf0eb 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -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)); 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) gfs2_ail1_flush(sdp, wbc); else @@ -853,7 +854,7 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) gfs2_quota_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); 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) gfs2_quota_sync(sb, -1); if (wait) - gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL); return sdp->sd_log_error; } @@ -1650,7 +1651,7 @@ alloc_failed: goto out_unlock; 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); if (test_bit(GLF_DIRTY, &ip->i_gl->gl_flags)) { filemap_fdatawrite(metamapping); diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index b95ebd166cac..7aec6d3434fa 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -117,7 +117,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) up_read(&sdp->sd_log_flush_lock); 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) sb_end_intwrite(sdp->sd_vfs); } diff --git a/include/uapi/linux/gfs2_ondisk.h b/include/uapi/linux/gfs2_ondisk.h index 09f0920f07e9..9a81d520f54a 100644 --- a/include/uapi/linux/gfs2_ondisk.h +++ b/include/uapi/linux/gfs2_ondisk.h @@ -403,7 +403,15 @@ struct gfs2_ea_header { * 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_meta_header lh_header; @@ -412,7 +420,21 @@ struct gfs2_log_header { __be32 lh_flags; /* GFS2_LOG_HEAD_... */ __be32 lh_tail; /* Block number of log tail */ __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; }; /* -- cgit v1.2.3 From 805c090750a315c5443c14e06304e19a01c697a0 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 8 Jan 2018 10:34:17 -0500 Subject: GFS2: Log the reason for log flushes in every log header This patch just adds the capability for GFS2 to track which function called gfs2_log_flush. This should make it easier to diagnose problems based on the sequence of events found in the journals. Signed-off-by: Bob Peterson Reviewed-by: Andreas Gruenbacher --- fs/gfs2/aops.c | 3 ++- fs/gfs2/file.c | 3 ++- fs/gfs2/glops.c | 18 ++++++++++++------ fs/gfs2/log.c | 14 ++++++++------ fs/gfs2/ops_fstype.c | 2 +- fs/gfs2/quota.c | 2 +- fs/gfs2/rgrp.c | 3 ++- fs/gfs2/super.c | 12 ++++++++---- fs/gfs2/trace_gfs2.h | 11 +++++++---- fs/gfs2/trans.c | 3 ++- include/uapi/linux/gfs2_ondisk.h | 21 +++++++++++++++++++++ 11 files changed, 66 insertions(+), 26 deletions(-) (limited to 'include/uapi/linux') diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 462c3fd55929..2f725b4a386b 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -448,7 +448,8 @@ static int gfs2_jdata_writepages(struct address_space *mapping, ret = gfs2_write_cache_jdata(mapping, wbc); if (ret == 0 && wbc->sync_mode == WB_SYNC_ALL) { - gfs2_log_flush(sdp, ip->i_gl, GFS2_LOG_HEAD_FLUSH_NORMAL); + gfs2_log_flush(sdp, ip->i_gl, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_JDATA_WPAGES); ret = gfs2_write_cache_jdata(mapping, wbc); } return ret; diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 7a02b4e6e9f3..4f88e201b3f0 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -247,7 +247,8 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) if ((flags ^ new_flags) & GFS2_DIF_JDATA) { if (new_flags & GFS2_DIF_JDATA) gfs2_log_flush(sdp, ip->i_gl, - GFS2_LOG_HEAD_FLUSH_NORMAL); + GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_SET_FLAGS); error = filemap_fdatawrite(inode->i_mapping); if (error) goto out; diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 2daab13a9e0b..d8782a7a1e7d 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -107,7 +107,8 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) __gfs2_ail_flush(gl, 0, tr.tr_revokes); gfs2_trans_end(sdp); - gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_AIL_EMPTY_GL); } void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) @@ -128,7 +129,8 @@ void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) return; __gfs2_ail_flush(gl, fsync, max_revokes); gfs2_trans_end(sdp); - gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_AIL_FLUSH); } /** @@ -157,7 +159,8 @@ static void rgrp_go_sync(struct gfs2_glock *gl) return; GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE); - gfs2_log_flush(sdp, gl, GFS2_LOG_HEAD_FLUSH_NORMAL); + gfs2_log_flush(sdp, gl, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_RGRP_GO_SYNC); 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); mapping_set_error(mapping, error); @@ -252,7 +255,8 @@ static void inode_go_sync(struct gfs2_glock *gl) GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE); - gfs2_log_flush(gl->gl_name.ln_sbd, gl, GFS2_LOG_HEAD_FLUSH_NORMAL); + gfs2_log_flush(gl->gl_name.ln_sbd, gl, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_INODE_GO_SYNC); filemap_fdatawrite(metamapping); if (isreg) { struct address_space *mapping = ip->i_inode.i_mapping; @@ -304,7 +308,8 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) if (ip == GFS2_I(gl->gl_name.ln_sbd->sd_rindex)) { gfs2_log_flush(gl->gl_name.ln_sbd, NULL, - GFS2_LOG_HEAD_FLUSH_NORMAL); + GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_INODE_GO_INVAL); gl->gl_name.ln_sbd->sd_rindex_uptodate = 0; } if (ip && S_ISREG(ip->i_inode.i_mode)) @@ -496,7 +501,8 @@ static void freeze_go_sync(struct gfs2_glock *gl) gfs2_assert_withdraw(sdp, 0); } queue_work(gfs2_freeze_wq, &sdp->sd_freeze_work); - gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_FREEZE); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_FREEZE | + GFS2_LFC_FREEZE_GO_SYNC); } } diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index a2eb13c04591..cf6b46247df4 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -757,7 +757,7 @@ 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_* + * @flags: The log header flags: GFS2_LOG_HEAD_FLUSH_* and debug flags * */ @@ -773,7 +773,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) up_write(&sdp->sd_log_flush_lock); return; } - trace_gfs2_log_flush(sdp, 1); + trace_gfs2_log_flush(sdp, 1, flags); if (flags & GFS2_LOG_HEAD_FLUSH_SHUTDOWN) clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); @@ -841,7 +841,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) 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); @@ -937,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)); @@ -993,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, GFS2_LOG_HEAD_FLUSH_NORMAL); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_LOGD_JFLUSH_REQD); did_flush = true; } @@ -1001,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, GFS2_LOG_HEAD_FLUSH_NORMAL); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_LOGD_AIL_FLUSH_REQD); did_flush = true; } diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index d6e620beb9db..e6a0a8a89ea7 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -1382,7 +1382,7 @@ static void gfs2_kill_sb(struct super_block *sb) return; } - gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_SYNC); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_SYNC | GFS2_LFC_KILL_SB); dput(sdp->sd_root_dir); dput(sdp->sd_master_dir); sdp->sd_root_dir = NULL; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 2092df19e433..7a98abd340ee 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -956,7 +956,7 @@ out: inode_unlock(&ip->i_inode); kfree(ghs); gfs2_log_flush(ip->i_gl->gl_name.ln_sbd, ip->i_gl, - GFS2_LOG_HEAD_FLUSH_NORMAL); + GFS2_LOG_HEAD_FLUSH_NORMAL | GFS2_LFC_DO_SYNC); return error; } diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 00eab6c0525c..078b002e0a68 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -2093,7 +2093,8 @@ next_rgrp: } /* Flushing the log may release space */ if (loops == 2) - gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_INPLACE_RESERVE); } return -ENOSPC; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index fa3a19eaf0eb..50a297b920fc 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -758,7 +758,8 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) if (flush_all) gfs2_log_flush(GFS2_SB(inode), ip->i_gl, - GFS2_LOG_HEAD_FLUSH_NORMAL); + GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_WRITE_INODE); if (bdi->wb.dirty_exceeded) gfs2_ail1_flush(sdp, wbc); else @@ -854,7 +855,8 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) gfs2_quota_sync(sdp->sd_vfs, 0); gfs2_statfs_sync(sdp->sd_vfs, 0); - gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_SHUTDOWN); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_SHUTDOWN | + GFS2_LFC_MAKE_FS_RO); 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); @@ -947,7 +949,8 @@ static int gfs2_sync_fs(struct super_block *sb, int wait) gfs2_quota_sync(sb, -1); if (wait) - gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_SYNC_FS); return sdp->sd_log_error; } @@ -1651,7 +1654,8 @@ alloc_failed: goto out_unlock; out_truncate: - gfs2_log_flush(sdp, ip->i_gl, GFS2_LOG_HEAD_FLUSH_NORMAL); + gfs2_log_flush(sdp, ip->i_gl, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_EVICT_INODE); metamapping = gfs2_glock2aspace(ip->i_gl); if (test_bit(GLF_DIRTY, &ip->i_gl->gl_flags)) { filemap_fdatawrite(metamapping); diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h index f67a709589d3..b9318b49ff8f 100644 --- a/fs/gfs2/trace_gfs2.h +++ b/fs/gfs2/trace_gfs2.h @@ -353,26 +353,29 @@ TRACE_EVENT(gfs2_pin, /* Flushing the log */ TRACE_EVENT(gfs2_log_flush, - TP_PROTO(const struct gfs2_sbd *sdp, int start), + TP_PROTO(const struct gfs2_sbd *sdp, int start, u32 flags), - TP_ARGS(sdp, start), + TP_ARGS(sdp, start, flags), TP_STRUCT__entry( __field( dev_t, dev ) __field( int, start ) __field( u64, log_seq ) + __field( u32, flags ) ), TP_fast_assign( __entry->dev = sdp->sd_vfs->s_dev; __entry->start = start; __entry->log_seq = sdp->sd_log_sequence; + __entry->flags = flags; ), - TP_printk("%u,%u log flush %s %llu", + TP_printk("%u,%u log flush %s %llu %llx", MAJOR(__entry->dev), MINOR(__entry->dev), __entry->start ? "start" : "end", - (unsigned long long)__entry->log_seq) + (unsigned long long)__entry->log_seq, + (unsigned long long)__entry->flags) ); /* Reserving/releasing blocks in the log */ diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 7aec6d3434fa..c75cacaa349b 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -117,7 +117,8 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) up_read(&sdp->sd_log_flush_lock); if (sdp->sd_vfs->s_flags & SB_SYNCHRONOUS) - gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL); + gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_TRANS_END); if (alloced) sb_end_intwrite(sdp->sd_vfs); } diff --git a/include/uapi/linux/gfs2_ondisk.h b/include/uapi/linux/gfs2_ondisk.h index 9a81d520f54a..2dc10a034de1 100644 --- a/include/uapi/linux/gfs2_ondisk.h +++ b/include/uapi/linux/gfs2_ondisk.h @@ -411,6 +411,27 @@ struct gfs2_ea_header { #define GFS2_LOG_HEAD_RECOVERY 0x00000020 /* Journal recovery */ #define GFS2_LOG_HEAD_USERSPACE 0x80000000 /* Written by gfs2-utils */ +/* Log flush callers */ +#define GFS2_LFC_SHUTDOWN 0x00000100 +#define GFS2_LFC_JDATA_WPAGES 0x00000200 +#define GFS2_LFC_SET_FLAGS 0x00000400 +#define GFS2_LFC_AIL_EMPTY_GL 0x00000800 +#define GFS2_LFC_AIL_FLUSH 0x00001000 +#define GFS2_LFC_RGRP_GO_SYNC 0x00002000 +#define GFS2_LFC_INODE_GO_SYNC 0x00004000 +#define GFS2_LFC_INODE_GO_INVAL 0x00008000 +#define GFS2_LFC_FREEZE_GO_SYNC 0x00010000 +#define GFS2_LFC_KILL_SB 0x00020000 +#define GFS2_LFC_DO_SYNC 0x00040000 +#define GFS2_LFC_INPLACE_RESERVE 0x00080000 +#define GFS2_LFC_WRITE_INODE 0x00100000 +#define GFS2_LFC_MAKE_FS_RO 0x00200000 +#define GFS2_LFC_SYNC_FS 0x00400000 +#define GFS2_LFC_EVICT_INODE 0x00800000 +#define GFS2_LFC_TRANS_END 0x01000000 +#define GFS2_LFC_LOGD_JFLUSH_REQD 0x02000000 +#define GFS2_LFC_LOGD_AIL_FLUSH_REQD 0x04000000 + #define LH_V1_SIZE (offsetofend(struct gfs2_log_header, lh_hash)) struct gfs2_log_header { -- cgit v1.2.3