save_block() accepts a block number, reads it and saves it, which makes
it tricky to save an already-read block without reading it a second
time. Split out the bh saving part of save_block() into save_bh() to
make things more flexible.

Also switch the return value of save_block to only convey error/success
and return the block type through an optional pointer argument instead.

Signed-off-by: Andrew Price <anpr...@redhat.com>
---
 gfs2/edit/savemeta.c | 74 +++++++++++++++++++++++++++++-----------------------
 1 file changed, 41 insertions(+), 33 deletions(-)

diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index db9a947..3e8dae0 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -208,14 +208,16 @@ static int get_gfs_struct_info(struct gfs2_buffer_head 
*lbh, uint64_t owner,
        struct gfs2_meta_header mh;
        struct gfs2_inode *inode;
 
-       *block_type = 0;
+       if (block_type != NULL)
+               *block_type = 0;
        *gstruct_len = sbd.bsize;
 
        gfs2_meta_header_in(&mh, lbh);
        if (mh.mh_magic != GFS2_MAGIC)
                return -1;
 
-       *block_type = mh.mh_type;
+       if (block_type != NULL)
+               *block_type = mh.mh_type;
 
        switch (mh.mh_type) {
        case GFS2_METATYPE_SB:   /* 1 (superblock) */
@@ -405,32 +407,19 @@ static int savemetaclose(struct metafd *mfd)
        return close(mfd->fd);
 }
 
-static int save_block(int fd, struct metafd *mfd, uint64_t blk, uint64_t owner)
+static int save_bh(struct metafd *mfd, struct gfs2_buffer_head *savebh, 
uint64_t owner, int *blktype)
 {
-       int blktype, blklen;
-       size_t outsz;
-       struct gfs2_buffer_head *savebh;
        struct saved_metablock *savedata;
-
-       if (gfs2_check_range(&sbd, blk) && blk != sbd.sb_addr) {
-               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);
-               return 0;
-       }
-       savebh = bread(&sbd, blk);
+       size_t outsz;
+       int 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)) {
-               brelse(savebh);
+       if (get_gfs_struct_info(savebh, owner, blktype, &blklen) && 
!block_is_systemfile(owner))
                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--);
@@ -444,7 +433,7 @@ static int save_block(int fd, struct metafd *mfd, uint64_t 
blk, uint64_t owner)
                perror("Failed to save block");
                exit(1);
        }
-       savedata->blk = cpu_to_be64(blk);
+       savedata->blk = cpu_to_be64(savebh->b_blocknr);
        savedata->siglen = cpu_to_be16(blklen);
        memcpy(savedata->buf, savebh->b_data, blklen);
 
@@ -459,8 +448,27 @@ static int save_block(int fd, struct metafd *mfd, uint64_t 
blk, uint64_t owner)
 
        blks_saved++;
        free(savedata);
+       return 0;
+}
+
+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 != sbd.sb_addr) {
+               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);
+               return 0;
+       }
+       savebh = bread(&sbd, blk);
+       if (savebh == NULL)
+               return 1;
+       err = save_bh(mfd, savebh, owner, blktype);
        brelse(savebh);
-       return blktype;
+       return err;
 }
 
 /*
@@ -484,7 +492,7 @@ static void save_ea_block(struct metafd *mfd, struct 
gfs2_buffer_head *metabh, u
                        b = (uint64_t *)(metabh->b_data);
                        b += charoff + i;
                        blk = be64_to_cpu(*b);
-                       save_block(sbd.device_fd, mfd, blk, owner);
+                       save_block(sbd.device_fd, mfd, blk, owner, NULL);
                }
                if (!ea.ea_rec_len)
                        break;
@@ -514,7 +522,7 @@ static void save_indirect_blocks(struct metafd *mfd, 
osi_list_t *cur_list,
                if (indir_block == old_block)
                        continue;
                old_block = indir_block;
-               blktype = save_block(sbd.device_fd, mfd, indir_block, owner);
+               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);
@@ -625,7 +633,7 @@ static void save_inode_data(struct metafd *mfd, uint64_t 
iblk)
                        mybh = bread(&sbd, leaf_no);
                        warm_fuzzy_stuff(iblk, FALSE);
                        if (gfs2_check_meta(mybh, GFS2_METATYPE_LF) == 0)
-                               save_block(sbd.device_fd, mfd, leaf_no, iblk);
+                               save_block(sbd.device_fd, mfd, leaf_no, iblk, 
NULL);
                        brelse(mybh);
                }
        }
@@ -634,7 +642,7 @@ static void save_inode_data(struct metafd *mfd, uint64_t 
iblk)
                struct gfs2_buffer_head *lbh;
 
                lbh = bread(&sbd, inode->i_di.di_eattr);
-               save_block(sbd.device_fd, mfd, inode->i_di.di_eattr, iblk);
+               save_block(sbd.device_fd, mfd, inode->i_di.di_eattr, iblk, 
NULL);
                gfs2_meta_header_in(&mh, lbh);
                if (mh.mh_magic == GFS2_MAGIC &&
                    mh.mh_type == GFS2_METATYPE_EA)
@@ -644,8 +652,8 @@ static void save_inode_data(struct metafd *mfd, uint64_t 
iblk)
                        save_indirect_blocks(mfd, cur_list, lbh, iblk, 2, 2);
                else {
                        if (mh.mh_magic == GFS2_MAGIC) /* if it's metadata */
-                               save_block(sbd.device_fd, mfd,
-                                          inode->i_di.di_eattr, iblk);
+                               save_block(sbd.device_fd, mfd, 
inode->i_di.di_eattr,
+                                          iblk, NULL);
                        fprintf(stderr,
                                "\nWarning: corrupt extended "
                                "attribute at block %llu (0x%llx) "
@@ -722,7 +730,7 @@ static void save_allocated(struct rgrp_tree *rgd, struct 
metafd *mfd)
                for (j = 0; j < m; j++) {
                        blk = ibuf[j];
                        warm_fuzzy_stuff(blk, FALSE);
-                       blktype = save_block(sbd.device_fd, mfd, blk, blk);
+                       save_block(sbd.device_fd, mfd, blk, blk, &blktype);
                        if (blktype == GFS2_METATYPE_DI)
                                save_inode_data(mfd, blk);
                }
@@ -734,7 +742,7 @@ static void save_allocated(struct rgrp_tree *rgd, struct 
metafd *mfd)
                 * If we don't, we may run into metadata allocation issues. */
                m = lgfs2_bm_scan(rgd, i, ibuf, GFS2_BLKST_UNLINKED);
                for (j = 0; j < m; j++) {
-                       save_block(sbd.device_fd, mfd, blk, blk);
+                       save_block(sbd.device_fd, mfd, blk, blk, NULL);
                }
        }
        free(ibuf);
@@ -826,7 +834,7 @@ void savemeta(char *out_fn, int saveoption, int gziplevel)
                exit(1);
        }
        /* Save off the superblock */
-       save_block(sbd.device_fd, &mfd, GFS2_SB_ADDR * GFS2_BASIC_BLOCK / 
sbd.bsize, 0);
+       save_block(sbd.device_fd, &mfd, GFS2_SB_ADDR * GFS2_BASIC_BLOCK / 
sbd.bsize, 0, NULL);
        /* If this is gfs1, save off the rindex because it's not
           part of the file system as it is in gfs2. */
        if (sbd.gfs1) {
@@ -834,7 +842,7 @@ void savemeta(char *out_fn, int saveoption, int gziplevel)
                int j;
 
                blk = sbd1->sb_rindex_di.no_addr;
-               save_block(sbd.device_fd, &mfd, blk, blk);
+               save_block(sbd.device_fd, &mfd, blk, blk, NULL);
                save_inode_data(&mfd, blk);
                /* In GFS1, journals aren't part of the RG space */
                for (j = 0; j < journals_found; j++) {
@@ -842,7 +850,7 @@ void savemeta(char *out_fn, int saveoption, int gziplevel)
                        for (blk = journal_blocks[j];
                             blk < journal_blocks[j] + gfs1_journal_size;
                             blk++)
-                               save_block(sbd.device_fd, &mfd, blk, blk);
+                               save_block(sbd.device_fd, &mfd, blk, blk, NULL);
                }
        }
        /* Walk through the resource groups saving everything within */
@@ -861,7 +869,7 @@ void savemeta(char *out_fn, int saveoption, int gziplevel)
                for (blk = rgd->ri.ri_addr;
                     blk < rgd->ri.ri_data0; blk++) {
                        warm_fuzzy_stuff(blk, FALSE);
-                       save_block(sbd.device_fd, &mfd, blk, blk);
+                       save_block(sbd.device_fd, &mfd, blk, blk, NULL);
                }
                /* Save off the other metadata: inodes, etc. if mode is not 
'savergs' */
                if (saveoption != 2) {
-- 
2.9.3

Reply via email to