gfs2-utils: master - mkfs.gfs2: print message about BKLDISCARD ioctl taking a long time
by Paul Evans
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=2ad04486...
Commit: 2ad0448631bdc37a82d6e7db4e48ea48b892716c
Parent: cbb17b94ce6aa3813f0544acd8e1f3c6f8d4f038
Author: Paul Evans <pevans(a)redhat.com>
AuthorDate: Thu Oct 15 16:40:25 2015 +0100
Committer: Paul Evans <pevans(a)redhat.com>
CommitterDate: Mon Oct 19 14:07:49 2015 +0100
mkfs.gfs2: print message about BKLDISCARD ioctl taking a long time
When running mkfs.gfs2 the BLKDISCARD ioctl() can sit waiting for a
long time without feedback.
Added a message in mkfs.gfs2 to the user just before the ioctl begins
to warn the user that the operation could take a while to complete.
Signed-off-by: Paul Evans <pevans(a)redhat.com>
---
gfs2/mkfs/main_mkfs.c | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c
index ab525d1..48345b5 100644
--- a/gfs2/mkfs/main_mkfs.c
+++ b/gfs2/mkfs/main_mkfs.c
@@ -923,9 +923,17 @@ int main(int argc, char *argv[])
if (opts.confirm && !opts.override)
are_you_sure();
- if (!S_ISREG(opts.dev.stat.st_mode) && opts.discard)
+ if (!S_ISREG(opts.dev.stat.st_mode) && opts.discard) {
+ if (!opts.quiet) {
+ printf("%s", _("Discarding device contents (may take a while on large devices): "));
+ fflush(stdout);
+ }
discard_blocks(opts.dev.fd, opts.dev.size, opts.debug);
+ if (!opts.quiet)
+ printf("%s", _("Done\n"));
+ }
+
error = place_rgrps(&sbd, rgs, &opts);
if (error) {
fprintf(stderr, _("Failed to build resource groups\n"));
8 years, 6 months
gfs2-utils: master - mkfs.gfs2: Add a progress indicator to mkfs.gfs2
by Paul Evans
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=cbb17b94...
Commit: cbb17b94ce6aa3813f0544acd8e1f3c6f8d4f038
Parent: cf30857d5cfc236f382b578d8820e1e0f72945b7
Author: Paul Evans <pevans(a)redhat.com>
AuthorDate: Thu Oct 15 17:27:27 2015 +0100
Committer: Paul Evans <pevans(a)redhat.com>
CommitterDate: Thu Oct 15 17:27:27 2015 +0100
mkfs.gfs2: Add a progress indicator to mkfs.gfs2
Add a progress indicator to mkfs based on an adapted version of
the simple progress indicator used in e2fsprogs.
Update mkfs.gfs2 to make use of this progress bar allowing progress
to be reported during the creation of journals and resource groups
during filesystem creation.
Signed-off-by: Paul Evans <pevans(a)redhat.com>
---
gfs2/mkfs/Makefile.am | 6 +++-
gfs2/mkfs/main_mkfs.c | 37 +++++++++++++++++--
gfs2/mkfs/progress.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++
gfs2/mkfs/progress.h | 14 +++++++
4 files changed, 148 insertions(+), 4 deletions(-)
diff --git a/gfs2/mkfs/Makefile.am b/gfs2/mkfs/Makefile.am
index 6c49d3b..074c4c1 100644
--- a/gfs2/mkfs/Makefile.am
+++ b/gfs2/mkfs/Makefile.am
@@ -16,7 +16,11 @@ noinst_HEADERS = \
gfs2_mkfs.h \
metafs.h
-mkfs_gfs2_SOURCES = main_mkfs.c
+mkfs_gfs2_SOURCES = \
+ main_mkfs.c \
+ progress.c \
+ progress.h
+
mkfs_gfs2_CPPFLAGS = $(COMMON_CPPFLAGS)
mkfs_gfs2_CFLAGS = $(blkid_CFLAGS)
mkfs_gfs2_LDFLAGS = $(blkid_LIBS)
diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c
index d3d8edf..ab525d1 100644
--- a/gfs2/mkfs/main_mkfs.c
+++ b/gfs2/mkfs/main_mkfs.c
@@ -28,6 +28,7 @@
#include <linux/types.h>
#include "libgfs2.h"
#include "gfs2_mkfs.h"
+#include "progress.h"
static void print_usage(const char *prog_name)
{
@@ -653,10 +654,14 @@ static int add_rgrp(lgfs2_rgrps_t rgs, uint64_t *addr, uint32_t len, lgfs2_rgrp_
static int place_journals(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts *opts, uint64_t *rgaddr)
{
+ struct gfs2_progress_bar progress;
uint64_t jfsize = lgfs2_space_for_data(sdp, sdp->bsize, opts->jsize << 20);
uint32_t rgsize = lgfs2_rgsize_for_data(jfsize, sdp->bsize);
unsigned j;
+ /* Initialise a progress bar for resource group creation. */
+ gfs2_progress_init(&progress, opts->journals, _("Adding journals: "), opts->quiet);
+
/* We'll build the jindex later so remember where we put the journals */
mkfs_journals = calloc(opts->journals, sizeof(*mkfs_journals));
if (mkfs_journals == NULL)
@@ -668,6 +673,9 @@ static int place_journals(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_o
lgfs2_rgrp_t rg;
struct gfs2_inode in = {0};
+ /* Update progress bar for journal creation. */
+ gfs2_progress_update(&progress, (j + 1));
+
if (opts->debug)
printf(_("Placing resource group for journal%u\n"), j);
@@ -715,21 +723,27 @@ static int place_journals(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_o
}
mkfs_journals[j] = in.i_di.di_num;
}
+ gfs2_progress_close(&progress, _("Done\n"));
return 0;
}
static int place_rgrps(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts *opts)
{
+ struct gfs2_progress_bar progress;
uint64_t rgaddr = lgfs2_rgrp_align_addr(rgs, sdp->sb_addr + 1);
uint32_t rgblks = ((opts->rgsize << 20) / sdp->bsize);
+ uint32_t rgnum;
int result;
result = place_journals(sdp, rgs, opts, &rgaddr);
if (result != 0)
return result;
- lgfs2_rgrps_plan(rgs, sdp->device.length - rgaddr, rgblks);
+ rgnum = lgfs2_rgrps_plan(rgs, sdp->device.length - rgaddr, rgblks);
+
+ /* Initialise a progress bar for resource group creation (after journal creation). */
+ gfs2_progress_init(&progress, (rgnum + opts->journals), _("Building resource groups: "), opts->quiet);
while (1) {
lgfs2_rgrp_t rg;
@@ -744,7 +758,12 @@ static int place_rgrps(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts
fprintf(stderr, _("Failed to build resource groups\n"));
return result;
}
+
+ /* Update progress bar with resource group address. */
+ gfs2_progress_update(&progress, (sdp->rgrps));
}
+ gfs2_progress_close(&progress, _("Done\n"));
+
return 0;
}
@@ -949,11 +968,17 @@ int main(int argc, char *argv[])
fprintf(stderr, _("Error building '%s': %s\n"), "rindex", strerror(errno));
exit(EXIT_FAILURE);
}
+ if (!opts.quiet) {
+ printf("%s", _("Creating quota file: "));
+ fflush(stdout);
+ }
error = build_quota(&sbd);
if (error) {
fprintf(stderr, _("Error building '%s': %s\n"), "quota", strerror(errno));
exit(EXIT_FAILURE);
}
+ if (!opts.quiet)
+ printf("%s", _("Done\n"));
build_root(&sbd);
sb.sb_root_dir = sbd.md.rooti->i_di.di_num;
@@ -973,6 +998,11 @@ int main(int argc, char *argv[])
lgfs2_rgrps_free(&rgs);
+ if (!opts.quiet) {
+ printf("%s", _("Writing superblock and syncing: "));
+ fflush(stdout);
+ }
+
error = lgfs2_sb_write(&sb, opts.dev.fd, sbd.bsize);
if (error) {
perror(_("Failed to write superblock\n"));
@@ -991,8 +1021,9 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
- if (!opts.quiet)
+ if (!opts.quiet) {
+ printf("%s", _("Done\n"));
print_results(&sb, &opts, sbd.rgrps, sbd.fssize);
-
+ }
return 0;
}
diff --git a/gfs2/mkfs/progress.c b/gfs2/mkfs/progress.c
new file mode 100644
index 0000000..538ee71
--- /dev/null
+++ b/gfs2/mkfs/progress.c
@@ -0,0 +1,95 @@
+/**
+ * Progress bar to give updates for operations in gfs2-utils.
+ * Adapted from the simple progress bar in e2fsprogs progress.c
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "progress.h"
+
+static char spaces[44], backspaces[44];
+static time_t last_update;
+
+static int number_of_digits(int value)
+{
+ int digits = 0;
+
+ do {
+ value /= 10;
+ digits++;
+ } while (value != 0);
+
+ return digits;
+}
+
+void gfs2_progress_init(struct gfs2_progress_bar *progress, uint64_t max, const char *message, int quiet)
+{
+ /**
+ * NOTE:
+ *
+ * Default operation is to output the progress indication
+ * in full. Although we will honor the quiet flag in the
+ * application, if this is set we skip progress bar any
+ * update operations and output.
+ *
+ */
+
+ memset(spaces, ' ', sizeof(spaces)-1);
+ spaces[sizeof(spaces)-1] = 0;
+
+ memset(backspaces, '\b', sizeof(backspaces)-1);
+ backspaces[sizeof(backspaces)-1] = 0;
+
+ memset(progress, 0, sizeof(*progress));
+
+ if (quiet) {
+ progress->skip_progress++;
+ return;
+ }
+
+ progress->max = max;
+ progress->max_digits = number_of_digits(max);
+
+ if (message) {
+ fputs(message, stdout);
+ fflush(stdout);
+ }
+ last_update = 0;
+}
+
+extern void gfs2_progress_update(struct gfs2_progress_bar *progress, uint64_t value)
+{
+ time_t current_time;
+
+ if (progress->skip_progress || (!isatty(STDOUT_FILENO)))
+ return;
+
+ current_time = time(0);
+ if (current_time == last_update)
+ return;
+ last_update = current_time;
+
+ printf("[%*"PRIu64"/%*"PRIu64"]", progress->max_digits, value,
+ progress->max_digits, progress->max);
+ fflush(stdout);
+ fprintf(stdout, "%.*s", (2 * progress->max_digits) + 3, backspaces);
+}
+
+extern void gfs2_progress_close(struct gfs2_progress_bar *progress, const char *message)
+{
+ if (progress->skip_progress)
+ return;
+
+ if (isatty(STDOUT_FILENO)) {
+ fprintf(stdout, "%.*s", (2 * progress->max_digits) + 3, spaces);
+ fprintf(stdout, "%.*s", (2 * progress->max_digits) + 3, backspaces);
+ }
+
+ if (message)
+ fputs(message, stdout);
+}
diff --git a/gfs2/mkfs/progress.h b/gfs2/mkfs/progress.h
new file mode 100644
index 0000000..545bf58
--- /dev/null
+++ b/gfs2/mkfs/progress.h
@@ -0,0 +1,14 @@
+#ifndef PROGRESS_H
+#define PROGRESS_H
+
+struct gfs2_progress_bar {
+ uint64_t max;
+ int max_digits;
+ int skip_progress;
+};
+
+extern void gfs2_progress_init(struct gfs2_progress_bar *progress, uint64_t max, const char *message, int quiet);
+extern void gfs2_progress_update(struct gfs2_progress_bar *progress, uint64_t value);
+extern void gfs2_progress_close(struct gfs2_progress_bar *progress, const char *message);
+
+#endif /* PROGRESS_H */
8 years, 6 months
gfs2-utils: master - libgfs2: Return the rgrp count in lgfs2_rgrps_plan()
by Andrew Price
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=cf30857d...
Commit: cf30857d5cfc236f382b578d8820e1e0f72945b7
Parent: 0d899f6e8d0301b7fb017d374b3b7bf61b53260e
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Mon Oct 12 15:43:03 2015 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Tue Oct 13 13:24:55 2015 +0100
libgfs2: Return the rgrp count in lgfs2_rgrps_plan()
lgfs2_rgrps_plan() previously returned one of the rgrp sizes
specifically so that gfs2_grow could check it. This check was also done
inside the function so the return value would always be 0 when the rgrp
size was too small anyway (really this means that there's not enough
space in which to place sensibly sized rgrps). As returning 0 is
sufficient to pass back the same information, we can return the resource
group count from lgfs2_rgrps_plan() instead, as that is a more useful
value in general.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/libgfs2/rgrp.c | 7 +++----
gfs2/mkfs/main_grow.c | 8 +++-----
2 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/gfs2/libgfs2/rgrp.c b/gfs2/libgfs2/rgrp.c
index 2a55523..c20aa1f 100644
--- a/gfs2/libgfs2/rgrp.c
+++ b/gfs2/libgfs2/rgrp.c
@@ -302,8 +302,8 @@ uint32_t lgfs2_rgrp_align_len(const lgfs2_rgrps_t rgs, uint32_t len)
* rgs: The resource groups descriptor
* space: The number of remaining blocks to be allocated
* tgtsize: The target resource group size in blocks
- * Returns the larger of the calculated resource group sizes, in blocks, or 0
- * if the smaller would be less than GFS2_MIN_RGSIZE.
+ * Returns the number of resource groups planned to fit in the given space, or
+ * 0 if the smallest resource group would be smaller than GFS2_MIN_RGSIZE.
*/
uint32_t lgfs2_rgrps_plan(const lgfs2_rgrps_t rgs, uint64_t space, uint32_t tgtsize)
{
@@ -352,11 +352,10 @@ uint32_t lgfs2_rgrps_plan(const lgfs2_rgrps_t rgs, uint64_t space, uint32_t tgts
/* Once we've reached this point,
(plan[0].num * plan[0].len) + (plan[1].num * plan[1].len)
will be less than one adjustment smaller than 'space'. */
-
if (rgs->plan[0].len < minlen)
return 0;
- return rgs->plan[0].len;
+ return rgs->plan[0].num + rgs->plan[1].num;
}
/**
diff --git a/gfs2/mkfs/main_grow.c b/gfs2/mkfs/main_grow.c
index 860c319..173466c 100644
--- a/gfs2/mkfs/main_grow.c
+++ b/gfs2/mkfs/main_grow.c
@@ -32,7 +32,6 @@
static uint64_t override_device_size = 0;
static int test = 0;
static uint64_t fssize = 0, fsgrowth;
-static unsigned int rgsize = 0;
int print_level = MSG_NOTICE;
extern int create_new_inode(struct gfs2_sbd *sdp);
@@ -315,7 +314,6 @@ static void print_info(struct gfs2_sbd *sdp, char *device, char *mnt_path)
log_notice("FS: %-25s%s\n", _("Device:"), device);
log_notice("FS: %-25s%llu (0x%llx)\n", _("Size:"),
(unsigned long long)fssize, (unsigned long long)fssize);
- log_notice("FS: %-25s%u (0x%x)\n", _("New resource group size:"), rgsize, rgsize);
log_notice("DEV: %-24s%llu (0x%llx)\n", _("Length:"),
(unsigned long long)sdp->device.length,
(unsigned long long)sdp->device.length);
@@ -359,7 +357,7 @@ int main(int argc, char *argv[])
sdp->qcsize = GFS2_DEFAULT_QCSIZE;
sdp->md.journals = 1;
decode_arguments(argc, argv, sdp);
-
+
for(; (argc - optind) > 0; optind++) {
struct metafs mfs = {0};
struct mntent *mnt;
@@ -444,8 +442,8 @@ int main(int argc, char *argv[])
goto out;
}
fsgrowth = (sdp->device.length - fssize);
- rgsize = lgfs2_rgrps_plan(rgs, fsgrowth, ((GFS2_MAX_RGSIZE << 20) / sdp->bsize));
- if (rgsize < ((GFS2_MIN_RGSIZE << 20) / sdp->bsize)) {
+ rgcount = lgfs2_rgrps_plan(rgs, fsgrowth, ((GFS2_MAX_RGSIZE << 20) / sdp->bsize));
+ if (rgcount == 0) {
log_err( _("The calculated resource group size is too small.\n"));
log_err( _("%s has not grown.\n"), argv[optind]);
error = -1;
8 years, 6 months
cluster: RHEL6 - fsck.gfs2: Detect, fix and clone duplicate block refs within a dinode
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=870ba3e84c9...
Commit: 870ba3e84c99dfa1b36a35ca22dcc37d41b3f501
Parent: e375d00ed561ce3977b9975fa6cdcae72007e382
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Jun 29 10:53:52 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Oct 9 10:42:43 2015 -0500
fsck.gfs2: Detect, fix and clone duplicate block refs within a dinode
Prior to this patch, fsck.gfs2 was unable to detect and fix duplicate
block references within the same file. This patch detects when data
blocks are duplicated within a dinode, then tries to clone the data
to a new block.
rhbz#1206149
---
gfs2/fsck/fs_recovery.c | 3 +-
gfs2/fsck/fsck.h | 2 +
gfs2/fsck/metawalk.c | 9 ++-
gfs2/fsck/metawalk.h | 6 ++-
gfs2/fsck/pass1.c | 15 ++++--
gfs2/fsck/pass1b.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++-
gfs2/fsck/pass2.c | 3 +-
gfs2/fsck/util.c | 7 ++-
8 files changed, 146 insertions(+), 16 deletions(-)
diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c
index 2e902ea..883ddeb 100644
--- a/gfs2/fsck/fs_recovery.c
+++ b/gfs2/fsck/fs_recovery.c
@@ -605,7 +605,8 @@ static int rangecheck_jmeta(struct gfs2_inode *ip, uint64_t block,
}
static int rangecheck_jdata(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
return rangecheck_jblock(ip, block);
}
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index 5f15894..5a5cd19 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -52,6 +52,8 @@ struct dir_status {
};
#define DUPFLAG_REF1_FOUND 1 /* Has the original reference been found? */
+#define DUPFLAG_REF1_IS_DUPL 2 /* The original reference is also where we
+ determined there was a duplicate. */
struct duptree {
struct osi_node node;
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 959b905..191c4f3 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1354,7 +1354,8 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
would defeat the rangecheck_block related functions in
pass1. Therefore the individual check_data functions
should do a range check. */
- rc = pass->check_data(ip, metablock, block, pass->private);
+ rc = pass->check_data(ip, metablock, block, pass->private,
+ bh, ptr);
if (!error && rc) {
error = rc;
log_info("\n");
@@ -1664,7 +1665,8 @@ int delete_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
}
int delete_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private, struct gfs2_buffer_head *bh,
+ uint64_t *ptr)
{
return delete_block_if_notdup(ip, block, NULL, _("data"), NULL,
private);
@@ -1791,7 +1793,8 @@ static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
}
static int alloc_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
uint8_t q;
const char *desc = (const char *)private;
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 5e30bfe..b3224ba 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -28,7 +28,8 @@ extern int delete_metadata(struct gfs2_inode *ip, uint64_t block,
int *was_duplicate, void *private);
extern int delete_leaf(struct gfs2_inode *ip, uint64_t block, void *private);
extern int delete_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private);
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr);
extern int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
struct gfs2_buffer_head **bh, void *private);
extern int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
@@ -117,7 +118,8 @@ struct metawalk_fxns {
int *is_valid, int *was_duplicate,
void *private);
int (*check_data) (struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private);
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr);
int (*check_eattr_indir) (struct gfs2_inode *ip, uint64_t block,
uint64_t parent,
struct gfs2_buffer_head **bh, void *private);
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 4d31cff..6717436 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -41,7 +41,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
int h, void *private);
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private);
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr);
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
void *private);
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
@@ -69,7 +70,8 @@ static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
void *private);
static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private);
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr);
static int invalidate_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent,
struct gfs2_buffer_head **bh,
@@ -433,7 +435,8 @@ out:
}
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bbh, uint64_t *ptr)
{
uint8_t q;
struct block_count *bc = (struct block_count *) private;
@@ -937,7 +940,8 @@ static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
}
static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
return mark_block_invalid(ip, block, ref_as_data, _("data"),
NULL, NULL);
@@ -1032,7 +1036,8 @@ static int rangecheck_leaf(struct gfs2_inode *ip, uint64_t block,
}
static int rangecheck_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
return rangecheck_block(ip, block, NULL, btype_data, private);
}
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 401ee80..28f0dd3 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -25,6 +25,11 @@ struct dup_handler {
int ref_count;
};
+struct clone_target {
+ uint64_t dup_block;
+ int first;
+};
+
static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval)
{
char reftypestring[32];
@@ -247,6 +252,112 @@ static void revise_dup_handler(uint64_t dup_blk, struct dup_handler *dh)
}
}
+static int clone_check_meta(struct gfs2_inode *ip, uint64_t block,
+ struct gfs2_buffer_head **bh, int h,
+ int *is_valid, int *was_duplicate, void *private)
+{
+ *was_duplicate = 0;
+ *is_valid = 1;
+ *bh = bread(ip->i_sbd, block);
+ return 0;
+}
+
+/* clone_data - clone a duplicate reference
+ *
+ * This function remembers the first reference to the specified block, and
+ * clones all subsequent references to it (with permission).
+ */
+static int clone_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
+{
+ struct clone_target *clonet = (struct clone_target *)private;
+ struct gfs2_buffer_head *clone_bh;
+ uint64_t cloneblock;
+
+ if (block != clonet->dup_block)
+ return 0;
+
+ if (clonet->first) {
+ log_debug(_("Inode %lld (0x%llx)'s first reference to "
+ "block %lld (0x%llx) is targeted for cloning.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)block,
+ (unsigned long long)block);
+ clonet->first = 0;
+ return 0;
+ }
+ log_err(_("Error: Inode %lld (0x%llx)'s subsequent reference to "
+ "block %lld (0x%llx) is an error.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)block, (unsigned long long)block);
+ if (query( _("Okay to clone the duplicated reference? (y/n) "))) {
+ cloneblock = meta_alloc(ip);
+ clone_bh = bread(ip->i_sbd, clonet->dup_block);
+ if (clone_bh) {
+ fsck_blockmap_set(ip, cloneblock, _("data"),
+ GFS2_BLKST_USED);
+ clone_bh->b_blocknr = cloneblock;
+ bmodified(clone_bh);
+ brelse(clone_bh);
+ /* Now fix the reference: */
+ *ptr = cpu_to_be64(cloneblock);
+ bmodified(bh);
+ log_err(_("Duplicate reference to block %lld (0x%llx) "
+ "was cloned to block %lld (0x%llx).\n"),
+ (unsigned long long)block,
+ (unsigned long long)block,
+ (unsigned long long)cloneblock,
+ (unsigned long long)cloneblock);
+ return 0;
+ }
+ log_err(_("Error: Unable to allocate a new data block.\n"));
+ if (!query("Should I zero the reference instead? (y/n)")) {
+ log_err(_("Duplicate reference to block %lld "
+ "(0x%llx) was not fixed.\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ return 0;
+ }
+ *ptr = 0;
+ bmodified(bh);
+ log_err(_("Duplicate reference to block %lld (0x%llx) was "
+ "zeroed.\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ } else {
+ log_err(_("Duplicate reference to block %lld (0x%llx) "
+ "was not fixed.\n"), (unsigned long long)block,
+ (unsigned long long)block);
+ }
+ return 0;
+}
+
+/* clone_dup_ref_in_inode - clone a duplicate reference within a single inode
+ *
+ * This function traverses the metadata tree of an inode, cloning all
+ * but the first reference to a duplicate block reference.
+ */
+static void clone_dup_ref_in_inode(struct gfs2_inode *ip, struct duptree *dt)
+{
+ int error;
+ struct clone_target clonet = {.dup_block = dt->block, .first = 1};
+ struct metawalk_fxns pass1b_fxns_clone = {
+ .private = &clonet,
+ .check_metalist = clone_check_meta,
+ .check_data = clone_data,
+ };
+
+ error = check_metatree(ip, &pass1b_fxns_clone);
+ if (error) {
+ log_err(_("Error cloning duplicate reference(s) to block %lld "
+ "(0x%llx).\n"), (unsigned long long)dt->block,
+ (unsigned long long)dt->block);
+ }
+}
+
/* handle_dup_blk - handle a duplicate block reference.
*
* This function should resolve and delete the duplicate block reference given,
@@ -387,6 +498,9 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt)
(unsigned long long)id->block_no);
ip = fsck_load_inode(sdp, id->block_no);
+ if (dt->dup_flags & DUPFLAG_REF1_IS_DUPL)
+ clone_dup_ref_in_inode(ip, dt);
+
q = block_type(id->block_no);
if (q == gfs2_inode_invalid) {
log_debug( _("The remaining reference inode %lld "
@@ -462,7 +576,8 @@ static int check_metalist_refs(struct gfs2_inode *ip, uint64_t block,
}
static int check_data_refs(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bh, uint64_t *ptr)
{
return add_duplicate_ref(ip, block, ref_as_data, 1, INODE_VALID);
}
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index dd030ce..63fe6a6 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -1605,7 +1605,8 @@ static int check_metalist_qc(struct gfs2_inode *ip, uint64_t block,
}
static int check_data_qc(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
+ uint64_t block, void *private,
+ struct gfs2_buffer_head *bbh, uint64_t *ptr)
{
struct gfs2_buffer_head *bh;
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 6039fe3..250ce3d 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -258,15 +258,16 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
resolve it. The first reference can't be the second reference. */
if (id && first && !(dt->dup_flags & DUPFLAG_REF1_FOUND)) {
log_info(_("Original reference to block %llu (0x%llx) was "
- "previously found to be bad and deleted.\n"),
+ "either found to be bad and deleted, or else "
+ "a duplicate within the same inode.\n"),
(unsigned long long)block,
(unsigned long long)block);
log_info(_("I'll consider the reference from inode %llu "
"(0x%llx) the first reference.\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- dt->dup_flags |= DUPFLAG_REF1_FOUND;
- return meta_is_good;
+ dt->dup_flags |= DUPFLAG_REF1_IS_DUPL;
+ dt->refs++;
}
/* The first time this is called from pass1 is actually the second
8 years, 6 months
cluster: RHEL6 - fsck.gfs2: Change duptree structure to have generic flags
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=e375d00ed56...
Commit: e375d00ed561ce3977b9975fa6cdcae72007e382
Parent: 06116f1663094f0dfad88e9285ebd86d13f46248
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jun 26 12:18:59 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Thu Oct 8 09:46:08 2015 -0500
fsck.gfs2: Change duptree structure to have generic flags
This patch does not change any functionality. It merely changes the
specialized first_ref_found flag to a flag within a multi-flag var.
rhbz#1206149
---
gfs2/fsck/fsck.h | 4 +++-
gfs2/fsck/util.c | 9 ++++-----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index ddabf79..5f15894 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -51,9 +51,11 @@ struct dir_status {
uint32_t entry_count;
};
+#define DUPFLAG_REF1_FOUND 1 /* Has the original reference been found? */
+
struct duptree {
struct osi_node node;
- int first_ref_found; /* Has the original reference been found? */
+ int dup_flags;
int refs;
uint64_t block;
osi_list_t ref_inode_list; /* list of inodes referencing a dup block */
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 05989fe..6039fe3 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -180,7 +180,6 @@ static struct duptree *gfs2_dup_set(uint64_t dblock, int create)
dt->block = dblock;
dt->refs = 1; /* reference 1 is actually the reference we need to
discover in pass1b. */
- dt->first_ref_found = 0;
osi_list_init(&dt->ref_inode_list);
osi_list_init(&dt->ref_invinode_list);
osi_link_node(&dt->node, parent, newn);
@@ -245,7 +244,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
/* If we found the duplicate reference but we've already discovered
the first reference (in pass1b) and the other references in pass1,
we don't need to count it, so just return. */
- if (dt->first_ref_found)
+ if (dt->dup_flags & DUPFLAG_REF1_FOUND)
return meta_is_good;
/* Check for a previous reference to this duplicate */
@@ -257,7 +256,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
that case, we don't want to be confused and consider this second
reference the same as the first. If we do, we'll never be able to
resolve it. The first reference can't be the second reference. */
- if (id && first && !dt->first_ref_found) {
+ if (id && first && !(dt->dup_flags & DUPFLAG_REF1_FOUND)) {
log_info(_("Original reference to block %llu (0x%llx) was "
"previously found to be bad and deleted.\n"),
(unsigned long long)block,
@@ -266,7 +265,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
"(0x%llx) the first reference.\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- dt->first_ref_found = 1;
+ dt->dup_flags |= DUPFLAG_REF1_FOUND;
return meta_is_good;
}
@@ -275,7 +274,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
reference, we don't want to increment the reference count because
it's already accounted for. */
if (first) {
- dt->first_ref_found = 1;
+ dt->dup_flags |= DUPFLAG_REF1_FOUND;
dups_found_first++; /* We found another first ref. */
} else {
dt->refs++;
8 years, 6 months