This new field in the resource group headers is set on write and checked on read so that fsck.gfs2 now considers a resource group with a bad, non-zero crc to be corrupted. gfs2_grow, gfs2_edit, and mkfs.gfs2 all now support the rg_crc field, including save/restoremeta.
Signed-off-by: Andrew Price <[email protected]> --- gfs2/libgfs2/libgfs2.h | 2 ++ gfs2/libgfs2/meta.c | 1 + gfs2/libgfs2/ondisk.c | 7 +++++-- gfs2/libgfs2/rgrp.c | 54 +++++++++++++++++++++++++++++++++++++++++++----- tests/rgrifieldscheck.sh | 3 +++ 5 files changed, 60 insertions(+), 7 deletions(-) diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h index 50dc3f56..5309e6d6 100644 --- a/gfs2/libgfs2/libgfs2.h +++ b/gfs2/libgfs2/libgfs2.h @@ -667,6 +667,8 @@ extern int clean_journal(struct gfs2_inode *ip, struct gfs2_log_header *head); /* rgrp.c */ extern int gfs2_compute_bitstructs(const uint32_t bsize, struct rgrp_tree *rgd); extern struct rgrp_tree *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, uint64_t blk); +extern int lgfs2_rgrp_crc_check(const struct gfs2_rgrp *rg, char *buf); +extern void lgfs2_rgrp_crc_set(char *buf); extern uint64_t gfs2_rgrp_read(struct gfs2_sbd *sdp, struct rgrp_tree *rgd); extern void gfs2_rgrp_relse(struct rgrp_tree *rgd); extern struct rgrp_tree *rgrp_insert(struct osi_root *rgtree, diff --git a/gfs2/libgfs2/meta.c b/gfs2/libgfs2/meta.c index 1b771f30..82c8c6be 100644 --- a/gfs2/libgfs2/meta.c +++ b/gfs2/libgfs2/meta.c @@ -211,6 +211,7 @@ F(rg_igeneration) FP(rg_data0, .points_to = ANY_GFS2_BLOCK|(1 << LGFS2_MT_FREE)) F(rg_data, .flags = LGFS2_MFF_FSBLOCKS) F(rg_bitbytes, .flags = LGFS2_MFF_BYTES) +F(rg_crc, .flags = LGFS2_MFF_CHECK) #endif RF(rg_reserved) }; diff --git a/gfs2/libgfs2/ondisk.c b/gfs2/libgfs2/ondisk.c index fd25a860..dfb99d14 100644 --- a/gfs2/libgfs2/ondisk.c +++ b/gfs2/libgfs2/ondisk.c @@ -237,7 +237,8 @@ void gfs2_rgrp_in(struct gfs2_rgrp *rg, struct gfs2_buffer_head *bh) CPIN_64(rg, str, rg_data0); CPIN_32(rg, str, rg_data); CPIN_32(rg, str, rg_bitbytes); - CPIN_08(rg, str, rg_reserved, 64); + CPIN_32(rg, str, rg_crc); + CPIN_08(rg, str, rg_reserved, 60); #else CPIN_08(rg, str, rg_reserved, 80); #endif @@ -261,7 +262,8 @@ void gfs2_rgrp_out(const struct gfs2_rgrp *rg, char *buf) CPOUT_64(rg, str, rg_data0); CPOUT_32(rg, str, rg_data); CPOUT_32(rg, str, rg_bitbytes); - CPOUT_08(rg, str, rg_reserved, 64); + CPOUT_08(rg, str, rg_reserved, 60); + lgfs2_rgrp_crc_set(buf); #else CPOUT_08(rg, str, rg_reserved, 80); #endif @@ -289,6 +291,7 @@ void gfs2_rgrp_print(const struct gfs2_rgrp *rg) pv(rg, rg_data0, "%llu", "0x%llx"); pv(rg, rg_data, "%u", "0x%x"); pv(rg, rg_bitbytes, "%u", "0x%x"); + pv(rg, rg_crc, "%u", "0x%x"); #endif } diff --git a/gfs2/libgfs2/rgrp.c b/gfs2/libgfs2/rgrp.c index 17178bd9..03861d14 100644 --- a/gfs2/libgfs2/rgrp.c +++ b/gfs2/libgfs2/rgrp.c @@ -158,6 +158,42 @@ void lgfs2_rgrp_bitbuf_free(lgfs2_rgrp_t rg) } /** + * Check a resource group's crc + * Returns 0 on success, non-zero if crc is bad + */ +int lgfs2_rgrp_crc_check(const struct gfs2_rgrp *rg, char *buf) +{ + int ret = 0; +#ifdef GFS2_HAS_RG_RI_FIELDS + uint32_t crc = rg->rg_crc; + + if (crc == 0) + return 0; + + ((struct gfs2_rgrp *)buf)->rg_crc = 0; + if (crc != gfs2_disk_hash(buf, sizeof(struct gfs2_rgrp))) + ret = 1; + ((struct gfs2_rgrp *)buf)->rg_crc = cpu_to_be32(crc); +#endif + return ret; +} + +/** + * Set the crc of an on-disk resource group + */ +void lgfs2_rgrp_crc_set(char *buf) +{ +#ifdef GFS2_HAS_RG_RI_FIELDS + struct gfs2_rgrp *rg = (struct gfs2_rgrp *)buf; + uint32_t crc; + + rg->rg_crc = 0; + crc = gfs2_disk_hash(buf, sizeof(struct gfs2_rgrp)); + rg->rg_crc = cpu_to_be32(crc); +#endif +} + +/** * gfs2_rgrp_read - read in the resource group information from disk. * @rgd - resource group structure * returns: 0 if no error, otherwise the block number that failed @@ -194,11 +230,18 @@ uint64_t gfs2_rgrp_read(struct gfs2_sbd *sdp, struct rgrp_tree *rgd) return rgd->ri.ri_addr + err; } } - if (x > 0) { - if (sdp->gfs1) - gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh); - else - gfs2_rgrp_in(&rgd->rg, rgd->bits[0].bi_bh); + if (x <= 0) { + free(bhs); + return 0; + } + if (sdp->gfs1) + gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh); + else { + gfs2_rgrp_in(&rgd->rg, rgd->bits[0].bi_bh); + if (lgfs2_rgrp_crc_check(&rgd->rg, rgd->bits[0].bi_bh->b_data)) { + free(bhs); + return rgd->ri.ri_addr; + } } free(bhs); return 0; @@ -623,6 +666,7 @@ lgfs2_rgrp_t lgfs2_rgrps_append(lgfs2_rgrps_t rgs, struct gfs2_rindex *entry, ui rg->rg.rg_data0 = rg->ri.ri_data0; rg->rg.rg_data = rg->ri.ri_data; rg->rg.rg_bitbytes = rg->ri.ri_bitbytes; + rg->rg.rg_crc = 0; #endif compute_bitmaps(rg, rgs->sdp->bsize); rg->rgrps = rgs; diff --git a/tests/rgrifieldscheck.sh b/tests/rgrifieldscheck.sh index c99470a9..85f6408e 100755 --- a/tests/rgrifieldscheck.sh +++ b/tests/rgrifieldscheck.sh @@ -1,6 +1,9 @@ #!/bin/sh dev=$1 i=0 +gfs2_edit -p rg 0 $dev | grep rg_data0 > /dev/null 2>&1 +# New fields not present in /usr/include/linux/gfs2_ondisk.h +test $? = 0 || exit 0 gfs2_edit -p rindex $dev | while read field rival unused do test $field = ri_data0 -o $field = ri_data -o $field = ri_bitbytes || continue -- 2.13.6
