aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2018-02-02 09:32:45 -0600
committerEric Sandeen <sandeen@redhat.com>2018-02-02 09:32:45 -0600
commitbc94c5d69e14bbe6e2b4fd74e2ef8b2ef66ccedc (patch)
treeda4129cf5b4e2adc6875abf98067248e1e548767
parent372d4ba99155b2432dee293431f15b0df2f9e4b0 (diff)
downloadxfsprogs-dev-bc94c5d69e14bbe6e2b4fd74e2ef8b2ef66ccedc.tar.gz
xfs_scrub: add space map iteration functions
These helpers enable userspace to iterate all the space map information in a filesystem. The iteration function uses GETFSMAP. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Eric Sandeen <sandeen@redhat.com> Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
-rw-r--r--scrub/Makefile2
-rw-r--r--scrub/spacemap.c256
-rw-r--r--scrub/spacemap.h31
3 files changed, 289 insertions, 0 deletions
diff --git a/scrub/Makefile b/scrub/Makefile
index 4d1c908202..24e0c449f7 100644
--- a/scrub/Makefile
+++ b/scrub/Makefile
@@ -19,6 +19,7 @@ HFILES = \
common.h \
disk.h \
inodes.h \
+spacemap.h \
xfs_scrub.h
CFILES = \
@@ -26,6 +27,7 @@ common.c \
disk.c \
inodes.c \
phase1.c \
+spacemap.c \
xfs_scrub.c
LLDLIBS += $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD)
diff --git a/scrub/spacemap.c b/scrub/spacemap.c
new file mode 100644
index 0000000000..2dc6e2b884
--- /dev/null
+++ b/scrub/spacemap.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 Oracle. All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/statvfs.h>
+#include "workqueue.h"
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "path.h"
+#include "xfs_scrub.h"
+#include "common.h"
+#include "spacemap.h"
+
+/*
+ * Filesystem space map iterators.
+ *
+ * Logically, we call GETFSMAP to fetch a set of space map records and
+ * call a function to iterate over the records. However, that's not
+ * what actually happens -- the work is split into separate items, with
+ * each AG, the realtime device, and the log device getting their own
+ * work items. For an XFS with a realtime device and an external log,
+ * this means that we can have up to ($agcount + 2) threads running at
+ * once.
+ *
+ * This comes into play if we want to have per-workitem memory. Maybe.
+ * XXX: do we really need all that ?
+ */
+
+#define FSMAP_NR 65536
+
+/* Iterate all the fs block mappings between the two keys. */
+bool
+xfs_iterate_fsmap(
+ struct scrub_ctx *ctx,
+ const char *descr,
+ struct fsmap *keys,
+ xfs_fsmap_iter_fn fn,
+ void *arg)
+{
+ struct fsmap_head *head;
+ struct fsmap *p;
+ bool moveon = true;
+ int i;
+ int error;
+
+ head = malloc(fsmap_sizeof(FSMAP_NR));
+ if (!head) {
+ str_errno(ctx, descr);
+ return false;
+ }
+
+ memset(head, 0, sizeof(*head));
+ memcpy(head->fmh_keys, keys, sizeof(struct fsmap) * 2);
+ head->fmh_count = FSMAP_NR;
+
+ while ((error = ioctl(ctx->mnt_fd, FS_IOC_GETFSMAP, head)) == 0) {
+ for (i = 0, p = head->fmh_recs;
+ i < head->fmh_entries;
+ i++, p++) {
+ moveon = fn(ctx, descr, p, arg);
+ if (!moveon)
+ goto out;
+ if (xfs_scrub_excessive_errors(ctx)) {
+ moveon = false;
+ goto out;
+ }
+ }
+
+ if (head->fmh_entries == 0)
+ break;
+ p = &head->fmh_recs[head->fmh_entries - 1];
+ if (p->fmr_flags & FMR_OF_LAST)
+ break;
+ fsmap_advance(head);
+ }
+
+ if (error) {
+ str_errno(ctx, descr);
+ moveon = false;
+ }
+out:
+ free(head);
+ return moveon;
+}
+
+/* GETFSMAP wrappers routines. */
+struct xfs_scan_blocks {
+ xfs_fsmap_iter_fn fn;
+ void *arg;
+ bool moveon;
+};
+
+/* Iterate all the reverse mappings of an AG. */
+static void
+xfs_scan_ag_blocks(
+ struct workqueue *wq,
+ xfs_agnumber_t agno,
+ void *arg)
+{
+ struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
+ struct xfs_scan_blocks *sbx = arg;
+ char descr[DESCR_BUFSZ];
+ struct fsmap keys[2];
+ off64_t bperag;
+ bool moveon;
+
+ bperag = (off64_t)ctx->geo.agblocks *
+ (off64_t)ctx->geo.blocksize;
+
+ snprintf(descr, DESCR_BUFSZ, _("dev %d:%d AG %u fsmap"),
+ major(ctx->fsinfo.fs_datadev),
+ minor(ctx->fsinfo.fs_datadev),
+ agno);
+
+ memset(keys, 0, sizeof(struct fsmap) * 2);
+ keys->fmr_device = ctx->fsinfo.fs_datadev;
+ keys->fmr_physical = agno * bperag;
+ (keys + 1)->fmr_device = ctx->fsinfo.fs_datadev;
+ (keys + 1)->fmr_physical = ((agno + 1) * bperag) - 1;
+ (keys + 1)->fmr_owner = ULLONG_MAX;
+ (keys + 1)->fmr_offset = ULLONG_MAX;
+ (keys + 1)->fmr_flags = UINT_MAX;
+
+ moveon = xfs_iterate_fsmap(ctx, descr, keys, sbx->fn, sbx->arg);
+ if (!moveon)
+ sbx->moveon = false;
+}
+
+/* Iterate all the reverse mappings of a standalone device. */
+static void
+xfs_scan_dev_blocks(
+ struct scrub_ctx *ctx,
+ int idx,
+ dev_t dev,
+ struct xfs_scan_blocks *sbx)
+{
+ struct fsmap keys[2];
+ char descr[DESCR_BUFSZ];
+ bool moveon;
+
+ snprintf(descr, DESCR_BUFSZ, _("dev %d:%d fsmap"),
+ major(dev), minor(dev));
+
+ memset(keys, 0, sizeof(struct fsmap) * 2);
+ keys->fmr_device = dev;
+ (keys + 1)->fmr_device = dev;
+ (keys + 1)->fmr_physical = ULLONG_MAX;
+ (keys + 1)->fmr_owner = ULLONG_MAX;
+ (keys + 1)->fmr_offset = ULLONG_MAX;
+ (keys + 1)->fmr_flags = UINT_MAX;
+
+ moveon = xfs_iterate_fsmap(ctx, descr, keys, sbx->fn, sbx->arg);
+ if (!moveon)
+ sbx->moveon = false;
+}
+
+/* Iterate all the reverse mappings of the realtime device. */
+static void
+xfs_scan_rt_blocks(
+ struct workqueue *wq,
+ xfs_agnumber_t agno,
+ void *arg)
+{
+ struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
+
+ xfs_scan_dev_blocks(ctx, agno, ctx->fsinfo.fs_rtdev, arg);
+}
+
+/* Iterate all the reverse mappings of the log device. */
+static void
+xfs_scan_log_blocks(
+ struct workqueue *wq,
+ xfs_agnumber_t agno,
+ void *arg)
+{
+ struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
+
+ xfs_scan_dev_blocks(ctx, agno, ctx->fsinfo.fs_logdev, arg);
+}
+
+/* Scan all the blocks in a filesystem. */
+bool
+xfs_scan_all_spacemaps(
+ struct scrub_ctx *ctx,
+ xfs_fsmap_iter_fn fn,
+ void *arg)
+{
+ struct workqueue wq;
+ struct xfs_scan_blocks sbx;
+ xfs_agnumber_t agno;
+ int ret;
+
+ sbx.moveon = true;
+ sbx.fn = fn;
+ sbx.arg = arg;
+
+ ret = workqueue_create(&wq, (struct xfs_mount *)ctx,
+ scrub_nproc_workqueue(ctx));
+ if (ret) {
+ str_error(ctx, ctx->mntpoint, _("Could not create workqueue."));
+ return false;
+ }
+ if (ctx->fsinfo.fs_rt) {
+ ret = workqueue_add(&wq, xfs_scan_rt_blocks,
+ ctx->geo.agcount + 1, &sbx);
+ if (ret) {
+ sbx.moveon = false;
+ str_error(ctx, ctx->mntpoint,
+_("Could not queue rtdev fsmap work."));
+ goto out;
+ }
+ }
+ if (ctx->fsinfo.fs_log) {
+ ret = workqueue_add(&wq, xfs_scan_log_blocks,
+ ctx->geo.agcount + 2, &sbx);
+ if (ret) {
+ sbx.moveon = false;
+ str_error(ctx, ctx->mntpoint,
+_("Could not queue logdev fsmap work."));
+ goto out;
+ }
+ }
+ for (agno = 0; agno < ctx->geo.agcount; agno++) {
+ ret = workqueue_add(&wq, xfs_scan_ag_blocks, agno, &sbx);
+ if (ret) {
+ sbx.moveon = false;
+ str_error(ctx, ctx->mntpoint,
+_("Could not queue AG %u fsmap work."), agno);
+ break;
+ }
+ }
+out:
+ workqueue_destroy(&wq);
+
+ return sbx.moveon;
+}
diff --git a/scrub/spacemap.h b/scrub/spacemap.h
new file mode 100644
index 0000000000..9ee46f7885
--- /dev/null
+++ b/scrub/spacemap.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 Oracle. All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef XFS_SCRUB_SPACEMAP_H_
+#define XFS_SCRUB_SPACEMAP_H_
+
+typedef bool (*xfs_fsmap_iter_fn)(struct scrub_ctx *ctx, const char *descr,
+ struct fsmap *fsr, void *arg);
+
+bool xfs_iterate_fsmap(struct scrub_ctx *ctx, const char *descr,
+ struct fsmap *keys, xfs_fsmap_iter_fn fn, void *arg);
+bool xfs_scan_all_spacemaps(struct scrub_ctx *ctx, xfs_fsmap_iter_fn fn,
+ void *arg);
+
+#endif /* XFS_SCRUB_SPACEMAP_H_ */