summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2022-07-17 22:31:21 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:09:36 -0400
commit615f867c14b2d70efb02dafb8e668d984e74d0e3 (patch)
tree266f977a35d430198ba942f24e4dcbb73664f9fa
parent3ab25c1b4ef2a57b8bc55e786e90af63f7d06663 (diff)
bcachefs: Improved errcodes
Instead of overloading standard error codes (EINTR/EAGAIN), and defining short lists of error codes in multiple places that potentially end up overlapping & conflicting, we're now going to have one master list of error codes. Error codes are defined with an x-macro: thus we also have bch2_err_str() now. Also, error codes have a class field. Now, instead of checking for errors with ==, code should use bch2_err_matches(), which returns true if the error is equal to or a sub-error of the error class. This means we can define unique errors for every source location where an error is generated, which will help improve our error messages. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/Kconfig1
-rw-r--r--fs/bcachefs/Makefile1
-rw-r--r--fs/bcachefs/alloc_background.c3
-rw-r--r--fs/bcachefs/alloc_foreground.c39
-rw-r--r--fs/bcachefs/errcode.c51
-rw-r--r--fs/bcachefs/errcode.h33
-rw-r--r--fs/bcachefs/fsck.c4
-rw-r--r--fs/bcachefs/trace.h32
8 files changed, 120 insertions, 44 deletions
diff --git a/fs/bcachefs/Kconfig b/fs/bcachefs/Kconfig
index 7ae85900e5b4..76953e05b240 100644
--- a/fs/bcachefs/Kconfig
+++ b/fs/bcachefs/Kconfig
@@ -21,6 +21,7 @@ config BCACHEFS_FS
select XOR_BLOCKS
select XXHASH
select SRCU
+ select SYMBOLIC_ERRNAME
help
The bcachefs filesystem - a modern, copy on write filesystem, with
support for multiple devices, compression, checksumming, etc.
diff --git a/fs/bcachefs/Makefile b/fs/bcachefs/Makefile
index 95b990ad0196..2f4bd31c862f 100644
--- a/fs/bcachefs/Makefile
+++ b/fs/bcachefs/Makefile
@@ -27,6 +27,7 @@ bcachefs-y := \
disk_groups.o \
data_update.o \
ec.o \
+ errcode.o \
error.o \
extents.o \
extent_update.o \
diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c
index baefd12a3fe8..9ba1fdba4138 100644
--- a/fs/bcachefs/alloc_background.c
+++ b/fs/bcachefs/alloc_background.c
@@ -1051,7 +1051,8 @@ static void bch2_do_discards_work(struct work_struct *work)
percpu_ref_put(&c->writes);
- trace_discard_buckets(c, seen, open, need_journal_commit, discarded, ret);
+ trace_discard_buckets(c, seen, open, need_journal_commit, discarded,
+ bch2_err_str(ret));
}
void bch2_do_discards(struct bch_fs *c)
diff --git a/fs/bcachefs/alloc_foreground.c b/fs/bcachefs/alloc_foreground.c
index 2d44ce2e11de..39e3bb5205ca 100644
--- a/fs/bcachefs/alloc_foreground.c
+++ b/fs/bcachefs/alloc_foreground.c
@@ -238,7 +238,7 @@ static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *
c->blocked_allocate_open_bucket = local_clock();
spin_unlock(&c->freelist_lock);
- return ERR_PTR(-OPEN_BUCKETS_EMPTY);
+ return ERR_PTR(-BCH_ERR_open_buckets_empty);
}
/* Recheck under lock: */
@@ -440,7 +440,7 @@ again:
goto again;
}
- return ob ?: ERR_PTR(ret ?: -FREELIST_EMPTY);
+ return ob ?: ERR_PTR(ret ?: -BCH_ERR_no_buckets_found);
}
static struct open_bucket *bch2_bucket_alloc_freelist(struct btree_trans *trans,
@@ -548,7 +548,7 @@ again:
if (!c->blocked_allocate)
c->blocked_allocate = local_clock();
- ob = ERR_PTR(-FREELIST_EMPTY);
+ ob = ERR_PTR(-BCH_ERR_freelist_empty);
goto err;
}
@@ -579,7 +579,7 @@ again:
bch2_journal_flush_async(&c->journal, NULL);
err:
if (!ob)
- ob = ERR_PTR(-FREELIST_EMPTY);
+ ob = ERR_PTR(-BCH_ERR_no_buckets_found);
if (!IS_ERR(ob)) {
trace_bucket_alloc(ca, bch2_alloc_reserves[reserve],
@@ -591,7 +591,8 @@ err:
skipped_open,
skipped_need_journal_commit,
skipped_nouse,
- cl == NULL, PTR_ERR_OR_ZERO(ob));
+ cl == NULL,
+ "");
} else {
trace_bucket_alloc_fail(ca, bch2_alloc_reserves[reserve],
usage.d[BCH_DATA_free].buckets,
@@ -602,7 +603,8 @@ err:
skipped_open,
skipped_need_journal_commit,
skipped_nouse,
- cl == NULL, PTR_ERR_OR_ZERO(ob));
+ cl == NULL,
+ bch2_err_str(PTR_ERR(ob)));
atomic_long_inc(&c->bucket_alloc_fail);
}
@@ -750,7 +752,7 @@ static int bch2_bucket_alloc_set_trans(struct btree_trans *trans,
if (*nr_effective >= nr_replicas)
ret = 0;
else if (!ret)
- ret = -INSUFFICIENT_DEVICES;
+ ret = -BCH_ERR_insufficient_devices;
return ret;
}
@@ -923,8 +925,8 @@ static int open_bucket_add_buckets(struct btree_trans *trans,
nr_replicas, nr_effective,
have_cache, flags, _cl);
if (ret == -EINTR ||
- ret == -FREELIST_EMPTY ||
- ret == -OPEN_BUCKETS_EMPTY)
+ bch2_err_matches(ret, BCH_ERR_freelist_empty) ||
+ bch2_err_matches(ret, BCH_ERR_open_buckets_empty))
return ret;
if (*nr_effective >= nr_replicas)
return 0;
@@ -947,7 +949,7 @@ retry_blocking:
reserve, flags, cl);
if (ret &&
ret != -EINTR &&
- ret != -INSUFFICIENT_DEVICES &&
+ !bch2_err_matches(ret, BCH_ERR_insufficient_devices) &&
!cl && _cl) {
cl = _cl;
goto retry_blocking;
@@ -1203,7 +1205,7 @@ alloc_done:
if (erasure_code && !ec_open_bucket(c, &ptrs))
pr_debug("failed to get ec bucket: ret %u", ret);
- if (ret == -INSUFFICIENT_DEVICES &&
+ if (ret == -BCH_ERR_insufficient_devices &&
nr_effective >= nr_replicas_required)
ret = 0;
@@ -1234,19 +1236,18 @@ err:
mutex_unlock(&wp->lock);
- if (ret == -FREELIST_EMPTY &&
+ if (bch2_err_matches(ret, BCH_ERR_freelist_empty) &&
try_decrease_writepoints(c, write_points_nr))
goto retry;
- switch (ret) {
- case -OPEN_BUCKETS_EMPTY:
- case -FREELIST_EMPTY:
+ if (bch2_err_matches(ret, BCH_ERR_open_buckets_empty) ||
+ bch2_err_matches(ret, BCH_ERR_freelist_empty))
return cl ? -EAGAIN : -ENOSPC;
- case -INSUFFICIENT_DEVICES:
+
+ if (bch2_err_matches(ret, BCH_ERR_insufficient_devices))
return -EROFS;
- default:
- return ret;
- }
+
+ return ret;
}
int bch2_alloc_sectors_start(struct bch_fs *c,
diff --git a/fs/bcachefs/errcode.c b/fs/bcachefs/errcode.c
new file mode 100644
index 000000000000..9da8a5973af0
--- /dev/null
+++ b/fs/bcachefs/errcode.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "bcachefs.h"
+#include "errcode.h"
+
+#include <linux/errname.h>
+
+static const char * const bch2_errcode_strs[] = {
+#define x(class, err) [BCH_ERR_##err - BCH_ERR_START] = #err,
+ BCH_ERRCODES()
+#undef x
+ NULL
+};
+
+#define BCH_ERR_0 0
+
+static unsigned bch2_errcode_parents[] = {
+#define x(class, err) [BCH_ERR_##err - BCH_ERR_START] = BCH_ERR_##class,
+ BCH_ERRCODES()
+#undef x
+};
+
+const char *bch2_err_str(int err)
+{
+ const char *errstr;
+ err = abs(err);
+
+ BUG_ON(err >= BCH_ERR_MAX);
+
+ if (err >= BCH_ERR_START)
+ errstr = bch2_errcode_strs[err - BCH_ERR_START];
+ else if (err)
+ errstr = errname(err);
+ else
+ errstr = "(No error)";
+ return errstr ?: "(Invalid error)";
+}
+
+bool __bch2_err_matches(int err, int class)
+{
+ err = abs(err);
+ class = abs(class);
+
+ BUG_ON(err >= BCH_ERR_MAX);
+ BUG_ON(class >= BCH_ERR_MAX);
+
+ while (err >= BCH_ERR_START && err != class)
+ err = bch2_errcode_parents[err - BCH_ERR_START];
+
+ return err == class;
+}
diff --git a/fs/bcachefs/errcode.h b/fs/bcachefs/errcode.h
index 0581f3c7a0d8..69cc7cdd1c06 100644
--- a/fs/bcachefs/errcode.h
+++ b/fs/bcachefs/errcode.h
@@ -2,12 +2,33 @@
#ifndef _BCACHEFS_ERRCODE_H
#define _BCACHEFS_ERRCODE_H
-enum {
- /* Bucket allocator: */
- OPEN_BUCKETS_EMPTY = 2048,
- FREELIST_EMPTY, /* Allocator thread not keeping up */
- INSUFFICIENT_DEVICES,
- NEED_SNAPSHOT_CLEANUP,
+#define BCH_ERRCODES() \
+ x(0, open_buckets_empty) \
+ x(0, freelist_empty) \
+ x(freelist_empty, no_buckets_found) \
+ x(0, insufficient_devices) \
+ x(0, need_snapshot_cleanup)
+
+enum bch_errcode {
+ BCH_ERR_START = 2048,
+#define x(class, err) BCH_ERR_##err,
+ BCH_ERRCODES()
+#undef x
+ BCH_ERR_MAX
};
+const char *bch2_err_str(int);
+bool __bch2_err_matches(int, int);
+
+static inline bool _bch2_err_matches(int err, int class)
+{
+ return err && __bch2_err_matches(err, class);
+}
+
+#define bch2_err_matches(_err, _class) \
+({ \
+ BUILD_BUG_ON(!__builtin_constant_p(_class)); \
+ _bch2_err_matches(_err, _class); \
+})
+
#endif /* _BCACHFES_ERRCODE_H */
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
index 8f006b9a4804..e601a1ee0ee1 100644
--- a/fs/bcachefs/fsck.c
+++ b/fs/bcachefs/fsck.c
@@ -534,7 +534,7 @@ static int snapshots_seen_update(struct bch_fs *c, struct snapshots_seen *s,
bch2_btree_ids[btree_id],
pos.inode, pos.offset,
i->id, n.id, n.equiv);
- return -NEED_SNAPSHOT_CLEANUP;
+ return -BCH_ERR_need_snapshot_cleanup;
}
return 0;
@@ -2371,7 +2371,7 @@ again:
check_nlinks(c) ?:
fix_reflink_p(c);
- if (ret == -NEED_SNAPSHOT_CLEANUP) {
+ if (bch2_err_matches(ret, BCH_ERR_need_snapshot_cleanup)) {
set_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags);
goto again;
}
diff --git a/fs/bcachefs/trace.h b/fs/bcachefs/trace.h
index 5782952b72a5..65c38aa38359 100644
--- a/fs/bcachefs/trace.h
+++ b/fs/bcachefs/trace.h
@@ -449,9 +449,9 @@ DECLARE_EVENT_CLASS(bucket_alloc,
u64 need_journal_commit,
u64 nouse,
bool nonblocking,
- int ret),
+ const char *err),
TP_ARGS(ca, alloc_reserve, free, avail, copygc_wait_amount, copygc_waiting_for,
- seen, open, need_journal_commit, nouse, nonblocking, ret),
+ seen, open, need_journal_commit, nouse, nonblocking, err),
TP_STRUCT__entry(
__field(dev_t, dev )
@@ -465,7 +465,7 @@ DECLARE_EVENT_CLASS(bucket_alloc,
__field(u64, need_journal_commit )
__field(u64, nouse )
__field(bool, nonblocking )
- __field(int, ret )
+ __array(char, err, 16 )
),
TP_fast_assign(
@@ -480,10 +480,10 @@ DECLARE_EVENT_CLASS(bucket_alloc,
__entry->need_journal_commit = need_journal_commit;
__entry->nouse = nouse;
__entry->nonblocking = nonblocking;
- __entry->ret = ret;
+ strlcpy(__entry->err, err, sizeof(__entry->err));
),
- TP_printk("%d,%d reserve %s free %llu avail %llu copygc_wait %llu/%lli seen %llu open %llu need_journal_commit %llu nouse %llu nonblocking %u ret %i",
+ TP_printk("%d,%d reserve %s free %llu avail %llu copygc_wait %llu/%lli seen %llu open %llu need_journal_commit %llu nouse %llu nonblocking %u err %s",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->reserve,
__entry->free,
@@ -495,7 +495,7 @@ DECLARE_EVENT_CLASS(bucket_alloc,
__entry->need_journal_commit,
__entry->nouse,
__entry->nonblocking,
- __entry->ret)
+ __entry->err)
);
DEFINE_EVENT(bucket_alloc, bucket_alloc,
@@ -509,9 +509,9 @@ DEFINE_EVENT(bucket_alloc, bucket_alloc,
u64 need_journal_commit,
u64 nouse,
bool nonblocking,
- int ret),
+ const char *err),
TP_ARGS(ca, alloc_reserve, free, avail, copygc_wait_amount, copygc_waiting_for,
- seen, open, need_journal_commit, nouse, nonblocking, ret)
+ seen, open, need_journal_commit, nouse, nonblocking, err)
);
DEFINE_EVENT(bucket_alloc, bucket_alloc_fail,
@@ -525,15 +525,15 @@ DEFINE_EVENT(bucket_alloc, bucket_alloc_fail,
u64 need_journal_commit,
u64 nouse,
bool nonblocking,
- int ret),
+ const char *err),
TP_ARGS(ca, alloc_reserve, free, avail, copygc_wait_amount, copygc_waiting_for,
- seen, open, need_journal_commit, nouse, nonblocking, ret)
+ seen, open, need_journal_commit, nouse, nonblocking, err)
);
TRACE_EVENT(discard_buckets,
TP_PROTO(struct bch_fs *c, u64 seen, u64 open,
- u64 need_journal_commit, u64 discarded, int ret),
- TP_ARGS(c, seen, open, need_journal_commit, discarded, ret),
+ u64 need_journal_commit, u64 discarded, const char *err),
+ TP_ARGS(c, seen, open, need_journal_commit, discarded, err),
TP_STRUCT__entry(
__field(dev_t, dev )
@@ -541,7 +541,7 @@ TRACE_EVENT(discard_buckets,
__field(u64, open )
__field(u64, need_journal_commit )
__field(u64, discarded )
- __field(int, ret )
+ __array(char, err, 16 )
),
TP_fast_assign(
@@ -550,16 +550,16 @@ TRACE_EVENT(discard_buckets,
__entry->open = open;
__entry->need_journal_commit = need_journal_commit;
__entry->discarded = discarded;
- __entry->ret = ret;
+ strlcpy(__entry->err, err, sizeof(__entry->err));
),
- TP_printk("%d%d seen %llu open %llu need_journal_commit %llu discarded %llu ret %i",
+ TP_printk("%d%d seen %llu open %llu need_journal_commit %llu discarded %llu err %s",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->seen,
__entry->open,
__entry->need_journal_commit,
__entry->discarded,
- __entry->ret)
+ __entry->err)
);
TRACE_EVENT(invalidate_bucket,