522 lines
12 KiB
Diff
522 lines
12 KiB
Diff
From 45f667488e390bd9771163eddbcdc304798f32a5 Mon Sep 17 00:00:00 2001
|
|
From: Kent Overstreet <kent.overstreet@linux.dev>
|
|
Date: Wed, 6 Nov 2024 13:13:25 -0500
|
|
Subject: [PATCH 066/233] bcachefs: Move fsck ioctl code to fsck.c
|
|
Content-Type: text/plain; charset="utf-8"
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
chardev.c and fs-ioctl.c are not organized by subject; let's try to fix
|
|
this.
|
|
|
|
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
|
|
Signed-off-by: Alexander Miroshnichenko <alex@millerson.name>
|
|
---
|
|
fs/bcachefs/chardev.c | 219 +-----------------------------------------
|
|
fs/bcachefs/fsck.c | 218 +++++++++++++++++++++++++++++++++++++++++
|
|
fs/bcachefs/fsck.h | 3 +
|
|
3 files changed, 222 insertions(+), 218 deletions(-)
|
|
|
|
diff --git a/fs/bcachefs/chardev.c b/fs/bcachefs/chardev.c
|
|
index 2182b555c112..46e9e32105a9 100644
|
|
--- a/fs/bcachefs/chardev.c
|
|
+++ b/fs/bcachefs/chardev.c
|
|
@@ -6,11 +6,11 @@
|
|
#include "buckets.h"
|
|
#include "chardev.h"
|
|
#include "disk_accounting.h"
|
|
+#include "fsck.h"
|
|
#include "journal.h"
|
|
#include "move.h"
|
|
#include "recovery_passes.h"
|
|
#include "replicas.h"
|
|
-#include "super.h"
|
|
#include "super-io.h"
|
|
#include "thread_with_file.h"
|
|
|
|
@@ -127,130 +127,6 @@ static long bch2_ioctl_incremental(struct bch_ioctl_incremental __user *user_arg
|
|
}
|
|
#endif
|
|
|
|
-struct fsck_thread {
|
|
- struct thread_with_stdio thr;
|
|
- struct bch_fs *c;
|
|
- struct bch_opts opts;
|
|
-};
|
|
-
|
|
-static void bch2_fsck_thread_exit(struct thread_with_stdio *_thr)
|
|
-{
|
|
- struct fsck_thread *thr = container_of(_thr, struct fsck_thread, thr);
|
|
- kfree(thr);
|
|
-}
|
|
-
|
|
-static int bch2_fsck_offline_thread_fn(struct thread_with_stdio *stdio)
|
|
-{
|
|
- struct fsck_thread *thr = container_of(stdio, struct fsck_thread, thr);
|
|
- struct bch_fs *c = thr->c;
|
|
-
|
|
- int ret = PTR_ERR_OR_ZERO(c);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- ret = bch2_fs_start(thr->c);
|
|
- if (ret)
|
|
- goto err;
|
|
-
|
|
- if (test_bit(BCH_FS_errors_fixed, &c->flags)) {
|
|
- bch2_stdio_redirect_printf(&stdio->stdio, false, "%s: errors fixed\n", c->name);
|
|
- ret |= 1;
|
|
- }
|
|
- if (test_bit(BCH_FS_error, &c->flags)) {
|
|
- bch2_stdio_redirect_printf(&stdio->stdio, false, "%s: still has errors\n", c->name);
|
|
- ret |= 4;
|
|
- }
|
|
-err:
|
|
- bch2_fs_stop(c);
|
|
- return ret;
|
|
-}
|
|
-
|
|
-static const struct thread_with_stdio_ops bch2_offline_fsck_ops = {
|
|
- .exit = bch2_fsck_thread_exit,
|
|
- .fn = bch2_fsck_offline_thread_fn,
|
|
-};
|
|
-
|
|
-static long bch2_ioctl_fsck_offline(struct bch_ioctl_fsck_offline __user *user_arg)
|
|
-{
|
|
- struct bch_ioctl_fsck_offline arg;
|
|
- struct fsck_thread *thr = NULL;
|
|
- darray_str(devs) = {};
|
|
- long ret = 0;
|
|
-
|
|
- if (copy_from_user(&arg, user_arg, sizeof(arg)))
|
|
- return -EFAULT;
|
|
-
|
|
- if (arg.flags)
|
|
- return -EINVAL;
|
|
-
|
|
- if (!capable(CAP_SYS_ADMIN))
|
|
- return -EPERM;
|
|
-
|
|
- for (size_t i = 0; i < arg.nr_devs; i++) {
|
|
- u64 dev_u64;
|
|
- ret = copy_from_user_errcode(&dev_u64, &user_arg->devs[i], sizeof(u64));
|
|
- if (ret)
|
|
- goto err;
|
|
-
|
|
- char *dev_str = strndup_user((char __user *)(unsigned long) dev_u64, PATH_MAX);
|
|
- ret = PTR_ERR_OR_ZERO(dev_str);
|
|
- if (ret)
|
|
- goto err;
|
|
-
|
|
- ret = darray_push(&devs, dev_str);
|
|
- if (ret) {
|
|
- kfree(dev_str);
|
|
- goto err;
|
|
- }
|
|
- }
|
|
-
|
|
- thr = kzalloc(sizeof(*thr), GFP_KERNEL);
|
|
- if (!thr) {
|
|
- ret = -ENOMEM;
|
|
- goto err;
|
|
- }
|
|
-
|
|
- thr->opts = bch2_opts_empty();
|
|
-
|
|
- if (arg.opts) {
|
|
- char *optstr = strndup_user((char __user *)(unsigned long) arg.opts, 1 << 16);
|
|
- ret = PTR_ERR_OR_ZERO(optstr) ?:
|
|
- bch2_parse_mount_opts(NULL, &thr->opts, NULL, optstr);
|
|
- if (!IS_ERR(optstr))
|
|
- kfree(optstr);
|
|
-
|
|
- if (ret)
|
|
- goto err;
|
|
- }
|
|
-
|
|
- opt_set(thr->opts, stdio, (u64)(unsigned long)&thr->thr.stdio);
|
|
- opt_set(thr->opts, read_only, 1);
|
|
- opt_set(thr->opts, ratelimit_errors, 0);
|
|
-
|
|
- /* We need request_key() to be called before we punt to kthread: */
|
|
- opt_set(thr->opts, nostart, true);
|
|
-
|
|
- bch2_thread_with_stdio_init(&thr->thr, &bch2_offline_fsck_ops);
|
|
-
|
|
- thr->c = bch2_fs_open(devs.data, arg.nr_devs, thr->opts);
|
|
-
|
|
- if (!IS_ERR(thr->c) &&
|
|
- thr->c->opts.errors == BCH_ON_ERROR_panic)
|
|
- thr->c->opts.errors = BCH_ON_ERROR_ro;
|
|
-
|
|
- ret = __bch2_run_thread_with_stdio(&thr->thr);
|
|
-out:
|
|
- darray_for_each(devs, i)
|
|
- kfree(*i);
|
|
- darray_exit(&devs);
|
|
- return ret;
|
|
-err:
|
|
- if (thr)
|
|
- bch2_fsck_thread_exit(&thr->thr);
|
|
- pr_err("ret %s", bch2_err_str(ret));
|
|
- goto out;
|
|
-}
|
|
-
|
|
static long bch2_global_ioctl(unsigned cmd, void __user *arg)
|
|
{
|
|
long ret;
|
|
@@ -775,99 +651,6 @@ static long bch2_ioctl_disk_resize_journal(struct bch_fs *c,
|
|
return ret;
|
|
}
|
|
|
|
-static int bch2_fsck_online_thread_fn(struct thread_with_stdio *stdio)
|
|
-{
|
|
- struct fsck_thread *thr = container_of(stdio, struct fsck_thread, thr);
|
|
- struct bch_fs *c = thr->c;
|
|
-
|
|
- c->stdio_filter = current;
|
|
- c->stdio = &thr->thr.stdio;
|
|
-
|
|
- /*
|
|
- * XXX: can we figure out a way to do this without mucking with c->opts?
|
|
- */
|
|
- unsigned old_fix_errors = c->opts.fix_errors;
|
|
- if (opt_defined(thr->opts, fix_errors))
|
|
- c->opts.fix_errors = thr->opts.fix_errors;
|
|
- else
|
|
- c->opts.fix_errors = FSCK_FIX_ask;
|
|
-
|
|
- c->opts.fsck = true;
|
|
- set_bit(BCH_FS_fsck_running, &c->flags);
|
|
-
|
|
- c->curr_recovery_pass = BCH_RECOVERY_PASS_check_alloc_info;
|
|
- int ret = bch2_run_online_recovery_passes(c);
|
|
-
|
|
- clear_bit(BCH_FS_fsck_running, &c->flags);
|
|
- bch_err_fn(c, ret);
|
|
-
|
|
- c->stdio = NULL;
|
|
- c->stdio_filter = NULL;
|
|
- c->opts.fix_errors = old_fix_errors;
|
|
-
|
|
- up(&c->online_fsck_mutex);
|
|
- bch2_ro_ref_put(c);
|
|
- return ret;
|
|
-}
|
|
-
|
|
-static const struct thread_with_stdio_ops bch2_online_fsck_ops = {
|
|
- .exit = bch2_fsck_thread_exit,
|
|
- .fn = bch2_fsck_online_thread_fn,
|
|
-};
|
|
-
|
|
-static long bch2_ioctl_fsck_online(struct bch_fs *c,
|
|
- struct bch_ioctl_fsck_online arg)
|
|
-{
|
|
- struct fsck_thread *thr = NULL;
|
|
- long ret = 0;
|
|
-
|
|
- if (arg.flags)
|
|
- return -EINVAL;
|
|
-
|
|
- if (!capable(CAP_SYS_ADMIN))
|
|
- return -EPERM;
|
|
-
|
|
- if (!bch2_ro_ref_tryget(c))
|
|
- return -EROFS;
|
|
-
|
|
- if (down_trylock(&c->online_fsck_mutex)) {
|
|
- bch2_ro_ref_put(c);
|
|
- return -EAGAIN;
|
|
- }
|
|
-
|
|
- thr = kzalloc(sizeof(*thr), GFP_KERNEL);
|
|
- if (!thr) {
|
|
- ret = -ENOMEM;
|
|
- goto err;
|
|
- }
|
|
-
|
|
- thr->c = c;
|
|
- thr->opts = bch2_opts_empty();
|
|
-
|
|
- if (arg.opts) {
|
|
- char *optstr = strndup_user((char __user *)(unsigned long) arg.opts, 1 << 16);
|
|
-
|
|
- ret = PTR_ERR_OR_ZERO(optstr) ?:
|
|
- bch2_parse_mount_opts(c, &thr->opts, NULL, optstr);
|
|
- if (!IS_ERR(optstr))
|
|
- kfree(optstr);
|
|
-
|
|
- if (ret)
|
|
- goto err;
|
|
- }
|
|
-
|
|
- ret = bch2_run_thread_with_stdio(&thr->thr, &bch2_online_fsck_ops);
|
|
-err:
|
|
- if (ret < 0) {
|
|
- bch_err_fn(c, ret);
|
|
- if (thr)
|
|
- bch2_fsck_thread_exit(&thr->thr);
|
|
- up(&c->online_fsck_mutex);
|
|
- bch2_ro_ref_put(c);
|
|
- }
|
|
- return ret;
|
|
-}
|
|
-
|
|
#define BCH_IOCTL(_name, _argtype) \
|
|
do { \
|
|
_argtype i; \
|
|
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
|
|
index 2229f0dcc860..e0335265de3d 100644
|
|
--- a/fs/bcachefs/fsck.c
|
|
+++ b/fs/bcachefs/fsck.c
|
|
@@ -1,6 +1,7 @@
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include "bcachefs.h"
|
|
+#include "bcachefs_ioctl.h"
|
|
#include "bkey_buf.h"
|
|
#include "btree_cache.h"
|
|
#include "btree_update.h"
|
|
@@ -16,6 +17,7 @@
|
|
#include "recovery_passes.h"
|
|
#include "snapshot.h"
|
|
#include "super.h"
|
|
+#include "thread_with_file.h"
|
|
#include "xattr.h"
|
|
|
|
#include <linux/bsearch.h>
|
|
@@ -3192,3 +3194,219 @@ int bch2_fix_reflink_p(struct bch_fs *c)
|
|
bch_err_fn(c, ret);
|
|
return ret;
|
|
}
|
|
+
|
|
+struct fsck_thread {
|
|
+ struct thread_with_stdio thr;
|
|
+ struct bch_fs *c;
|
|
+ struct bch_opts opts;
|
|
+};
|
|
+
|
|
+static void bch2_fsck_thread_exit(struct thread_with_stdio *_thr)
|
|
+{
|
|
+ struct fsck_thread *thr = container_of(_thr, struct fsck_thread, thr);
|
|
+ kfree(thr);
|
|
+}
|
|
+
|
|
+static int bch2_fsck_offline_thread_fn(struct thread_with_stdio *stdio)
|
|
+{
|
|
+ struct fsck_thread *thr = container_of(stdio, struct fsck_thread, thr);
|
|
+ struct bch_fs *c = thr->c;
|
|
+
|
|
+ int ret = PTR_ERR_OR_ZERO(c);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = bch2_fs_start(thr->c);
|
|
+ if (ret)
|
|
+ goto err;
|
|
+
|
|
+ if (test_bit(BCH_FS_errors_fixed, &c->flags)) {
|
|
+ bch2_stdio_redirect_printf(&stdio->stdio, false, "%s: errors fixed\n", c->name);
|
|
+ ret |= 1;
|
|
+ }
|
|
+ if (test_bit(BCH_FS_error, &c->flags)) {
|
|
+ bch2_stdio_redirect_printf(&stdio->stdio, false, "%s: still has errors\n", c->name);
|
|
+ ret |= 4;
|
|
+ }
|
|
+err:
|
|
+ bch2_fs_stop(c);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct thread_with_stdio_ops bch2_offline_fsck_ops = {
|
|
+ .exit = bch2_fsck_thread_exit,
|
|
+ .fn = bch2_fsck_offline_thread_fn,
|
|
+};
|
|
+
|
|
+long bch2_ioctl_fsck_offline(struct bch_ioctl_fsck_offline __user *user_arg)
|
|
+{
|
|
+ struct bch_ioctl_fsck_offline arg;
|
|
+ struct fsck_thread *thr = NULL;
|
|
+ darray_str(devs) = {};
|
|
+ long ret = 0;
|
|
+
|
|
+ if (copy_from_user(&arg, user_arg, sizeof(arg)))
|
|
+ return -EFAULT;
|
|
+
|
|
+ if (arg.flags)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
+ return -EPERM;
|
|
+
|
|
+ for (size_t i = 0; i < arg.nr_devs; i++) {
|
|
+ u64 dev_u64;
|
|
+ ret = copy_from_user_errcode(&dev_u64, &user_arg->devs[i], sizeof(u64));
|
|
+ if (ret)
|
|
+ goto err;
|
|
+
|
|
+ char *dev_str = strndup_user((char __user *)(unsigned long) dev_u64, PATH_MAX);
|
|
+ ret = PTR_ERR_OR_ZERO(dev_str);
|
|
+ if (ret)
|
|
+ goto err;
|
|
+
|
|
+ ret = darray_push(&devs, dev_str);
|
|
+ if (ret) {
|
|
+ kfree(dev_str);
|
|
+ goto err;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ thr = kzalloc(sizeof(*thr), GFP_KERNEL);
|
|
+ if (!thr) {
|
|
+ ret = -ENOMEM;
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ thr->opts = bch2_opts_empty();
|
|
+
|
|
+ if (arg.opts) {
|
|
+ char *optstr = strndup_user((char __user *)(unsigned long) arg.opts, 1 << 16);
|
|
+ ret = PTR_ERR_OR_ZERO(optstr) ?:
|
|
+ bch2_parse_mount_opts(NULL, &thr->opts, NULL, optstr);
|
|
+ if (!IS_ERR(optstr))
|
|
+ kfree(optstr);
|
|
+
|
|
+ if (ret)
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ opt_set(thr->opts, stdio, (u64)(unsigned long)&thr->thr.stdio);
|
|
+ opt_set(thr->opts, read_only, 1);
|
|
+ opt_set(thr->opts, ratelimit_errors, 0);
|
|
+
|
|
+ /* We need request_key() to be called before we punt to kthread: */
|
|
+ opt_set(thr->opts, nostart, true);
|
|
+
|
|
+ bch2_thread_with_stdio_init(&thr->thr, &bch2_offline_fsck_ops);
|
|
+
|
|
+ thr->c = bch2_fs_open(devs.data, arg.nr_devs, thr->opts);
|
|
+
|
|
+ if (!IS_ERR(thr->c) &&
|
|
+ thr->c->opts.errors == BCH_ON_ERROR_panic)
|
|
+ thr->c->opts.errors = BCH_ON_ERROR_ro;
|
|
+
|
|
+ ret = __bch2_run_thread_with_stdio(&thr->thr);
|
|
+out:
|
|
+ darray_for_each(devs, i)
|
|
+ kfree(*i);
|
|
+ darray_exit(&devs);
|
|
+ return ret;
|
|
+err:
|
|
+ if (thr)
|
|
+ bch2_fsck_thread_exit(&thr->thr);
|
|
+ pr_err("ret %s", bch2_err_str(ret));
|
|
+ goto out;
|
|
+}
|
|
+
|
|
+static int bch2_fsck_online_thread_fn(struct thread_with_stdio *stdio)
|
|
+{
|
|
+ struct fsck_thread *thr = container_of(stdio, struct fsck_thread, thr);
|
|
+ struct bch_fs *c = thr->c;
|
|
+
|
|
+ c->stdio_filter = current;
|
|
+ c->stdio = &thr->thr.stdio;
|
|
+
|
|
+ /*
|
|
+ * XXX: can we figure out a way to do this without mucking with c->opts?
|
|
+ */
|
|
+ unsigned old_fix_errors = c->opts.fix_errors;
|
|
+ if (opt_defined(thr->opts, fix_errors))
|
|
+ c->opts.fix_errors = thr->opts.fix_errors;
|
|
+ else
|
|
+ c->opts.fix_errors = FSCK_FIX_ask;
|
|
+
|
|
+ c->opts.fsck = true;
|
|
+ set_bit(BCH_FS_fsck_running, &c->flags);
|
|
+
|
|
+ c->curr_recovery_pass = BCH_RECOVERY_PASS_check_alloc_info;
|
|
+ int ret = bch2_run_online_recovery_passes(c);
|
|
+
|
|
+ clear_bit(BCH_FS_fsck_running, &c->flags);
|
|
+ bch_err_fn(c, ret);
|
|
+
|
|
+ c->stdio = NULL;
|
|
+ c->stdio_filter = NULL;
|
|
+ c->opts.fix_errors = old_fix_errors;
|
|
+
|
|
+ up(&c->online_fsck_mutex);
|
|
+ bch2_ro_ref_put(c);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct thread_with_stdio_ops bch2_online_fsck_ops = {
|
|
+ .exit = bch2_fsck_thread_exit,
|
|
+ .fn = bch2_fsck_online_thread_fn,
|
|
+};
|
|
+
|
|
+long bch2_ioctl_fsck_online(struct bch_fs *c, struct bch_ioctl_fsck_online arg)
|
|
+{
|
|
+ struct fsck_thread *thr = NULL;
|
|
+ long ret = 0;
|
|
+
|
|
+ if (arg.flags)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
+ return -EPERM;
|
|
+
|
|
+ if (!bch2_ro_ref_tryget(c))
|
|
+ return -EROFS;
|
|
+
|
|
+ if (down_trylock(&c->online_fsck_mutex)) {
|
|
+ bch2_ro_ref_put(c);
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ thr = kzalloc(sizeof(*thr), GFP_KERNEL);
|
|
+ if (!thr) {
|
|
+ ret = -ENOMEM;
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ thr->c = c;
|
|
+ thr->opts = bch2_opts_empty();
|
|
+
|
|
+ if (arg.opts) {
|
|
+ char *optstr = strndup_user((char __user *)(unsigned long) arg.opts, 1 << 16);
|
|
+
|
|
+ ret = PTR_ERR_OR_ZERO(optstr) ?:
|
|
+ bch2_parse_mount_opts(c, &thr->opts, NULL, optstr);
|
|
+ if (!IS_ERR(optstr))
|
|
+ kfree(optstr);
|
|
+
|
|
+ if (ret)
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ ret = bch2_run_thread_with_stdio(&thr->thr, &bch2_online_fsck_ops);
|
|
+err:
|
|
+ if (ret < 0) {
|
|
+ bch_err_fn(c, ret);
|
|
+ if (thr)
|
|
+ bch2_fsck_thread_exit(&thr->thr);
|
|
+ up(&c->online_fsck_mutex);
|
|
+ bch2_ro_ref_put(c);
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
diff --git a/fs/bcachefs/fsck.h b/fs/bcachefs/fsck.h
|
|
index 1cca31011530..4481b40a881d 100644
|
|
--- a/fs/bcachefs/fsck.h
|
|
+++ b/fs/bcachefs/fsck.h
|
|
@@ -14,4 +14,7 @@ int bch2_check_directory_structure(struct bch_fs *);
|
|
int bch2_check_nlinks(struct bch_fs *);
|
|
int bch2_fix_reflink_p(struct bch_fs *);
|
|
|
|
+long bch2_ioctl_fsck_offline(struct bch_ioctl_fsck_offline __user *);
|
|
+long bch2_ioctl_fsck_online(struct bch_fs *, struct bch_ioctl_fsck_online);
|
|
+
|
|
#endif /* _BCACHEFS_FSCK_H */
|
|
--
|
|
2.45.2
|
|
|