gfs2-utils: master - gfs2_edit savemeta: Save corrupt rgrp headers
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=e6bb3d27...
Commit: e6bb3d27cd08c50f04825f5873023d19534c5fe6
Parent: 803f914e2d9a6397bf09dabede18590b0a0fb29a
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Wed Jan 18 15:14:57 2017 +0000
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Wed Jan 18 16:21:54 2017 +0000
gfs2_edit savemeta: Save corrupt rgrp headers
Previously, savemeta used gfs2_rgrp_read() to read resource groups. This
includes a metadata check which fails the read if the resource groups
are corrupt. Since we want to save corruption in order to analyze it, we
need to read the rgrp headers without checking them. Use a new,
simplified rgrp_read() function for that.
Also avoid the effect of a similar metadata check in
get_gfs_struct_info() when saving rgrps.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/edit/savemeta.c | 34 ++++++++++++++++++++++++++++++++--
1 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index da24645..dee405b 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -417,7 +417,8 @@ static int save_bh(struct metafd *mfd, struct gfs2_buffer_head *savebh, uint64_t
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))
+ 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 */
@@ -770,12 +771,41 @@ 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)
+{
+ unsigned x, length = rgd->ri.ri_length;
+ struct gfs2_buffer_head **bhs;
+
+ if (length == 0 || gfs2_check_range(sdp, rgd->ri.ri_addr))
+ return -1;
+
+ bhs = calloc(length, sizeof(struct gfs2_buffer_head *));
+ if (bhs == NULL)
+ return -1;
+
+ if (breadm(sdp, bhs, length, rgd->ri.ri_addr)) {
+ free(bhs);
+ return -1;
+ }
+ for (x = 0; x < length; x++)
+ rgd->bits[x].bi_bh = bhs[x];
+
+ 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);
+ free(bhs);
+ return 0;
+}
+
static void save_rgrp(struct metafd *mfd, struct rgrp_tree *rgd, int withcontents)
{
uint64_t addr = rgd->ri.ri_addr;
uint32_t i;
- if (gfs2_rgrp_read(&sbd, rgd))
+ if (rgrp_read(&sbd, rgd))
return;
log_debug("RG at %"PRIu64" (0x%"PRIx64") is %u long\n",
addr, addr, rgd->ri.ri_length);
7 years, 3 months
gfs2-utils: master - gfs2_edit savemeta: Split out the rgrp saving
code
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=803f914e...
Commit: 803f914e2d9a6397bf09dabede18590b0a0fb29a
Parent: bcd5202ac5c8b8165b8005a572b9af1f208c34f1
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Wed Jan 18 13:59:09 2017 +0000
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Wed Jan 18 13:59:09 2017 +0000
gfs2_edit savemeta: Split out the rgrp saving code
Factor out the rgrp saving code into its own function to make it easier
to work with.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/edit/savemeta.c | 38 +++++++++++++++++++++-----------------
1 files changed, 21 insertions(+), 17 deletions(-)
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index f6b7ff0..da24645 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -770,6 +770,26 @@ static void save_allocated(struct rgrp_tree *rgd, struct metafd *mfd)
free(ibuf);
}
+static void save_rgrp(struct metafd *mfd, struct rgrp_tree *rgd, int withcontents)
+{
+ uint64_t addr = rgd->ri.ri_addr;
+ uint32_t i;
+
+ if (gfs2_rgrp_read(&sbd, rgd))
+ return;
+ log_debug("RG at %"PRIu64" (0x%"PRIx64") is %u long\n",
+ addr, addr, rgd->ri.ri_length);
+ /* Save the rg and bitmaps */
+ for (i = 0; i < rgd->ri.ri_length; i++) {
+ warm_fuzzy_stuff(rgd->ri.ri_addr + i, FALSE);
+ save_bh(mfd, rgd->bits[i].bi_bh, 0, NULL);
+ }
+ /* Save the other metadata: inodes, etc. if mode is not 'savergs' */
+ if (withcontents)
+ save_allocated(rgd, mfd);
+ gfs2_rgrp_relse(rgd);
+}
+
static int save_header(struct metafd *mfd, uint64_t fsbytes)
{
struct savemeta_header smh = {
@@ -878,25 +898,9 @@ void savemeta(char *out_fn, int saveoption, int gziplevel)
/* Walk through the resource groups saving everything within */
for (n = osi_first(&sbd.rgtree); n; n = osi_next(n)) {
struct rgrp_tree *rgd;
- unsigned i;
rgd = (struct rgrp_tree *)n;
- if (gfs2_rgrp_read(&sbd, rgd))
- continue;
- log_debug("RG at %lld (0x%llx) is %u long\n",
- (unsigned long long)rgd->ri.ri_addr,
- (unsigned long long)rgd->ri.ri_addr,
- rgd->ri.ri_length);
- /* Save off the rg and bitmaps */
- for (i = 0; i < rgd->ri.ri_length; i++) {
- warm_fuzzy_stuff(rgd->ri.ri_addr + i, FALSE);
- save_bh(&mfd, rgd->bits[i].bi_bh, 0, NULL);
- }
- /* Save off the other metadata: inodes, etc. if mode is not 'savergs' */
- if (saveoption != 2) {
- save_allocated(rgd, &mfd);
- }
- gfs2_rgrp_relse(rgd);
+ save_rgrp(&mfd, rgd, (saveoption != 2));
}
/* Clean up */
/* There may be a gap between end of file system and end of device */
7 years, 3 months
gfs2-utils: master - fsck.gfs2: Repair rindex entries that were
destroyed
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=bcd5202a...
Commit: bcd5202ac5c8b8165b8005a572b9af1f208c34f1
Parent: 99444c0388a31db2a579c63ea5ddb5333a3ffe06
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 13 14:42:14 2017 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Jan 16 15:43:23 2017 -0500
fsck.gfs2: Repair rindex entries that were destroyed
If an rindex entry was destroyed, the rindex was skipped, which
means its rgrp never gets inserted into the rgrp tree. The trouble
is, that causes a off-by-one-entry problem with all subsequent
rindex entries. So if rindex entry R is destroyed, then rebuilt,
originally good entry R+1 is checked against new entry for R.
Function rg_repair already had the capability to insert new rindex
entries, but only at the end. This would be typical for a gfs2_grow
that failed and left a bunch of rgrps on the device, but the rindex
was never synced properly.
This patch allows the function to insert catch-up entries in the
middle, which re-syncs the actual versus expected rgrp trees.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/fsck/rgrepair.c | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/gfs2/fsck/rgrepair.c b/gfs2/fsck/rgrepair.c
index 49bbad6..f397db1 100644
--- a/gfs2/fsck/rgrepair.c
+++ b/gfs2/fsck/rgrepair.c
@@ -1137,10 +1137,14 @@ int rg_repair(struct gfs2_sbd *sdp, int trust_lvl, int *rg_count, int *sane)
next = osi_next(n);
enext = osi_next(e);
expected = (struct rgrp_tree *)e;
+ actual = (struct rgrp_tree *)n;
- /* If we ran out of actual rindex entries due to rindex
+ /* If the next "actual" rgrp in memory is too far away,
+ fill in a new one with the expected value. -or-
+ If we ran out of actual rindex entries due to rindex
damage, fill in a new one with the expected values. */
- if (!n) { /* end of actual rindex */
+ if (!n || /* end of actual rindex */
+ expected->ri.ri_addr < actual->ri.ri_addr) {
log_err( _("Entry missing from rindex: 0x%llx\n"),
(unsigned long long)expected->ri.ri_addr);
actual = rgrp_insert(&sdp->rgtree,
@@ -1150,8 +1154,9 @@ int rg_repair(struct gfs2_sbd *sdp, int trust_lvl, int *rg_count, int *sane)
break;
}
rindex_modified = 1;
+ next = n; /* Ensure that the old actual gets checked
+ against a new expected, since we added */
} else {
- actual = (struct rgrp_tree *)n;
ri_compare(rg, actual->ri, expected->ri, ri_addr,
"llx", unsigned long long);
ri_compare(rg, actual->ri, expected->ri, ri_length,
7 years, 3 months
gfs2-utils: master - fsck.gfs2: allow rindex recovery when too many
segments
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=99444c03...
Commit: 99444c0388a31db2a579c63ea5ddb5333a3ffe06
Parent: 9cd630b8bc3315c0fd16a464896e302c4cf0e415
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 13 14:36:56 2017 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Jan 16 15:43:23 2017 -0500
fsck.gfs2: allow rindex recovery when too many segments
Patch 0103dc0 (fsck.gfs2: Detect multiple rgrp grow segments) added
an array of rgrp segments. If it found too many segments, it threw
up its hands and gave up and refused to try to fix it. But in most
cases, proceeding to fix the rgrps won't cause any harm, since the
rgrps are checked for integrity anyway. This patch allows fsck to
try to fix the rgrp corruption, even after the maximum number of
rgrp segments has been reached.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/fsck/rgrepair.c | 6 ++----
1 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/gfs2/fsck/rgrepair.c b/gfs2/fsck/rgrepair.c
index 7479458..49bbad6 100644
--- a/gfs2/fsck/rgrepair.c
+++ b/gfs2/fsck/rgrepair.c
@@ -230,9 +230,8 @@ static int find_shortest_rgdist(struct gfs2_sbd *sdp, uint64_t *dist_array,
}
if (gsegment >= MAX_RGSEGMENTS) {
log_err(_("Maximum number of rgrp grow segments reached.\n"));
- log_err(_("This file system cannot be repaired with fsck.\n"));
- gsegment = 0;
- goto out;
+ log_err(_("This file system has more than %d resource "
+ "group segments.\n"), MAX_RGSEGMENTS);
}
/* -------------------------------------------------------------- */
/* Sanity-check our first_rg_dist. If RG #2 got nuked, the */
@@ -260,7 +259,6 @@ static int find_shortest_rgdist(struct gfs2_sbd *sdp, uint64_t *dist_array,
(unsigned long long)*dist_array);
} /* if first RG distance is within tolerance */
-out:
gfs2_special_free(&false_rgrps);
return gsegment;
}
7 years, 3 months
gfs2-utils: master - fsck.gfs2: Prevent rgrp segment overflow
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=9cd630b8...
Commit: 9cd630b8bc3315c0fd16a464896e302c4cf0e415
Parent: f4797121a2a3daebe333ac19ddc207157c5c8168
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 13 14:30:13 2017 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Jan 16 15:43:23 2017 -0500
fsck.gfs2: Prevent rgrp segment overflow
Patch 0103dc0 (fsck.gfs2: Detect multiple rgrp grow segments) allowed
fsck to detect multiple gfs2_grow segments that may have placed
resource groups on unexpected boundaries. However, it failed to check
or take appropriate action when too many segments were found.
Instead, it would write past the arrays and corrupt memory. This
patch adds some sanity checks to prevent this from happening.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/fsck/rgrepair.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/gfs2/fsck/rgrepair.c b/gfs2/fsck/rgrepair.c
index 55057ce..7479458 100644
--- a/gfs2/fsck/rgrepair.c
+++ b/gfs2/fsck/rgrepair.c
@@ -164,6 +164,8 @@ static int find_shortest_rgdist(struct gfs2_sbd *sdp, uint64_t *dist_array,
/* That last one didn't pan out, so: */
dist_cnt[gsegment]--;
gsegment++;
+ if (gsegment >= MAX_RGSEGMENTS)
+ break;
}
if ((blk - block_last_rg) > (524288 * 2)) {
log_info(_("No rgrps were found within 4GB "
@@ -217,6 +219,8 @@ static int find_shortest_rgdist(struct gfs2_sbd *sdp, uint64_t *dist_array,
}
} else {
gsegment++;
+ if (gsegment >= MAX_RGSEGMENTS)
+ break;
}
block_last_rg = blk;
if (rgs_sampled < 6)
@@ -224,7 +228,7 @@ static int find_shortest_rgdist(struct gfs2_sbd *sdp, uint64_t *dist_array,
else
blk += shortest_dist_btwn_rgs - 1;
}
- if (gsegment > MAX_RGSEGMENTS) {
+ if (gsegment >= MAX_RGSEGMENTS) {
log_err(_("Maximum number of rgrp grow segments reached.\n"));
log_err(_("This file system cannot be repaired with fsck.\n"));
gsegment = 0;
7 years, 3 months
gfs2-utils: master - libgfs2: Make rg repair do better sanity checks
on rindex
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=f4797121...
Commit: f4797121a2a3daebe333ac19ddc207157c5c8168
Parent: 91b80722d19bf6d703d9c1f4d2c618ec7ad19fa6
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Thu Jan 12 16:09:32 2017 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Jan 16 15:43:23 2017 -0500
libgfs2: Make rg repair do better sanity checks on rindex
This patch changes the checks done on the rindex file. Before, if
the rindex addresses weren't perfectly aligned and equally spaced,
it considered the rindex not sane. However, in most cases it should
be sane. Rather than flag this as a violation, I use it to trigger
a read from disk to see if the rindex really DOES point to an rgrp
in these cases, and if not, THEN flag the rindex as not sane.
I also added some basic checks on the rindex values, such as
checking if the number of bitmaps is sane, and if most of the fields
have values we'd expect.
Signed-off-by: Bob Peterson <rpeterso(a)redhat.com>
---
gfs2/libgfs2/super.c | 66 +++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 57 insertions(+), 9 deletions(-)
diff --git a/gfs2/libgfs2/super.c b/gfs2/libgfs2/super.c
index 81834b3..6175203 100644
--- a/gfs2/libgfs2/super.c
+++ b/gfs2/libgfs2/super.c
@@ -127,6 +127,59 @@ int read_sb(struct gfs2_sbd *sdp)
return 0;
}
+/* rgd_seems_sane - check some general things about the rindex entry
+ *
+ * If rg lengths are not consistent, it's not sane (or it's converted from
+ * gfs1). The first RG will be a different length due to space reserved for
+ * the superblock, so we can't detect this until we check rgrp 3, when we
+ * can compare the distance between rgrp 1 and rgrp 2.
+ *
+ * Returns: 1 if the rgd seems relatively sane
+ */
+static int rgd_seems_sane(struct gfs2_sbd *sdp, struct rgrp_tree *rgd)
+{
+ uint32_t most_bitmaps_possible;
+
+ /* rg length must be at least 1 */
+ if (rgd->ri.ri_length == 0)
+ return 0;
+
+ /* A max rgrp, 2GB, divided into blocksize, divided by blocks/byte
+ represented in the bitmap, NBBY. Rough approximation only, due to
+ metadata headers. I'm doing the math this way to avoid overflow. */
+ most_bitmaps_possible = (GFS2_MAX_RGSIZE * 1024 * 256) / sdp->bsize;
+ if (rgd->ri.ri_length > most_bitmaps_possible)
+ return 0;
+
+ if (rgd->ri.ri_data0 != rgd->ri.ri_addr + rgd->ri.ri_length)
+ return 0;
+
+ if (rgd->ri.ri_bitbytes != rgd->ri.ri_data / GFS2_NBBY)
+ return 0;
+
+ return 1;
+}
+
+/* good_on_disk - check if the rindex points to what looks like an rgrp on disk
+ *
+ * This is only called when the rindex pointers aren't spaced evenly, which
+ * isn't often. The rindex is pointing to an unexpected location, so we
+ * check if the block it is pointing to is really an rgrp. If so, we count the
+ * rindex entry as "sane" (after all, it did pass the previous checks above.)
+ * If not, we count it as not sane, and therefore, the whole rindex is not to
+ * be trusted by fsck.gfs2.
+ */
+static int good_on_disk(struct gfs2_sbd *sdp, struct rgrp_tree *rgd)
+{
+ struct gfs2_buffer_head *bh;
+ int is_rgrp;
+
+ bh = bread(sdp, rgd->ri.ri_addr);
+ is_rgrp = (gfs2_check_meta(bh, GFS2_METATYPE_RG) == 0);
+ brelse(bh);
+ return is_rgrp;
+}
+
/**
* rindex_read - read in the rg index file
* @sdp: the incore superblock pointer
@@ -182,17 +235,12 @@ int rindex_read(struct gfs2_sbd *sdp, int fd, uint64_t *count1, int *sane)
if (!sdp->gfs1) {
if (prev_rgd->start >= rgd->start)
*sane = 0;
- /* If rg lengths are not consistent, it's not
- sane (or it's converted from gfs1). The
- first RG will be a different length due to
- space allocated for the superblock, so we
- can't detect this until we check rgrp 3,
- when we can compare the distance between
- rgrp 1 and rgrp 2. */
- if (rg > 2 && prev_length &&
+ else if (!rgd_seems_sane(sdp, rgd))
+ *sane = 0;
+ else if (*sane && rg > 2 && prev_length &&
prev_length != rgd->start -
prev_rgd->start)
- *sane = 0;
+ *sane = good_on_disk(sdp, rgd);
}
prev_length = rgd->start - prev_rgd->start;
prev_rgd->length = rgrp_size(prev_rgd);
7 years, 3 months
gfs2-utils: master - gfs2_edit: Fix unaligned accesses due to
saved_metablock size
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=91b80722...
Commit: 91b80722d19bf6d703d9c1f4d2c618ec7ad19fa6
Parent: a411713232097d1fe73d94d3bb2c5ae52f62074e
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Thu Nov 10 00:08:44 2016 +0000
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Thu Jan 12 16:20:34 2017 +0000
gfs2_edit: Fix unaligned accesses due to saved_metablock size
Each saved block is prefixed by a saved_metablock structure that holds
its block number and data length. Unfortunately this structure is 10
bytes in size, which means that storing the metadata header in memory
immediately following it causes accesses to the header fields to be
unaligned. This causes testsuite failures on sparc64. Instead, on
restore, use a separate buffer for the block data to ensure aligned
accesses to those fields.
Reported-By: Valentin Vidic <Valentin.Vidic(a)CARNet.hr>
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/edit/savemeta.c | 59 +++++++++++++++++++++++--------------------------
1 files changed, 28 insertions(+), 31 deletions(-)
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index ac2dd9f..f6b7ff0 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -44,7 +44,6 @@ struct savemeta_header {
struct saved_metablock {
uint64_t blk;
uint16_t siglen; /* significant data length */
- char buf[];
/* This needs to be packed because old versions of gfs2_edit read and write the
individual fields separately, so the hole after siglen must be eradicated
before the struct reflects what's on disk. */
@@ -435,7 +434,7 @@ static int save_bh(struct metafd *mfd, struct gfs2_buffer_head *savebh, uint64_t
}
savedata->blk = cpu_to_be64(savebh->b_blocknr);
savedata->siglen = cpu_to_be16(blklen);
- memcpy(savedata->buf, savebh->b_data, blklen);
+ memcpy(savedata + 1, savebh->b_data, blklen);
if (savemetawrite(mfd, savedata, outsz) != outsz) {
fprintf(stderr, "write error: %s from %s:%d: block %lld (0x%llx)\n",
@@ -956,7 +955,7 @@ static off_t restore_init(gzFile gzfd, struct savemeta_header *smh)
}
-static int restore_block(gzFile gzfd, struct saved_metablock *svb, uint16_t maxlen)
+static int restore_block(gzFile gzfd, struct saved_metablock *svb, char *buf, uint16_t maxlen)
{
int gzerr;
int ret;
@@ -988,8 +987,8 @@ static int restore_block(gzFile gzfd, struct saved_metablock *svb, uint16_t maxl
return -1;
}
- if (maxlen) {
- ret = gzread(gzfd, svb + 1, svb->siglen);
+ if (buf != NULL && maxlen != 0) {
+ ret = gzread(gzfd, buf, svb->siglen);
if (ret < svb->siglen) {
goto gzread_err;
}
@@ -1011,17 +1010,16 @@ gzread_err:
static int restore_super(gzFile gzfd, off_t pos)
{
int ret;
- struct saved_metablock *svb;
+ struct saved_metablock svb = {0};
struct gfs2_buffer_head dummy_bh;
- size_t len = sizeof(*svb) + sizeof(struct gfs2_sb);
- svb = calloc(1, len);
- if (svb == NULL) {
+ dummy_bh.b_data = calloc(1, sizeof(struct gfs2_sb));
+ if (dummy_bh.b_data == NULL) {
perror("Failed to restore super block");
exit(1);
}
gzseek(gzfd, pos, SEEK_SET);
- ret = restore_block(gzfd, svb, sizeof(struct gfs2_sb));
+ ret = restore_block(gzfd, &svb, dummy_bh.b_data, sizeof(struct gfs2_sb));
if (ret == 1) {
fprintf(stderr, "Reached end of file while restoring superblock\n");
goto err;
@@ -1029,7 +1027,6 @@ static int restore_super(gzFile gzfd, off_t pos)
goto err;
}
- dummy_bh.b_data = (char *)svb->buf;
gfs2_sb_in(&sbd.sd_sb, &dummy_bh);
sbd1 = (struct gfs_sb *)&sbd.sd_sb;
ret = check_sb(&sbd.sd_sb);
@@ -1040,11 +1037,11 @@ static int restore_super(gzFile gzfd, off_t pos)
if (ret == 1)
sbd.gfs1 = 1;
sbd.bsize = sbd.sd_sb.sb_bsize;
- free(svb);
+ free(dummy_bh.b_data);
printf("Block size is %uB\n", sbd.bsize);
return 0;
err:
- free(svb);
+ free(dummy_bh.b_data);
return -1;
}
@@ -1056,7 +1053,7 @@ static int find_highest_block(gzFile gzfd, off_t pos, uint64_t fssize)
while (1) {
gzseek(gzfd, pos, SEEK_SET);
- err = restore_block(gzfd, &svb, 0);
+ err = restore_block(gzfd, &svb, NULL, 0);
if (err == 1)
break;
if (err != 0)
@@ -1081,12 +1078,12 @@ static int find_highest_block(gzFile gzfd, off_t pos, uint64_t fssize)
static int restore_data(int fd, gzFile gzin_fd, off_t pos, int printonly)
{
- struct saved_metablock *savedata;
- size_t insz = sizeof(*savedata) + sbd.bsize;
+ struct saved_metablock savedata = {0};
uint64_t writes = 0;
+ char *buf;
- savedata = calloc(1, insz);
- if (savedata == NULL) {
+ buf = calloc(1, sbd.bsize);
+ if (buf == NULL) {
perror("Failed to restore data");
exit(1);
}
@@ -1095,36 +1092,36 @@ static int restore_data(int fd, gzFile gzin_fd, off_t pos, int printonly)
blks_saved = 0;
while (TRUE) {
int err;
- err = restore_block(gzin_fd, savedata, sbd.bsize);
+ err = restore_block(gzin_fd, &savedata, buf, sbd.bsize);
if (err == 1)
break;
if (err != 0) {
- free(savedata);
+ free(buf);
return -1;
}
if (printonly) {
struct gfs2_buffer_head dummy_bh = {
- .b_data = savedata->buf,
- .b_blocknr = savedata->blk,
+ .b_data = buf,
+ .b_blocknr = savedata.blk,
};
- if (printonly > 1 && printonly == savedata->blk) {
+ if (printonly > 1 && printonly == savedata.blk) {
display_block_type(&dummy_bh, TRUE);
display_gfs2(&dummy_bh);
break;
} else if (printonly == 1) {
- print_gfs2("%"PRId64" (l=0x%x): ", blks_saved, savedata->siglen);
+ print_gfs2("%"PRId64" (l=0x%x): ", blks_saved, savedata.siglen);
display_block_type(&dummy_bh, TRUE);
}
} else {
- warm_fuzzy_stuff(savedata->blk, FALSE);
- memset(savedata->buf + savedata->siglen, 0, sbd.bsize - savedata->siglen);
- if (pwrite(fd, savedata->buf, sbd.bsize, savedata->blk * sbd.bsize) != sbd.bsize) {
+ warm_fuzzy_stuff(savedata.blk, FALSE);
+ memset(buf + savedata.siglen, 0, sbd.bsize - savedata.siglen);
+ if (pwrite(fd, buf, sbd.bsize, savedata.blk * sbd.bsize) != sbd.bsize) {
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);
- free(savedata);
+ (unsigned long long)savedata.blk,
+ (unsigned long long)savedata.blk);
+ free(buf);
return -1;
}
writes++;
@@ -1135,7 +1132,7 @@ static int restore_data(int fd, gzFile gzin_fd, off_t pos, int printonly)
}
if (!printonly)
warm_fuzzy_stuff(sbd.fssize, 1);
- free(savedata);
+ free(buf);
return 0;
}
7 years, 3 months
gfs2-utils: master - gfs2_edit: Fix unaligned access in restore_init()
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=a4117132...
Commit: a411713232097d1fe73d94d3bb2c5ae52f62074e
Parent: b4333e4109d082e666ec74f534ef4d55df6557dd
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Wed Nov 9 18:27:12 2016 +0000
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Thu Jan 12 16:20:33 2017 +0000
gfs2_edit: Fix unaligned access in restore_init()
Scanning this buffer byte-by-byte using casts results in a quick bus
error on sparc64. Avoid this by using a memcpy. This function only runs
once at the beginning of a restoremeta and in most cases the loop will
only execute once so this adds very little overhead.
Reported-By: Valentin Vidic <Valentin.Vidic(a)CARNet.hr>
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/edit/savemeta.c | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index c9b51e9..ac2dd9f 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -924,8 +924,7 @@ static off_t restore_init(gzFile gzfd, struct savemeta_header *smh)
size_t rs;
char buf[256];
off_t startpos = 0;
- struct saved_metablock *svb;
- struct gfs2_meta_header *sbmh;
+ struct gfs2_meta_header sbmh;
err = read_header(gzfd, smh);
if (err < 0) {
@@ -943,14 +942,15 @@ static off_t restore_init(gzFile gzfd, struct savemeta_header *smh)
exit(1);
}
/* Scan for the beginning of the file body. Required to support old formats(?). */
- for (i = 0; i < (256 - sizeof(*svb) - sizeof(*sbmh)); i++) {
- svb = (struct saved_metablock *)&buf[i];
- sbmh = (struct gfs2_meta_header *)svb->buf;
- if (sbmh->mh_magic == cpu_to_be32(GFS2_MAGIC) &&
- sbmh->mh_type == cpu_to_be32(GFS2_METATYPE_SB))
+ for (i = 0; i < (256 - sizeof(struct saved_metablock) - sizeof(sbmh)); i++) {
+ off_t off = i + sizeof(struct saved_metablock);
+
+ memcpy(&sbmh, &buf[off], sizeof(sbmh));
+ if (sbmh.mh_magic == cpu_to_be32(GFS2_MAGIC) &&
+ sbmh.mh_type == cpu_to_be32(GFS2_METATYPE_SB))
break;
}
- if (i == (sizeof(buf) - sizeof(*svb) - sizeof(*sbmh)))
+ if (i == (sizeof(buf) - sizeof(struct saved_metablock) - sizeof(sbmh)))
i = 0;
return startpos + i; /* File offset of saved sb */
}
7 years, 3 months
gfs2-utils: master - gfs2_edit savemeta: Follow lf_next
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=b4333e41...
Commit: b4333e4109d082e666ec74f534ef4d55df6557dd
Parent: 056477066e819f716df86c342676797ebacb803e
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Mon Dec 12 22:25:01 2016 +0000
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Thu Jan 12 16:20:33 2017 +0000
gfs2_edit savemeta: Follow lf_next
Previously, gfs2_edit savemeta did not walk down the lf_next chain to
save the directory leaf blocks that might be there. Add a
save_leaf_chain() function that does that.
Related: rhbz#1382087
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/edit/savemeta.c | 41 ++++++++++++++++++++++++++++++++---------
1 files changed, 32 insertions(+), 9 deletions(-)
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index 9723dcd..c9b51e9 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -539,12 +539,41 @@ static void save_indirect_blocks(struct metafd *mfd, osi_list_t *cur_list,
} /* for all data on the indirect block */
}
+static int save_leaf_chain(struct metafd *mfd, struct gfs2_sbd *sdp, uint64_t blk)
+{
+ struct gfs2_buffer_head *bh;
+ struct gfs2_leaf leaf;
+
+ do {
+ if (gfs2_check_range(sdp, blk) != 0)
+ return 0;
+ bh = bread(sdp, blk);
+ if (bh == NULL) {
+ perror("Failed to read leaf block");
+ return 1;
+ }
+ warm_fuzzy_stuff(blk, FALSE);
+ if (gfs2_check_meta(bh, GFS2_METATYPE_LF) == 0) {
+ int ret = save_bh(mfd, bh, blk, NULL);
+ if (ret != 0) {
+ brelse(bh);
+ return ret;
+ }
+ }
+ gfs2_leaf_in(&leaf, bh);
+ brelse(bh);
+ blk = leaf.lf_next;
+ } while (leaf.lf_next != 0);
+
+ return 0;
+}
+
/*
* save_inode_data - save off important data associated with an inode
*
* mfd - destination file descriptor
* iblk - block number of the inode to save the data for
- *
+ *
* For user files, we don't want anything except all the indirect block
* pointers that reside on blocks on all but the highest height.
*
@@ -626,15 +655,9 @@ static void save_inode_data(struct metafd *mfd, uint64_t iblk)
(uint64_t)inode->i_di.di_num.no_addr);
exit(-1);
}
- if (leaf_no == old_leaf ||
- gfs2_check_range(&sbd, leaf_no) != 0)
- continue;
+ if (leaf_no != old_leaf && save_leaf_chain(mfd, &sbd, leaf_no) != 0)
+ exit(-1);
old_leaf = leaf_no;
- 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, NULL);
- brelse(mybh);
}
}
if (inode->i_di.di_eattr) { /* if this inode has extended attributes */
7 years, 3 months
gfs2-utils: master - gfs2_edit savemeta: Don't read rgrp blocks twice
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=05647706...
Commit: 056477066e819f716df86c342676797ebacb803e
Parent: 4e60fdf18f5ece9e439ae66fef966eec1f38812a
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Fri Feb 12 17:25:38 2016 +0000
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Thu Jan 12 16:20:33 2017 +0000
gfs2_edit savemeta: Don't read rgrp blocks twice
When savemeta iterates over the rgrps and saves the rgrp header blocks
it calls save_block which does a bread() for each block despite them
already being read in earlier. Instead, call save_bh() on the existing
rgrp buffers. This isn't likely to give a significant performance
improvement as the duplicate reads would be cache hits but it should
have a noticeable effect on very large file systems.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/edit/savemeta.c | 9 ++++-----
1 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index 3e8dae0..9723dcd 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -855,8 +855,8 @@ void savemeta(char *out_fn, int saveoption, int gziplevel)
}
/* Walk through the resource groups saving everything within */
for (n = osi_first(&sbd.rgtree); n; n = osi_next(n)) {
- uint64_t blk;
struct rgrp_tree *rgd;
+ unsigned i;
rgd = (struct rgrp_tree *)n;
if (gfs2_rgrp_read(&sbd, rgd))
@@ -866,10 +866,9 @@ void savemeta(char *out_fn, int saveoption, int gziplevel)
(unsigned long long)rgd->ri.ri_addr,
rgd->ri.ri_length);
/* Save off the rg and bitmaps */
- 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, NULL);
+ for (i = 0; i < rgd->ri.ri_length; i++) {
+ warm_fuzzy_stuff(rgd->ri.ri_addr + i, FALSE);
+ save_bh(&mfd, rgd->bits[i].bi_bh, 0, NULL);
}
/* Save off the other metadata: inodes, etc. if mode is not 'savergs' */
if (saveoption != 2) {
7 years, 3 months