Separate the block saving code from save_bh out into save_buf so that the resource groups can be dumped without using a temporary gfs2_buffer_head. The rgrp saving code has also been tidied up.
Signed-off-by: Andrew Price <anpr...@redhat.com> --- gfs2/edit/savemeta.c | 123 +++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 62 deletions(-) diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c index 11c83553..f8f3312c 100644 --- a/gfs2/edit/savemeta.c +++ b/gfs2/edit/savemeta.c @@ -527,23 +527,13 @@ static int savemetaclose(struct metafd *mfd) return close(mfd->fd); } -static int save_bh(struct metafd *mfd, struct gfs2_buffer_head *savebh, uint64_t owner, int *blktype) +static int save_buf(struct metafd *mfd, char *buf, uint64_t addr, unsigned blklen) { struct saved_metablock *savedata; - size_t blklen; size_t outsz; - /* If this isn't metadata and isn't a system file, we don't want it. - Note that we're checking "owner" here rather than blk. That's - because we want to know if the source inode is a system inode - not the block within the inode "blk". They may or may not - be the same thing. */ - if (get_gfs_struct_info(savebh, owner, blktype, &blklen) && - !block_is_systemfile(owner) && owner != 0) - return 0; /* Not metadata, and not system file, so skip it */ - /* No need to save trailing zeroes */ - for (; blklen > 0 && savebh->b_data[blklen - 1] == '\0'; blklen--); + for (; blklen > 0 && buf[blklen - 1] == '\0'; blklen--); if (blklen == 0) /* No significant data; skip. */ return 0; @@ -554,34 +544,45 @@ static int save_bh(struct metafd *mfd, struct gfs2_buffer_head *savebh, uint64_t perror("Failed to save block"); exit(1); } - savedata->blk = cpu_to_be64(savebh->b_blocknr); + savedata->blk = cpu_to_be64(addr); savedata->siglen = cpu_to_be16(blklen); - memcpy(savedata + 1, savebh->b_data, blklen); + memcpy(savedata + 1, buf, blklen); if (savemetawrite(mfd, savedata, outsz) != outsz) { - fprintf(stderr, "write error: %s from %s:%d: block %lld (0x%llx)\n", - strerror(errno), __FUNCTION__, __LINE__, - (unsigned long long)savedata->blk, - (unsigned long long)savedata->blk); + fprintf(stderr, "write error: %s from %s:%d: block %"PRIu64"\n", + strerror(errno), __FUNCTION__, __LINE__, addr); free(savedata); exit(-1); } - blks_saved++; free(savedata); return 0; } +static int save_bh(struct metafd *mfd, struct gfs2_buffer_head *savebh, uint64_t owner, int *blktype) +{ + size_t blklen; + + /* If this isn't metadata and isn't a system file, we don't want it. + Note that we're checking "owner" here rather than blk. That's + because we want to know if the source inode is a system inode + not the block within the inode "blk". They may or may not + be the same thing. */ + if (get_gfs_struct_info(savebh, owner, blktype, &blklen) && + !block_is_systemfile(owner) && owner != 0) + return 0; /* Not metadata, and not system file, so skip it */ + + return save_buf(mfd, savebh->b_data, savebh->b_blocknr, blklen); +} + static int save_block(int fd, struct metafd *mfd, uint64_t blk, uint64_t owner, int *blktype) { struct gfs2_buffer_head *savebh; int err; if (gfs2_check_range(&sbd, blk) && blk != LGFS2_SB_ADDR(&sbd)) { - fprintf(stderr, "\nWarning: bad block pointer '0x%llx' " - "ignored in block (block %llu (0x%llx))", - (unsigned long long)blk, - (unsigned long long)owner, (unsigned long long)owner); + fprintf(stderr, "Warning: bad pointer 0x%"PRIx64" ignored in block 0x%"PRIx64"\n", + blk, owner); return 0; } savebh = bread(&sbd, blk); @@ -595,7 +596,7 @@ static int save_block(int fd, struct metafd *mfd, uint64_t blk, uint64_t owner, /* * save_ea_block - save off an extended attribute block */ -static void save_ea_block(struct metafd *mfd, struct gfs2_buffer_head *metabh, uint64_t owner) +static void save_ea_block(struct metafd *mfd, char *buf, uint64_t owner) { int e; struct gfs2_ea_header ea; @@ -604,13 +605,13 @@ static void save_ea_block(struct metafd *mfd, struct gfs2_buffer_head *metabh, u uint64_t blk, *b; int charoff, i; - gfs2_ea_header_in(&ea, metabh->b_data + e); + gfs2_ea_header_in(&ea, buf + e); for (i = 0; i < ea.ea_num_ptrs; i++) { charoff = e + ea.ea_name_len + sizeof(struct gfs2_ea_header) + sizeof(uint64_t) - 1; charoff /= sizeof(uint64_t); - b = (uint64_t *)(metabh->b_data); + b = (uint64_t *)buf; b += charoff + i; blk = be64_to_cpu(*b); save_block(sbd.device_fd, mfd, blk, owner, NULL); @@ -646,7 +647,7 @@ static void save_indirect_blocks(struct metafd *mfd, osi_list_t *cur_list, save_block(sbd.device_fd, mfd, indir_block, owner, &blktype); if (blktype == GFS2_METATYPE_EA) { nbh = bread(&sbd, indir_block); - save_ea_block(mfd, nbh, owner); + save_ea_block(mfd, nbh->b_data, owner); brelse(nbh); } if (height != hgt && /* If not at max height and */ @@ -790,7 +791,7 @@ static void save_inode_data(struct metafd *mfd, uint64_t iblk) gfs2_meta_header_in(&mh, lbh->b_data); if (mh.mh_magic == GFS2_MAGIC && mh.mh_type == GFS2_METATYPE_EA) - save_ea_block(mfd, lbh, iblk); + save_ea_block(mfd, lbh->b_data, iblk); else if (mh.mh_magic == GFS2_MAGIC && mh.mh_type == GFS2_METATYPE_IN) save_indirect_blocks(mfd, cur_list, lbh, iblk, 2, 2); @@ -853,7 +854,7 @@ static void get_journal_inode_blocks(void) jblock = ji.ji_addr; gfs1_journal_size = (uint64_t)ji.ji_nsegment * 16; } else { - if (journal > indirect->ii[0].dirents - 3) + if (journal + 3 > indirect->ii[0].dirents) break; jblock = indirect->ii[0].dirent[journal + 2].block; } @@ -878,7 +879,6 @@ static void save_allocated(struct rgrp_tree *rgd, struct metafd *mfd) if (blktype == GFS2_METATYPE_DI) save_inode_data(mfd, blk); } - if (!sbd.gfs1) continue; @@ -892,57 +892,56 @@ static void save_allocated(struct rgrp_tree *rgd, struct metafd *mfd) free(ibuf); } -/* We don't use gfs2_rgrp_read() here as it checks for metadata sanity and we - want to save rgrp headers even if they're corrupt. */ -static int rgrp_read(struct gfs2_sbd *sdp, struct rgrp_tree *rgd) +static char *rgrp_read(struct gfs2_sbd *sdp, uint64_t addr, unsigned blocks) { - unsigned length = rgd->ri.ri_length * sdp->bsize; - off_t off = rgd->ri.ri_addr * sdp->bsize; + size_t len = blocks * sdp->bsize; + off_t off = addr * sdp->bsize; char *buf; - if (length == 0 || gfs2_check_range(sdp, rgd->ri.ri_addr)) - return -1; + if (blocks == 0 || gfs2_check_range(sdp, addr)) + return NULL; - buf = calloc(1, length); + buf = calloc(1, len); if (buf == NULL) - return -1; + return NULL; - if (pread(sdp->device_fd, buf, length, off) != length) { + if (pread(sdp->device_fd, buf, len, off) != len) { free(buf); - return -1; + return NULL; } - for (unsigned i = 0; i < rgd->ri.ri_length; i++) - rgd->bits[i].bi_data = buf + (i * sdp->bsize); - - if (sdp->gfs1) - gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_data); - else - gfs2_rgrp_in(&rgd->rg, rgd->bits[0].bi_data); - return 0; + return buf; } -static void save_rgrp(struct metafd *mfd, struct rgrp_tree *rgd, int withcontents) +static void save_rgrp(struct gfs2_sbd *sdp, struct metafd *mfd, struct rgrp_tree *rgd, int withcontents) { uint64_t addr = rgd->ri.ri_addr; - uint32_t i; + char *buf; - if (rgrp_read(&sbd, rgd)) + buf = rgrp_read(sdp, rgd->ri.ri_addr, rgd->ri.ri_length); + if (buf == NULL) return; - log_debug("RG at %"PRIu64" (0x%"PRIx64") is %u long\n", - addr, addr, rgd->ri.ri_length); + + if (sdp->gfs1) + gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg, buf); + else + gfs2_rgrp_in(&rgd->rg, buf); + + for (unsigned i = 0; i < rgd->ri.ri_length; i++) + rgd->bits[i].bi_data = buf + (i * sdp->bsize); + + log_debug("RG at %"PRIu64" is %"PRIu32" long\n", addr, (uint32_t)rgd->ri.ri_length); /* Save the rg and bitmaps */ - for (i = 0; i < rgd->ri.ri_length; i++) { - struct gfs2_buffer_head tmpbh = { - .b_data = rgd->bits[i].bi_data, - .b_blocknr = rgd->ri.ri_addr + i - }; + for (unsigned i = 0; i < rgd->ri.ri_length; i++) { warm_fuzzy_stuff(rgd->ri.ri_addr + i, FALSE); - save_bh(mfd, &tmpbh, 0, NULL); + save_buf(mfd, buf + (i * sdp->bsize), rgd->ri.ri_addr + i, sdp->bsize); } /* Save the other metadata: inodes, etc. if mode is not 'savergs' */ if (withcontents) save_allocated(rgd, mfd); - gfs2_rgrp_relse(&sbd, rgd); + + free(buf); + for (unsigned i = 0; i < rgd->ri.ri_length; i++) + rgd->bits[i].bi_data = NULL; } static int save_header(struct metafd *mfd, uint64_t fsbytes) @@ -1042,7 +1041,7 @@ void savemeta(char *out_fn, int saveoption, int gziplevel) struct rgrp_tree *rgd; rgd = (struct rgrp_tree *)n; - save_rgrp(&mfd, rgd, (saveoption != 2)); + save_rgrp(&sbd, &mfd, rgd, (saveoption != 2)); } /* Clean up */ /* There may be a gap between end of file system and end of device */ -- 2.26.2