#include "list.h"
#include "libfrog/paths.h"
#include "libfrog/workqueue.h"
+#include "libfrog/fsgeom.h"
+#include "libfrog/scrub.h"
#include "xfs_scrub.h"
#include "common.h"
#include "scrub.h"
/* Phase 2: Check internal metadata. */
+struct scan_ctl {
+ /*
+ * Control mechanism to signal that the rt bitmap file scan is done and
+ * wake up any waiters.
+ */
+ pthread_cond_t rbm_wait;
+ pthread_mutex_t rbm_waitlock;
+ bool rbm_done;
+
+ bool aborted;
+};
+
/* Scrub each AG's metadata btrees. */
static void
scan_ag_metadata(
void *arg)
{
struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
- bool *aborted = arg;
+ struct scan_ctl *sctl = arg;
struct action_list alist;
struct action_list immediate_alist;
unsigned long long broken_primaries;
char descr[DESCR_BUFSZ];
int ret;
- if (*aborted)
+ if (sctl->aborted)
return;
action_list_init(&alist);
action_list_defer(ctx, agno, &alist);
return;
err:
- *aborted = true;
+ sctl->aborted = true;
}
-/* Scrub whole-FS metadata btrees. */
+/* Scan whole-fs metadata. */
static void
scan_fs_metadata(
- struct workqueue *wq,
- xfs_agnumber_t agno,
- void *arg)
+ struct workqueue *wq,
+ xfs_agnumber_t type,
+ void *arg)
{
- struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
- bool *aborted = arg;
- struct action_list alist;
- int ret;
+ struct action_list alist;
+ struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
+ struct scan_ctl *sctl = arg;
+ int ret;
- if (*aborted)
- return;
+ if (sctl->aborted)
+ goto out;
action_list_init(&alist);
- ret = scrub_fs_metadata(ctx, &alist);
+ ret = scrub_fs_metadata(ctx, type, &alist);
if (ret) {
- *aborted = true;
- return;
+ sctl->aborted = true;
+ goto out;
}
- action_list_defer(ctx, agno, &alist);
+ action_list_defer(ctx, 0, &alist);
+
+out:
+ if (type == XFS_SCRUB_TYPE_RTBITMAP) {
+ pthread_mutex_lock(&sctl->rbm_waitlock);
+ sctl->rbm_done = true;
+ pthread_cond_broadcast(&sctl->rbm_wait);
+ pthread_mutex_unlock(&sctl->rbm_waitlock);
+ }
}
/* Scan all filesystem metadata. */
phase2_func(
struct scrub_ctx *ctx)
{
- struct action_list alist;
struct workqueue wq;
+ struct scan_ctl sctl = {
+ .aborted = false,
+ .rbm_done = false,
+ };
+ struct action_list alist;
+ const struct xfrog_scrub_descr *sc = xfrog_scrubbers;
xfs_agnumber_t agno;
- bool aborted = false;
+ unsigned int type;
int ret, ret2;
+ pthread_mutex_init(&sctl.rbm_waitlock, NULL);
+ pthread_cond_init(&sctl.rbm_wait, NULL);
+
ret = -workqueue_create(&wq, (struct xfs_mount *)ctx,
scrub_nproc_workqueue(ctx));
if (ret) {
str_liberror(ctx, ret, _("creating scrub workqueue"));
- return ret;
+ goto out_wait;
}
/*
action_list_init(&alist);
ret = scrub_primary_super(ctx, &alist);
if (ret)
- goto out;
+ goto out_wq;
ret = action_list_process_or_defer(ctx, 0, &alist);
if (ret)
- goto out;
+ goto out_wq;
- for (agno = 0; !aborted && agno < ctx->mnt.fsgeom.agcount; agno++) {
- ret = -workqueue_add(&wq, scan_ag_metadata, agno, &aborted);
+ /* Scan each AG in parallel. */
+ for (agno = 0;
+ agno < ctx->mnt.fsgeom.agcount && !sctl.aborted;
+ agno++) {
+ ret = -workqueue_add(&wq, scan_ag_metadata, agno, &sctl);
if (ret) {
str_liberror(ctx, ret, _("queueing per-AG scrub work"));
- goto out;
+ goto out_wq;
}
}
- if (aborted)
- goto out;
+ if (sctl.aborted)
+ goto out_wq;
- ret = -workqueue_add(&wq, scan_fs_metadata, 0, &aborted);
+ /*
+ * Scan all of the whole-fs metadata objects: realtime bitmap, realtime
+ * summary, and the three quota files. Each of the metadata files can
+ * be scanned in parallel except for the realtime summary file, which
+ * must run after the realtime bitmap has been scanned.
+ */
+ for (type = 0; type < XFS_SCRUB_TYPE_NR; type++, sc++) {
+ if (sc->group != XFROG_SCRUB_GROUP_FS)
+ continue;
+ if (type == XFS_SCRUB_TYPE_RTSUM)
+ continue;
+
+ ret = -workqueue_add(&wq, scan_fs_metadata, type, &sctl);
+ if (ret) {
+ str_liberror(ctx, ret,
+ _("queueing whole-fs scrub work"));
+ goto out_wq;
+ }
+ }
+
+ if (sctl.aborted)
+ goto out_wq;
+
+ /*
+ * Wait for the rt bitmap to finish scanning, then scan the rt summary
+ * since the summary can be regenerated completely from the bitmap.
+ */
+ pthread_mutex_lock(&sctl.rbm_waitlock);
+ while (!sctl.rbm_done)
+ pthread_cond_wait(&sctl.rbm_wait, &sctl.rbm_waitlock);
+ pthread_mutex_unlock(&sctl.rbm_waitlock);
+
+ if (sctl.aborted)
+ goto out_wq;
+
+ ret = -workqueue_add(&wq, scan_fs_metadata, XFS_SCRUB_TYPE_RTSUM, &sctl);
if (ret) {
- str_liberror(ctx, ret, _("queueing per-FS scrub work"));
- goto out;
+ str_liberror(ctx, ret, _("queueing rtsummary scrub work"));
+ goto out_wq;
}
-out:
+out_wq:
ret2 = -workqueue_terminate(&wq);
if (ret2) {
str_liberror(ctx, ret2, _("finishing scrub work"));
ret = ret2;
}
workqueue_destroy(&wq);
+out_wait:
+ pthread_cond_destroy(&sctl.rbm_wait);
+ pthread_mutex_destroy(&sctl.rbm_waitlock);
- if (!ret && aborted)
+ if (!ret && sctl.aborted)
ret = ECANCELED;
return ret;
}