From: Kent Overstreet <kent.overstreet@linux.dev>
To: linux-bcachefs@vger.kernel.org
Cc: Kent Overstreet <kent.overstreet@linux.dev>
Subject: [PATCH 3/3] bcachefs: Plumb error messages through data drop paths
Date: Fri, 29 Aug 2025 02:54:07 -0400 [thread overview]
Message-ID: <20250829065409.3248746-4-kent.overstreet@linux.dev> (raw)
In-Reply-To: <20250829065409.3248746-1-kent.overstreet@linux.dev>
The ioctl v2 rework added the ability to return error messages to
userspace directly - instead of via the dmesg log.
This lets us return more informative error messages: we can now return a
message with the key we failed on.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
---
fs/bcachefs/ec.c | 23 ++++++++++++------
fs/bcachefs/ec.h | 5 ++--
fs/bcachefs/migrate.c | 55 ++++++++++++++++++++++++-------------------
fs/bcachefs/migrate.h | 4 ++--
fs/bcachefs/super.c | 6 ++---
5 files changed, 55 insertions(+), 38 deletions(-)
diff --git a/fs/bcachefs/ec.c b/fs/bcachefs/ec.c
index c2840cb674b2..271e252152da 100644
--- a/fs/bcachefs/ec.c
+++ b/fs/bcachefs/ec.c
@@ -2040,7 +2040,7 @@ int bch2_invalidate_stripe_to_dev(struct btree_trans *trans,
struct btree_iter *iter,
struct bkey_s_c k,
unsigned dev_idx,
- unsigned flags)
+ unsigned flags, struct printbuf *err)
{
if (k.k->type != KEY_TYPE_stripe)
return 0;
@@ -2081,13 +2081,21 @@ int bch2_invalidate_stripe_to_dev(struct btree_trans *trans,
nr_good += ca && ca->mi.state != BCH_MEMBER_STATE_failed;
}
- if (nr_good < s->v.nr_blocks && !(flags & BCH_FORCE_IF_DATA_DEGRADED))
+ if (nr_good < s->v.nr_blocks && !(flags & BCH_FORCE_IF_DATA_DEGRADED)) {
+ prt_str(err, "cannot drop device without degrading\n ");
+ bch2_bkey_val_to_text(err, c, k);
+ prt_newline(err);
return bch_err_throw(c, remove_would_lose_data);
+ }
unsigned nr_data = s->v.nr_blocks - s->v.nr_redundant;
- if (nr_good < nr_data && !(flags & BCH_FORCE_IF_DATA_LOST))
+ if (nr_good < nr_data && !(flags & BCH_FORCE_IF_DATA_LOST)) {
+ prt_str(err, "cannot drop device without losing data\n ");
+ bch2_bkey_val_to_text(err, c, k);
+ prt_newline(err);
return bch_err_throw(c, remove_would_lose_data);
+ }
sectors = -sectors;
@@ -2099,7 +2107,7 @@ int bch2_invalidate_stripe_to_dev(struct btree_trans *trans,
}
static int bch2_invalidate_stripe_to_dev_from_alloc(struct btree_trans *trans, struct bkey_s_c k_a,
- unsigned flags)
+ unsigned flags, struct printbuf *err)
{
struct bch_alloc_v4 a_convert;
const struct bch_alloc_v4 *a = bch2_alloc_to_v4(k_a, &a_convert);
@@ -2119,17 +2127,18 @@ static int bch2_invalidate_stripe_to_dev_from_alloc(struct btree_trans *trans, s
if (ret)
return ret;
- return bch2_invalidate_stripe_to_dev(trans, &iter, s.s_c, k_a.k->p.inode, flags);
+ return bch2_invalidate_stripe_to_dev(trans, &iter, s.s_c, k_a.k->p.inode, flags, err);
}
-int bch2_dev_remove_stripes(struct bch_fs *c, unsigned dev_idx, unsigned flags)
+int bch2_dev_remove_stripes(struct bch_fs *c, unsigned dev_idx,
+ unsigned flags, struct printbuf *err)
{
CLASS(btree_trans, trans)(c);
int ret = for_each_btree_key_max_commit(trans, iter,
BTREE_ID_alloc, POS(dev_idx, 0), POS(dev_idx, U64_MAX),
BTREE_ITER_intent, k,
NULL, NULL, 0, ({
- bch2_invalidate_stripe_to_dev_from_alloc(trans, k, flags);
+ bch2_invalidate_stripe_to_dev_from_alloc(trans, k, flags, err);
}));
bch_err_fn(c, ret);
return ret;
diff --git a/fs/bcachefs/ec.h b/fs/bcachefs/ec.h
index e807e7027d7a..cc778da99030 100644
--- a/fs/bcachefs/ec.h
+++ b/fs/bcachefs/ec.h
@@ -289,8 +289,9 @@ static inline void ec_stripe_new_put(struct bch_fs *c, struct ec_stripe_new *s,
}
int bch2_invalidate_stripe_to_dev(struct btree_trans *, struct btree_iter *,
- struct bkey_s_c, unsigned, unsigned);
-int bch2_dev_remove_stripes(struct bch_fs *, unsigned, unsigned);
+ struct bkey_s_c, unsigned,
+ unsigned, struct printbuf *);
+int bch2_dev_remove_stripes(struct bch_fs *, unsigned, unsigned, struct printbuf *);
void bch2_ec_stop_dev(struct bch_fs *, struct bch_dev *);
void bch2_fs_ec_stop(struct bch_fs *);
diff --git a/fs/bcachefs/migrate.c b/fs/bcachefs/migrate.c
index 892990b4a6a6..5b4c3f4b1c25 100644
--- a/fs/bcachefs/migrate.c
+++ b/fs/bcachefs/migrate.c
@@ -22,8 +22,8 @@
#include "replicas.h"
#include "super-io.h"
-static int drop_dev_ptrs(struct bch_fs *c, struct bkey_s k,
- unsigned dev_idx, unsigned flags, bool metadata)
+static int drop_dev_ptrs(struct bch_fs *c, struct bkey_s k, unsigned dev_idx,
+ unsigned flags, struct printbuf *err, bool metadata)
{
unsigned replicas = metadata ? c->opts.metadata_replicas : c->opts.data_replicas;
unsigned lost = metadata ? BCH_FORCE_IF_METADATA_LOST : BCH_FORCE_IF_DATA_LOST;
@@ -34,14 +34,19 @@ static int drop_dev_ptrs(struct bch_fs *c, struct bkey_s k,
nr_good = bch2_bkey_durability(c, k.s_c);
if ((!nr_good && !(flags & lost)) ||
- (nr_good < replicas && !(flags & degraded)))
+ (nr_good < replicas && !(flags & degraded))) {
+ prt_str(err, "cannot drop device without degrading/losing data\n ");
+ bch2_bkey_val_to_text(err, c, k.s_c);
+ prt_newline(err);
return bch_err_throw(c, remove_would_lose_data);
+ }
return 0;
}
static int drop_btree_ptrs(struct btree_trans *trans, struct btree_iter *iter,
- struct btree *b, unsigned dev_idx, unsigned flags)
+ struct btree *b, unsigned dev_idx,
+ unsigned flags, struct printbuf *err)
{
struct bch_fs *c = trans->c;
struct bkey_buf k;
@@ -49,10 +54,9 @@ static int drop_btree_ptrs(struct btree_trans *trans, struct btree_iter *iter,
bch2_bkey_buf_init(&k);
bch2_bkey_buf_copy(&k, c, &b->key);
- int ret = drop_dev_ptrs(c, bkey_i_to_s(k.k), dev_idx, flags, true) ?:
+ int ret = drop_dev_ptrs(c, bkey_i_to_s(k.k), dev_idx, flags, err, true) ?:
bch2_btree_node_update_key(trans, iter, b, k.k, 0, false);
- bch_err_fn(c, ret);
bch2_bkey_buf_exit(&k, c);
return ret;
}
@@ -61,7 +65,7 @@ static int bch2_dev_usrdata_drop_key(struct btree_trans *trans,
struct btree_iter *iter,
struct bkey_s_c k,
unsigned dev_idx,
- unsigned flags)
+ unsigned flags, struct printbuf *err)
{
struct bch_fs *c = trans->c;
struct bkey_i *n;
@@ -75,7 +79,7 @@ static int bch2_dev_usrdata_drop_key(struct btree_trans *trans,
if (ret)
return ret;
- ret = drop_dev_ptrs(c, bkey_i_to_s(n), dev_idx, flags, false);
+ ret = drop_dev_ptrs(c, bkey_i_to_s(n), dev_idx, flags, err, false);
if (ret)
return ret;
@@ -101,7 +105,7 @@ static int bch2_dev_btree_drop_key(struct btree_trans *trans,
struct bkey_s_c_backpointer bp,
unsigned dev_idx,
struct bkey_buf *last_flushed,
- unsigned flags)
+ unsigned flags, struct printbuf *err)
{
struct btree_iter iter;
struct btree *b = bch2_backpointer_get_node(trans, bp, &iter, last_flushed);
@@ -109,7 +113,7 @@ static int bch2_dev_btree_drop_key(struct btree_trans *trans,
if (ret)
return ret == -BCH_ERR_backpointer_to_overwritten_btree_node ? 0 : ret;
- ret = drop_btree_ptrs(trans, &iter, b, dev_idx, flags);
+ ret = drop_btree_ptrs(trans, &iter, b, dev_idx, flags, err);
bch2_trans_iter_exit(&iter);
return ret;
@@ -117,7 +121,8 @@ static int bch2_dev_btree_drop_key(struct btree_trans *trans,
static int bch2_dev_usrdata_drop(struct bch_fs *c,
struct progress_indicator_state *progress,
- unsigned dev_idx, unsigned flags)
+ unsigned dev_idx,
+ unsigned flags, struct printbuf *err)
{
CLASS(btree_trans, trans)(c);
@@ -133,7 +138,7 @@ static int bch2_dev_usrdata_drop(struct bch_fs *c,
BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k,
NULL, NULL, BCH_TRANS_COMMIT_no_enospc, ({
bch2_progress_update_iter(trans, progress, &iter, "dropping user data");
- bch2_dev_usrdata_drop_key(trans, &iter, k, dev_idx, flags);
+ bch2_dev_usrdata_drop_key(trans, &iter, k, dev_idx, flags, err);
}));
if (ret)
return ret;
@@ -144,7 +149,8 @@ static int bch2_dev_usrdata_drop(struct bch_fs *c,
static int bch2_dev_metadata_drop(struct bch_fs *c,
struct progress_indicator_state *progress,
- unsigned dev_idx, unsigned flags)
+ unsigned dev_idx,
+ unsigned flags, struct printbuf *err)
{
struct btree_iter iter;
struct closure cl;
@@ -174,7 +180,7 @@ static int bch2_dev_metadata_drop(struct bch_fs *c,
if (!bch2_bkey_has_device_c(bkey_i_to_s_c(&b->key), dev_idx))
goto next;
- ret = drop_btree_ptrs(trans, &iter, b, dev_idx, flags);
+ ret = drop_btree_ptrs(trans, &iter, b, dev_idx, flags, err);
if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) {
ret = 0;
continue;
@@ -206,7 +212,7 @@ static int bch2_dev_metadata_drop(struct bch_fs *c,
static int data_drop_bp(struct btree_trans *trans, unsigned dev_idx,
struct bkey_s_c_backpointer bp, struct bkey_buf *last_flushed,
- unsigned flags)
+ unsigned flags, struct printbuf *err)
{
struct btree_iter iter;
struct bkey_s_c k = bch2_backpointer_get_key(trans, bp, &iter, BTREE_ITER_intent,
@@ -226,17 +232,18 @@ static int data_drop_bp(struct btree_trans *trans, unsigned dev_idx,
*/
if (bkey_is_btree_ptr(k.k))
- ret = bch2_dev_btree_drop_key(trans, bp, dev_idx, last_flushed, flags);
+ ret = bch2_dev_btree_drop_key(trans, bp, dev_idx, last_flushed, flags, err);
else if (k.k->type == KEY_TYPE_stripe)
- ret = bch2_invalidate_stripe_to_dev(trans, &iter, k, dev_idx, flags);
+ ret = bch2_invalidate_stripe_to_dev(trans, &iter, k, dev_idx, flags, err);
else
- ret = bch2_dev_usrdata_drop_key(trans, &iter, k, dev_idx, flags);
+ ret = bch2_dev_usrdata_drop_key(trans, &iter, k, dev_idx, flags, err);
out:
bch2_trans_iter_exit(&iter);
return ret;
}
-int bch2_dev_data_drop_by_backpointers(struct bch_fs *c, unsigned dev_idx, unsigned flags)
+int bch2_dev_data_drop_by_backpointers(struct bch_fs *c, unsigned dev_idx, unsigned flags,
+ struct printbuf *err)
{
CLASS(btree_trans, trans)(c);
@@ -253,22 +260,22 @@ int bch2_dev_data_drop_by_backpointers(struct bch_fs *c, unsigned dev_idx, unsig
continue;
data_drop_bp(trans, dev_idx, bkey_s_c_to_backpointer(k),
- &last_flushed, flags);
+ &last_flushed, flags, err);
}));
bch2_bkey_buf_exit(&last_flushed, trans->c);
- bch_err_fn(c, ret);
return ret;
}
-int bch2_dev_data_drop(struct bch_fs *c, unsigned dev_idx, unsigned flags)
+int bch2_dev_data_drop(struct bch_fs *c, unsigned dev_idx,
+ unsigned flags, struct printbuf *err)
{
struct progress_indicator_state progress;
bch2_progress_init(&progress, c,
BIT_ULL(BTREE_ID_extents)|
BIT_ULL(BTREE_ID_reflink));
- return bch2_dev_usrdata_drop(c, &progress, dev_idx, flags) ?:
- bch2_dev_metadata_drop(c, &progress, dev_idx, flags);
+ return bch2_dev_usrdata_drop(c, &progress, dev_idx, flags, err) ?:
+ bch2_dev_metadata_drop(c, &progress, dev_idx, flags, err);
}
diff --git a/fs/bcachefs/migrate.h b/fs/bcachefs/migrate.h
index 30018140711b..ff4567fb5a83 100644
--- a/fs/bcachefs/migrate.h
+++ b/fs/bcachefs/migrate.h
@@ -2,7 +2,7 @@
#ifndef _BCACHEFS_MIGRATE_H
#define _BCACHEFS_MIGRATE_H
-int bch2_dev_data_drop_by_backpointers(struct bch_fs *, unsigned, unsigned);
-int bch2_dev_data_drop(struct bch_fs *, unsigned, unsigned);
+int bch2_dev_data_drop_by_backpointers(struct bch_fs *, unsigned, unsigned, struct printbuf *);
+int bch2_dev_data_drop(struct bch_fs *, unsigned, unsigned, struct printbuf *);
#endif /* _BCACHEFS_MIGRATE_H */
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
index 793c16fa8b09..d640ae188722 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -1992,9 +1992,9 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags,
__bch2_dev_read_only(c, ca);
ret = fast_device_removal
- ? bch2_dev_data_drop_by_backpointers(c, ca->dev_idx, flags)
- : (bch2_dev_data_drop(c, ca->dev_idx, flags) ?:
- bch2_dev_remove_stripes(c, ca->dev_idx, flags));
+ ? bch2_dev_data_drop_by_backpointers(c, ca->dev_idx, flags, err)
+ : (bch2_dev_data_drop(c, ca->dev_idx, flags, err) ?:
+ bch2_dev_remove_stripes(c, ca->dev_idx, flags, err));
if (ret)
goto err;
--
2.50.1
prev parent reply other threads:[~2025-08-29 6:54 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-29 6:54 [PATCH 0/3] better error messages for ioctls Kent Overstreet
2025-08-29 6:54 ` [PATCH 1/3] bcachefs: Add v2 ioctls that return error strings Kent Overstreet
2025-08-29 6:54 ` [PATCH 2/3] bcachefs: v2 versions of subvolume ioctls Kent Overstreet
2025-08-29 6:54 ` Kent Overstreet [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250829065409.3248746-4-kent.overstreet@linux.dev \
--to=kent.overstreet@linux.dev \
--cc=linux-bcachefs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.