summaryrefslogtreecommitdiff
path: root/libbcachefs
diff options
context:
space:
mode:
Diffstat (limited to 'libbcachefs')
-rw-r--r--libbcachefs/alloc_background.c5
-rw-r--r--libbcachefs/alloc_foreground.c110
-rw-r--r--libbcachefs/bcachefs.h2
-rw-r--r--libbcachefs/btree_iter.c13
-rw-r--r--libbcachefs/btree_types.h4
-rw-r--r--libbcachefs/btree_update.h2
-rw-r--r--libbcachefs/btree_update_interior.c29
-rw-r--r--libbcachefs/btree_update_leaf.c44
-rw-r--r--libbcachefs/darray.h76
-rw-r--r--libbcachefs/fs.c2
-rw-r--r--libbcachefs/fs.h4
-rw-r--r--libbcachefs/fsck.c153
-rw-r--r--libbcachefs/move.c8
-rw-r--r--libbcachefs/subvolume.c41
-rw-r--r--libbcachefs/subvolume.h38
-rw-r--r--libbcachefs/subvolume_types.h8
16 files changed, 319 insertions, 220 deletions
diff --git a/libbcachefs/alloc_background.c b/libbcachefs/alloc_background.c
index 81cbfeb5..07a76993 100644
--- a/libbcachefs/alloc_background.c
+++ b/libbcachefs/alloc_background.c
@@ -862,7 +862,9 @@ static void bch2_do_discards_work(struct work_struct *work)
bch2_bucket_is_open_safe(c, k.k->p.inode, k.k->p.offset))
continue;
- ret = __bch2_trans_do(&trans, NULL, NULL, 0,
+ ret = __bch2_trans_do(&trans, NULL, NULL,
+ BTREE_INSERT_USE_RESERVE|
+ BTREE_INSERT_NOFAIL,
bch2_clear_need_discard(&trans, k.k->p, ca, &discard_done));
if (ret)
break;
@@ -954,6 +956,7 @@ static void bch2_do_invalidates_work(struct work_struct *work)
for_each_member_device(ca, c, i)
while (!ret && should_invalidate_buckets(ca))
ret = __bch2_trans_do(&trans, NULL, NULL,
+ BTREE_INSERT_USE_RESERVE|
BTREE_INSERT_NOFAIL,
invalidate_one_bucket(&trans, ca));
diff --git a/libbcachefs/alloc_foreground.c b/libbcachefs/alloc_foreground.c
index 5b114936..538b597d 100644
--- a/libbcachefs/alloc_foreground.c
+++ b/libbcachefs/alloc_foreground.c
@@ -192,20 +192,26 @@ static inline unsigned open_buckets_reserved(enum alloc_reserve reserve)
static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *ca,
enum alloc_reserve reserve,
struct bkey_alloc_unpacked a,
- size_t *need_journal_commit,
+ u64 *skipped_open,
+ u64 *skipped_need_journal_commit,
+ u64 *skipped_nouse,
struct closure *cl)
{
struct open_bucket *ob;
- if (unlikely(ca->buckets_nouse && test_bit(a.bucket, ca->buckets_nouse)))
+ if (unlikely(ca->buckets_nouse && test_bit(a.bucket, ca->buckets_nouse))) {
+ (*skipped_nouse)++;
return NULL;
+ }
- if (bch2_bucket_is_open(c, ca->dev_idx, a.bucket))
+ if (bch2_bucket_is_open(c, ca->dev_idx, a.bucket)) {
+ (*skipped_open)++;
return NULL;
+ }
if (bch2_bucket_needs_journal_commit(&c->buckets_waiting_for_journal,
c->journal.flushed_seq_ondisk, ca->dev_idx, a.bucket)) {
- (*need_journal_commit)++;
+ (*skipped_need_journal_commit)++;
return NULL;
}
@@ -227,6 +233,7 @@ static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *
/* Recheck under lock: */
if (bch2_bucket_is_open(c, ca->dev_idx, a.bucket)) {
spin_unlock(&c->freelist_lock);
+ (*skipped_open)++;
return NULL;
}
@@ -267,7 +274,9 @@ static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *
static struct open_bucket *try_alloc_bucket(struct btree_trans *trans, struct bch_dev *ca,
enum alloc_reserve reserve, u64 free_entry,
- size_t *need_journal_commit,
+ u64 *skipped_open,
+ u64 *skipped_need_journal_commit,
+ u64 *skipped_nouse,
struct closure *cl)
{
struct bch_fs *c = trans->c;
@@ -317,7 +326,11 @@ static struct open_bucket *try_alloc_bucket(struct btree_trans *trans, struct bc
goto err;
}
- ob = __try_alloc_bucket(c, ca, reserve, a, need_journal_commit, cl);
+ ob = __try_alloc_bucket(c, ca, reserve, a,
+ skipped_open,
+ skipped_need_journal_commit,
+ skipped_nouse,
+ cl);
err:
bch2_trans_iter_exit(trans, &iter);
printbuf_exit(&buf);
@@ -360,8 +373,11 @@ static noinline struct open_bucket *
bch2_bucket_alloc_trans_early(struct btree_trans *trans,
struct bch_dev *ca,
enum alloc_reserve reserve,
- u64 *b,
- size_t *need_journal_commit,
+ u64 *cur_bucket,
+ u64 *buckets_seen,
+ u64 *skipped_open,
+ u64 *skipped_need_journal_commit,
+ u64 *skipped_nouse,
struct closure *cl)
{
struct btree_iter iter;
@@ -369,10 +385,10 @@ bch2_bucket_alloc_trans_early(struct btree_trans *trans,
struct open_bucket *ob = NULL;
int ret;
- *b = max_t(u64, *b, ca->mi.first_bucket);
- *b = max_t(u64, *b, ca->new_fs_bucket_idx);
+ *cur_bucket = max_t(u64, *cur_bucket, ca->mi.first_bucket);
+ *cur_bucket = max_t(u64, *cur_bucket, ca->new_fs_bucket_idx);
- for_each_btree_key(trans, iter, BTREE_ID_alloc, POS(ca->dev_idx, *b),
+ for_each_btree_key(trans, iter, BTREE_ID_alloc, POS(ca->dev_idx, *cur_bucket),
BTREE_ITER_SLOTS, k, ret) {
struct bkey_alloc_unpacked a;
@@ -388,14 +404,19 @@ bch2_bucket_alloc_trans_early(struct btree_trans *trans,
if (bucket_state(a) != BUCKET_free)
continue;
+ (*buckets_seen)++;
+
ob = __try_alloc_bucket(trans->c, ca, reserve, a,
- need_journal_commit, cl);
+ skipped_open,
+ skipped_need_journal_commit,
+ skipped_nouse,
+ cl);
if (ob)
break;
}
bch2_trans_iter_exit(trans, &iter);
- *b = iter.pos.offset;
+ *cur_bucket = iter.pos.offset;
return ob ?: ERR_PTR(ret ?: -FREELIST_EMPTY);
}
@@ -403,8 +424,11 @@ bch2_bucket_alloc_trans_early(struct btree_trans *trans,
static struct open_bucket *bch2_bucket_alloc_trans(struct btree_trans *trans,
struct bch_dev *ca,
enum alloc_reserve reserve,
- u64 *b,
- size_t *need_journal_commit,
+ u64 *cur_bucket,
+ u64 *buckets_seen,
+ u64 *skipped_open,
+ u64 *skipped_need_journal_commit,
+ u64 *skipped_nouse,
struct closure *cl)
{
struct btree_iter iter;
@@ -413,26 +437,37 @@ static struct open_bucket *bch2_bucket_alloc_trans(struct btree_trans *trans,
int ret;
if (unlikely(!ca->mi.freespace_initialized))
- return bch2_bucket_alloc_trans_early(trans, ca, reserve, b,
- need_journal_commit, cl);
+ return bch2_bucket_alloc_trans_early(trans, ca, reserve,
+ cur_bucket,
+ buckets_seen,
+ skipped_open,
+ skipped_need_journal_commit,
+ skipped_nouse,
+ cl);
BUG_ON(ca->new_fs_bucket_idx);
for_each_btree_key(trans, iter, BTREE_ID_freespace,
- POS(ca->dev_idx, *b), 0, k, ret) {
+ POS(ca->dev_idx, *cur_bucket), 0, k, ret) {
if (k.k->p.inode != ca->dev_idx)
break;
- for (*b = max(*b, bkey_start_offset(k.k));
- *b != k.k->p.offset && !ob;
- (*b)++) {
+ for (*cur_bucket = max(*cur_bucket, bkey_start_offset(k.k));
+ *cur_bucket != k.k->p.offset && !ob;
+ (*cur_bucket)++) {
if (btree_trans_too_many_iters(trans)) {
ob = ERR_PTR(-EINTR);
break;
}
- ob = try_alloc_bucket(trans, ca, reserve, *b,
- need_journal_commit, cl);
+ (*buckets_seen)++;
+
+ ob = try_alloc_bucket(trans, ca, reserve,
+ *cur_bucket,
+ skipped_open,
+ skipped_need_journal_commit,
+ skipped_nouse,
+ cl);
}
if (ob)
break;
@@ -453,9 +488,12 @@ struct open_bucket *bch2_bucket_alloc(struct bch_fs *c, struct bch_dev *ca,
struct closure *cl)
{
struct open_bucket *ob = NULL;
- size_t need_journal_commit = 0;
u64 avail = dev_buckets_available(ca, reserve);
- u64 b = 0;
+ u64 cur_bucket = 0;
+ u64 buckets_seen = 0;
+ u64 skipped_open = 0;
+ u64 skipped_need_journal_commit = 0;
+ u64 skipped_nouse = 0;
int ret;
if (may_alloc_partial) {
@@ -483,19 +521,27 @@ again:
}
ret = bch2_trans_do(c, NULL, NULL, 0,
- PTR_ERR_OR_ZERO(ob = bch2_bucket_alloc_trans(&trans,
- ca, reserve, &b,
- &need_journal_commit, cl)));
-
- if (need_journal_commit * 2 > avail)
+ PTR_ERR_OR_ZERO(ob = bch2_bucket_alloc_trans(&trans, ca, reserve,
+ &cur_bucket,
+ &buckets_seen,
+ &skipped_open,
+ &skipped_need_journal_commit,
+ &skipped_nouse,
+ cl)));
+
+ if (skipped_need_journal_commit * 2 > avail)
bch2_journal_flush_async(&c->journal, NULL);
err:
if (!ob)
ob = ERR_PTR(ret ?: -FREELIST_EMPTY);
- if (ob == ERR_PTR(-FREELIST_EMPTY)) {
+ if (IS_ERR(ob)) {
trace_bucket_alloc_fail(ca, bch2_alloc_reserves[reserve], avail,
- need_journal_commit, cl == NULL);
+ buckets_seen,
+ skipped_open,
+ skipped_need_journal_commit,
+ skipped_nouse,
+ cl == NULL, PTR_ERR(ob));
atomic_long_inc(&c->bucket_alloc_fail);
}
diff --git a/libbcachefs/bcachefs.h b/libbcachefs/bcachefs.h
index a4ef9aab..9877037f 100644
--- a/libbcachefs/bcachefs.h
+++ b/libbcachefs/bcachefs.h
@@ -649,7 +649,7 @@ struct bch_fs {
struct mutex snapshot_table_lock;
struct work_struct snapshot_delete_work;
struct work_struct snapshot_wait_for_pagecache_and_delete_work;
- struct snapshot_id_list snapshots_unlinked;
+ snapshot_id_list snapshots_unlinked;
struct mutex snapshots_unlinked_lock;
/* BTREE CACHE */
diff --git a/libbcachefs/btree_iter.c b/libbcachefs/btree_iter.c
index 56c493c9..25d254ee 100644
--- a/libbcachefs/btree_iter.c
+++ b/libbcachefs/btree_iter.c
@@ -1686,6 +1686,7 @@ bch2_btree_path_make_mut(struct btree_trans *trans,
btree_trans_verify_sorted(trans);
}
+ path->should_be_locked = false;
return path;
}
@@ -1705,8 +1706,7 @@ bch2_btree_path_set_pos(struct btree_trans *trans,
path = bch2_btree_path_make_mut(trans, path, intent, ip);
- path->pos = new_pos;
- path->should_be_locked = false;
+ path->pos = new_pos;
bch2_btree_path_check_sort(trans, path, cmp);
@@ -1720,6 +1720,7 @@ bch2_btree_path_set_pos(struct btree_trans *trans,
l = btree_path_up_until_good_node(trans, path, cmp);
if (btree_path_node(path, l)) {
+ BUG_ON(!btree_node_locked(path, l));
/*
* We might have to skip over many keys, or just a few: try
* advancing the node iterator, and if we have to skip over too
@@ -1923,6 +1924,7 @@ struct btree_path *bch2_path_get(struct btree_trans *trans,
BUG_ON(trans->restarted);
btree_trans_verify_sorted(trans);
+ bch2_trans_verify_locks(trans);
trans_for_each_path_inorder(trans, path, i) {
if (__btree_path_cmp(path,
@@ -2114,6 +2116,7 @@ struct btree *bch2_btree_iter_next_node(struct btree_iter *iter)
btree_node_unlock(path, path->level);
path->l[path->level].b = BTREE_ITER_NO_NODE_UP;
path->level++;
+ btree_path_set_dirty(path, BTREE_ITER_NEED_TRAVERSE);
return NULL;
}
@@ -2121,6 +2124,7 @@ struct btree *bch2_btree_iter_next_node(struct btree_iter *iter)
__bch2_btree_path_unlock(path);
path->l[path->level].b = BTREE_ITER_NO_NODE_GET_LOCKS;
path->l[path->level + 1].b = BTREE_ITER_NO_NODE_GET_LOCKS;
+ btree_path_set_dirty(path, BTREE_ITER_NEED_TRAVERSE);
trace_trans_restart_relock_next_node(trans->fn, _THIS_IP_,
path->btree_id, &path->pos);
btree_trans_restart(trans);
@@ -3055,8 +3059,7 @@ void bch2_trans_begin(struct btree_trans *trans)
trans->mem_top = 0;
trans->hooks = NULL;
- trans->extra_journal_entries = NULL;
- trans->extra_journal_entry_u64s = 0;
+ trans->extra_journal_entries.nr = 0;
if (trans->fs_usage_deltas) {
trans->fs_usage_deltas->used = 0;
@@ -3189,6 +3192,8 @@ void bch2_trans_exit(struct btree_trans *trans)
bch2_journal_preres_put(&c->journal, &trans->journal_preres);
+ kfree(trans->extra_journal_entries.data);
+
if (trans->fs_usage_deltas) {
if (trans->fs_usage_deltas->size + sizeof(trans->fs_usage_deltas) ==
REPLICAS_DELTA_LIST_MAX)
diff --git a/libbcachefs/btree_types.h b/libbcachefs/btree_types.h
index 993f04f5..b86a721f 100644
--- a/libbcachefs/btree_types.h
+++ b/libbcachefs/btree_types.h
@@ -8,6 +8,7 @@
#include "bkey_methods.h"
#include "buckets_types.h"
+#include "darray.h"
#include "journal_types.h"
struct open_bucket;
@@ -417,8 +418,7 @@ struct btree_trans {
/* update path: */
struct btree_trans_commit_hook *hooks;
- struct jset_entry *extra_journal_entries;
- unsigned extra_journal_entry_u64s;
+ DARRAY(u64) extra_journal_entries;
struct journal_entry_pin *journal_pin;
struct journal_res journal_res;
diff --git a/libbcachefs/btree_update.h b/libbcachefs/btree_update.h
index ca142f95..ad13b073 100644
--- a/libbcachefs/btree_update.h
+++ b/libbcachefs/btree_update.h
@@ -80,6 +80,8 @@ void bch2_trans_commit_hook(struct btree_trans *,
struct btree_trans_commit_hook *);
int __bch2_trans_commit(struct btree_trans *);
+int bch2_trans_log_msg(struct btree_trans *, const char *);
+
/**
* bch2_trans_commit - insert keys at given iterator positions
*
diff --git a/libbcachefs/btree_update_interior.c b/libbcachefs/btree_update_interior.c
index c2232f81..42ae3b0c 100644
--- a/libbcachefs/btree_update_interior.c
+++ b/libbcachefs/btree_update_interior.c
@@ -532,8 +532,15 @@ static int btree_update_nodes_written_trans(struct btree_trans *trans,
struct bkey_i *k;
int ret;
- trans->extra_journal_entries = (void *) &as->journal_entries[0];
- trans->extra_journal_entry_u64s = as->journal_u64s;
+ ret = darray_make_room(trans->extra_journal_entries, as->journal_u64s);
+ if (ret)
+ return ret;
+
+ memcpy(&darray_top(trans->extra_journal_entries),
+ as->journal_entries,
+ as->journal_u64s * sizeof(u64));
+ trans->extra_journal_entries.nr += as->journal_u64s;
+
trans->journal_pin = &as->journal;
for_each_keylist_key(&as->new_keys, k) {
@@ -1899,7 +1906,6 @@ static int __bch2_btree_node_update_key(struct btree_trans *trans,
struct bch_fs *c = trans->c;
struct btree_iter iter2 = { NULL };
struct btree *parent;
- u64 journal_entries[BKEY_BTREE_PTR_U64s_MAX];
int ret;
if (!skip_triggers) {
@@ -1933,6 +1939,7 @@ static int __bch2_btree_node_update_key(struct btree_trans *trans,
btree_node_unlock(iter2.path, iter2.path->level);
path_l(iter2.path)->b = BTREE_ITER_NO_NODE_UP;
iter2.path->level++;
+ btree_path_set_dirty(iter2.path, BTREE_ITER_NEED_TRAVERSE);
bch2_btree_path_check_sort(trans, iter2.path, 0);
@@ -1943,12 +1950,16 @@ static int __bch2_btree_node_update_key(struct btree_trans *trans,
} else {
BUG_ON(btree_node_root(c, b) != b);
- trans->extra_journal_entries = (void *) &journal_entries[0];
- trans->extra_journal_entry_u64s =
- journal_entry_set((void *) &journal_entries[0],
- BCH_JSET_ENTRY_btree_root,
- b->c.btree_id, b->c.level,
- new_key, new_key->k.u64s);
+ ret = darray_make_room(trans->extra_journal_entries,
+ jset_u64s(new_key->k.u64s));
+ if (ret)
+ return ret;
+
+ journal_entry_set((void *) &darray_top(trans->extra_journal_entries),
+ BCH_JSET_ENTRY_btree_root,
+ b->c.btree_id, b->c.level,
+ new_key, new_key->k.u64s);
+ trans->extra_journal_entries.nr += jset_u64s(new_key->k.u64s);
}
ret = bch2_trans_commit(trans, NULL, NULL,
diff --git a/libbcachefs/btree_update_leaf.c b/libbcachefs/btree_update_leaf.c
index 8d185c7c..6f4ee55e 100644
--- a/libbcachefs/btree_update_leaf.c
+++ b/libbcachefs/btree_update_leaf.c
@@ -700,13 +700,13 @@ bch2_trans_commit_write_locked(struct btree_trans *trans,
trans->journal_res.seq = c->journal.replay_journal_seq;
}
- if (unlikely(trans->extra_journal_entry_u64s)) {
+ if (unlikely(trans->extra_journal_entries.nr)) {
memcpy_u64s_small(journal_res_entry(&c->journal, &trans->journal_res),
- trans->extra_journal_entries,
- trans->extra_journal_entry_u64s);
+ trans->extra_journal_entries.data,
+ trans->extra_journal_entries.nr);
- trans->journal_res.offset += trans->extra_journal_entry_u64s;
- trans->journal_res.u64s -= trans->extra_journal_entry_u64s;
+ trans->journal_res.offset += trans->extra_journal_entries.nr;
+ trans->journal_res.u64s -= trans->extra_journal_entries.nr;
}
/*
@@ -1088,7 +1088,7 @@ int __bch2_trans_commit(struct btree_trans *trans)
int ret = 0;
if (!trans->nr_updates &&
- !trans->extra_journal_entry_u64s)
+ !trans->extra_journal_entries.nr)
goto out_reset;
if (trans->flags & BTREE_INSERT_GC_LOCK_HELD)
@@ -1112,7 +1112,7 @@ int __bch2_trans_commit(struct btree_trans *trans)
memset(&trans->journal_preres, 0, sizeof(trans->journal_preres));
- trans->journal_u64s = trans->extra_journal_entry_u64s;
+ trans->journal_u64s = trans->extra_journal_entries.nr;
trans->journal_preres_u64s = 0;
trans->journal_transaction_names = READ_ONCE(c->opts.journal_transaction_names);
@@ -1170,8 +1170,7 @@ out_reset:
trans->extra_journal_res = 0;
trans->nr_updates = 0;
trans->hooks = NULL;
- trans->extra_journal_entries = NULL;
- trans->extra_journal_entry_u64s = 0;
+ trans->extra_journal_entries.nr = 0;
if (trans->fs_usage_deltas) {
trans->fs_usage_deltas->used = 0;
@@ -1739,3 +1738,30 @@ int bch2_btree_delete_range(struct bch_fs *c, enum btree_id id,
bch2_btree_delete_range_trans(&trans, id, start, end,
update_flags, journal_seq));
}
+
+int bch2_trans_log_msg(struct btree_trans *trans, const char *msg)
+{
+ unsigned len = strlen(msg);
+ unsigned u64s = DIV_ROUND_UP(len, sizeof(u64));
+ struct jset_entry_log *l;
+ int ret;
+
+ ret = darray_make_room(trans->extra_journal_entries, jset_u64s(u64s));
+ if (ret)
+ return ret;
+
+ l = (void *) &darray_top(trans->extra_journal_entries);
+ l->entry.u64s = cpu_to_le16(u64s);
+ l->entry.btree_id = 0;
+ l->entry.level = 1;
+ l->entry.type = BCH_JSET_ENTRY_log;
+ l->entry.pad[0] = 0;
+ l->entry.pad[1] = 0;
+ l->entry.pad[2] = 0;
+ memcpy(l->d, msg, len);
+ while (len & 7)
+ l->d[len++] = '\0';
+
+ trans->extra_journal_entries.nr += jset_u64s(u64s);
+ return 0;
+}
diff --git a/libbcachefs/darray.h b/libbcachefs/darray.h
new file mode 100644
index 00000000..745b1cdb
--- /dev/null
+++ b/libbcachefs/darray.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _BCACHEFS_DARRAY_H
+#define _BCACHEFS_DARRAY_H
+
+/*
+ * Dynamic arrays:
+ *
+ * Inspired by CCAN's darray
+ */
+
+#include "util.h"
+#include <linux/slab.h>
+
+#define DARRAY(type) \
+struct { \
+ size_t nr, size; \
+ type *data; \
+}
+
+typedef DARRAY(void) darray_void;
+
+static inline int __darray_make_room(darray_void *d, size_t t_size, size_t more)
+{
+ if (d->nr + more > d->size) {
+ size_t new_size = roundup_pow_of_two(d->nr + more);
+ void *data = krealloc_array(d->data, new_size, t_size, GFP_KERNEL);
+
+ if (!data)
+ return -ENOMEM;
+
+ d->data = data;
+ d->size = new_size;
+ }
+
+ return 0;
+}
+
+#define darray_make_room(_d, _more) \
+ __darray_make_room((darray_void *) &(_d), sizeof((_d).data[0]), (_more))
+
+#define darray_top(_d) ((_d).data[(_d).nr])
+
+#define darray_push(_d, _item) \
+({ \
+ int _ret = darray_make_room((_d), 1); \
+ \
+ if (!_ret) \
+ (_d).data[(_d).nr++] = (_item); \
+ _ret; \
+})
+
+#define darray_insert_item(_d, _pos, _item) \
+({ \
+ int _ret = darray_make_room((_d), 1); \
+ \
+ if (!_ret) \
+ array_insert_item((_d).data, (_d).nr, (_pos), (_item)); \
+ _ret; \
+})
+
+#define darray_for_each(_d, _i) \
+ for (_i = (_d).data; _i < (_d).data + (_d).nr; _i++)
+
+#define darray_init(_d) \
+do { \
+ (_d).data = NULL; \
+ (_d).nr = (_d).size = 0; \
+} while (0)
+
+#define darray_exit(_d) \
+do { \
+ kfree((_d).data); \
+ darray_init(_d); \
+} while (0)
+
+#endif /* _BCACHEFS_DARRAY_H */
diff --git a/libbcachefs/fs.c b/libbcachefs/fs.c
index 9fc6c39e..d462c068 100644
--- a/libbcachefs/fs.c
+++ b/libbcachefs/fs.c
@@ -1477,7 +1477,7 @@ static void bch2_evict_inode(struct inode *vinode)
}
void bch2_evict_subvolume_inodes(struct bch_fs *c,
- struct snapshot_id_list *s)
+ snapshot_id_list *s)
{
struct super_block *sb = c->vfs_sb;
struct inode *inode;
diff --git a/libbcachefs/fs.h b/libbcachefs/fs.h
index b2211ec7..9f4b57e3 100644
--- a/libbcachefs/fs.h
+++ b/libbcachefs/fs.h
@@ -191,7 +191,7 @@ int bch2_setattr_nonsize(struct user_namespace *,
struct iattr *);
int __bch2_unlink(struct inode *, struct dentry *, bool);
-void bch2_evict_subvolume_inodes(struct bch_fs *, struct snapshot_id_list *);
+void bch2_evict_subvolume_inodes(struct bch_fs *, snapshot_id_list *);
void bch2_vfs_exit(void);
int bch2_vfs_init(void);
@@ -199,7 +199,7 @@ int bch2_vfs_init(void);
#else
static inline void bch2_evict_subvolume_inodes(struct bch_fs *c,
- struct snapshot_id_list *s) {}
+ snapshot_id_list *s) {}
static inline void bch2_vfs_exit(void) {}
static inline int bch2_vfs_init(void) { return 0; }
diff --git a/libbcachefs/fsck.c b/libbcachefs/fsck.c
index 8783b950..2582ddf1 100644
--- a/libbcachefs/fsck.c
+++ b/libbcachefs/fsck.c
@@ -3,6 +3,7 @@
#include "bcachefs.h"
#include "bkey_buf.h"
#include "btree_update.h"
+#include "darray.h"
#include "dirent.h"
#include "error.h"
#include "fs-common.h"
@@ -471,11 +472,11 @@ static int snapshots_seen_update(struct bch_fs *c, struct snapshots_seen *s, str
pos.snapshot = snapshot_t(c, pos.snapshot)->equiv;
if (bkey_cmp(s->pos, pos))
- s->nr = 0;
+ s->ids.nr = 0;
s->pos = pos;
/* Might get called multiple times due to lock restarts */
- if (s->nr && s->d[s->nr - 1] == pos.snapshot)
+ if (s->ids.nr && s->ids.data[s->ids.nr - 1] == pos.snapshot)
return 0;
return snapshots_seen_add(c, s, pos.snapshot);
@@ -498,7 +499,7 @@ static bool key_visible_in_snapshot(struct bch_fs *c, struct snapshots_seen *see
ancestor = snapshot_t(c, ancestor)->equiv;
/* @ancestor should be the snapshot most recently added to @seen */
- BUG_ON(!seen->nr || seen->d[seen->nr - 1] != ancestor);
+ BUG_ON(!seen->ids.nr || seen->ids.data[seen->ids.nr - 1] != ancestor);
BUG_ON(seen->pos.snapshot != ancestor);
if (id == ancestor)
@@ -507,11 +508,11 @@ static bool key_visible_in_snapshot(struct bch_fs *c, struct snapshots_seen *see
if (!bch2_snapshot_is_ancestor(c, id, ancestor))
return false;
- for (i = seen->nr - 2;
- i >= 0 && seen->d[i] >= id;
+ for (i = seen->ids.nr - 2;
+ i >= 0 && seen->ids.data[i] >= id;
--i)
- if (bch2_snapshot_is_ancestor(c, id, seen->d[i]) &&
- bch2_snapshot_is_ancestor(c, seen->d[i], ancestor))
+ if (bch2_snapshot_is_ancestor(c, id, seen->ids.data[i]) &&
+ bch2_snapshot_is_ancestor(c, seen->ids.data[i], ancestor))
return false;
return true;
@@ -537,26 +538,25 @@ static int ref_visible(struct bch_fs *c, struct snapshots_seen *s,
}
#define for_each_visible_inode(_c, _s, _w, _snapshot, _i) \
- for (_i = (_w)->d; _i < (_w)->d + (_w)->nr && (_i)->snapshot <= (_snapshot); _i++)\
+ for (_i = (_w)->inodes.data; _i < (_w)->inodes.data + (_w)->inodes.nr && (_i)->snapshot <= (_snapshot); _i++)\
if (key_visible_in_snapshot(_c, _s, _i->snapshot, _snapshot))
+struct inode_walker_entry {
+ struct bch_inode_unpacked inode;
+ u32 snapshot;
+ u64 count;
+};
+
struct inode_walker {
bool first_this_inode;
u64 cur_inum;
- size_t nr;
- size_t size;
- struct inode_walker_entry {
- struct bch_inode_unpacked inode;
- u32 snapshot;
- u64 count;
- } *d;
+ DARRAY(struct inode_walker_entry) inodes;
};
static void inode_walker_exit(struct inode_walker *w)
{
- kfree(w->d);
- w->d = NULL;
+ darray_exit(w->inodes);
}
static struct inode_walker inode_walker_init(void)
@@ -564,43 +564,17 @@ static struct inode_walker inode_walker_init(void)
return (struct inode_walker) { 0, };
}
-static int inode_walker_realloc(struct bch_fs *c, struct inode_walker *w)
-{
- if (w->nr == w->size) {
- size_t new_size = max_t(size_t, 8UL, w->size * 2);
- void *d = krealloc(w->d, new_size * sizeof(w->d[0]),
- GFP_KERNEL);
- if (!d) {
- bch_err(c, "fsck: error allocating memory for inode_walker, size %zu",
- new_size);
- return -ENOMEM;
- }
-
- w->d = d;
- w->size = new_size;
- }
-
- return 0;
-}
-
static int add_inode(struct bch_fs *c, struct inode_walker *w,
struct bkey_s_c inode)
{
struct bch_inode_unpacked u;
- int ret;
-
- ret = inode_walker_realloc(c, w);
- if (ret)
- return ret;
BUG_ON(bch2_inode_unpack(inode, &u));
- w->d[w->nr++] = (struct inode_walker_entry) {
+ return darray_push(w->inodes, ((struct inode_walker_entry) {
.inode = u,
.snapshot = snapshot_t(c, inode.k->p.snapshot)->equiv,
- };
-
- return 0;
+ }));
}
static int __walk_inode(struct btree_trans *trans,
@@ -619,7 +593,7 @@ static int __walk_inode(struct btree_trans *trans,
goto lookup_snapshot;
}
- w->nr = 0;
+ w->inodes.nr = 0;
for_each_btree_key(trans, iter, BTREE_ID_inodes, POS(0, pos.inode),
BTREE_ITER_ALL_SNAPSHOTS, k, ret) {
@@ -637,26 +611,25 @@ static int __walk_inode(struct btree_trans *trans,
w->cur_inum = pos.inode;
w->first_this_inode = true;
lookup_snapshot:
- for (i = 0; i < w->nr; i++)
- if (bch2_snapshot_is_ancestor(c, pos.snapshot, w->d[i].snapshot))
+ for (i = 0; i < w->inodes.nr; i++)
+ if (bch2_snapshot_is_ancestor(c, pos.snapshot, w->inodes.data[i].snapshot))
goto found;
return INT_MAX;
found:
- BUG_ON(pos.snapshot > w->d[i].snapshot);
+ BUG_ON(pos.snapshot > w->inodes.data[i].snapshot);
- if (pos.snapshot != w->d[i].snapshot) {
+ if (pos.snapshot != w->inodes.data[i].snapshot) {
ancestor_pos = i;
- while (i && w->d[i - 1].snapshot > pos.snapshot)
+ while (i && w->inodes.data[i - 1].snapshot > pos.snapshot)
--i;
- ret = inode_walker_realloc(c, w);
+ ret = darray_insert_item(w->inodes, i, w->inodes.data[ancestor_pos]);
if (ret)
return ret;
- array_insert_item(w->d, w->nr, i, w->d[ancestor_pos]);
- w->d[i].snapshot = pos.snapshot;
- w->d[i].count = 0;
+ w->inodes.data[i].snapshot = pos.snapshot;
+ w->inodes.data[i].count = 0;
}
return i;
@@ -672,7 +645,7 @@ static int __get_visible_inodes(struct btree_trans *trans,
struct bkey_s_c k;
int ret;
- w->nr = 0;
+ w->inodes.nr = 0;
for_each_btree_key(trans, iter, BTREE_ID_inodes, POS(0, inum),
BTREE_ITER_ALL_SNAPSHOTS, k, ret) {
@@ -1133,7 +1106,7 @@ static int check_i_sectors(struct btree_trans *trans, struct inode_walker *w)
int ret = 0, ret2 = 0;
s64 count2;
- for (i = w->d; i < w->d + w->nr; i++) {
+ darray_for_each(w->inodes, i) {
if (i->inode.bi_sectors == i->count)
continue;
@@ -1232,7 +1205,7 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
goto out;
}
- i = inode->d + ret;
+ i = inode->inodes.data + ret;
ret = 0;
if (fsck_err_on(!S_ISREG(i->inode.bi_mode) &&
@@ -1333,7 +1306,7 @@ static int check_subdir_count(struct btree_trans *trans, struct inode_walker *w)
int ret = 0, ret2 = 0;
s64 count2;
- for (i = w->d; i < w->d + w->nr; i++) {
+ darray_for_each(w->inodes, i) {
if (i->inode.bi_nlink == i->count)
continue;
@@ -1537,7 +1510,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
goto out;
}
- i = dir->d + ret;
+ i = dir->inodes.data + ret;
ret = 0;
if (fsck_err_on(!S_ISDIR(i->inode.bi_mode), c,
@@ -1550,7 +1523,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
}
if (dir->first_this_inode)
- *hash_info = bch2_hash_info_init(c, &dir->d[0].inode);
+ *hash_info = bch2_hash_info_init(c, &dir->inodes.data[0].inode);
ret = hash_check_key(trans, bch2_dirent_hash_desc,
hash_info, iter, k);
@@ -1618,7 +1591,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
if (ret)
goto err;
- if (fsck_err_on(!target->nr, c,
+ if (fsck_err_on(!target->inodes.nr, c,
"dirent points to missing inode:\n%s",
(printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k),
@@ -1628,7 +1601,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
goto err;
}
- for (i = target->d; i < target->d + target->nr; i++) {
+ darray_for_each(target->inodes, i) {
ret = check_dirent_target(trans, iter, d,
&i->inode, i->snapshot);
if (ret)
@@ -1726,7 +1699,7 @@ static int check_xattr(struct btree_trans *trans, struct btree_iter *iter,
ret = 0;
if (inode->first_this_inode)
- *hash_info = bch2_hash_info_init(c, &inode->d[0].inode);
+ *hash_info = bch2_hash_info_init(c, &inode->inodes.data[0].inode);
ret = hash_check_key(trans, bch2_xattr_hash_desc, hash_info, iter, k);
fsck_err:
@@ -1836,21 +1809,18 @@ static int check_root(struct bch_fs *c)
check_root_trans(&trans));
}
-struct pathbuf {
- size_t nr;
- size_t size;
-
- struct pathbuf_entry {
- u64 inum;
- u32 snapshot;
- } *entries;
+struct pathbuf_entry {
+ u64 inum;
+ u32 snapshot;
};
-static bool path_is_dup(struct pathbuf *p, u64 inum, u32 snapshot)
+typedef DARRAY(struct pathbuf_entry) pathbuf;
+
+static bool path_is_dup(pathbuf *p, u64 inum, u32 snapshot)
{
struct pathbuf_entry *i;
- for (i = p->entries; i < p->entries + p->nr; i++)
+ darray_for_each(*p, i)
if (i->inum == inum &&
i->snapshot == snapshot)
return true;
@@ -1858,29 +1828,18 @@ static bool path_is_dup(struct pathbuf *p, u64 inum, u32 snapshot)
return false;
}
-static int path_down(struct bch_fs *c, struct pathbuf *p,
+static int path_down(struct bch_fs *c, pathbuf *p,
u64 inum, u32 snapshot)
{
- if (p->nr == p->size) {
- size_t new_size = max_t(size_t, 256UL, p->size * 2);
- void *n = krealloc(p->entries,
- new_size * sizeof(p->entries[0]),
- GFP_KERNEL);
- if (!n) {
- bch_err(c, "fsck: error allocating memory for pathbuf, size %zu",
- new_size);
- return -ENOMEM;
- }
-
- p->entries = n;
- p->size = new_size;
- };
-
- p->entries[p->nr++] = (struct pathbuf_entry) {
+ int ret = darray_push(*p, ((struct pathbuf_entry) {
.inum = inum,
.snapshot = snapshot,
- };
- return 0;
+ }));
+
+ if (ret)
+ bch_err(c, "fsck: error allocating memory for pathbuf, size %zu",
+ p->size);
+ return ret;
}
/*
@@ -1889,7 +1848,7 @@ static int path_down(struct bch_fs *c, struct pathbuf *p,
* XXX: we should also be verifying that inodes are in the right subvolumes
*/
static int check_path(struct btree_trans *trans,
- struct pathbuf *p,
+ pathbuf *p,
struct bch_inode_unpacked *inode,
u32 snapshot)
{
@@ -1963,7 +1922,7 @@ static int check_path(struct btree_trans *trans,
/* XXX print path */
bch_err(c, "directory structure loop");
- for (i = p->entries; i < p->entries + p->nr; i++)
+ darray_for_each(*p, i)
pr_err("%llu:%u", i->inum, i->snapshot);
pr_err("%llu:%u", inode->bi_inum, snapshot);
@@ -2000,7 +1959,7 @@ static int check_directory_structure(struct bch_fs *c)
struct btree_iter iter;
struct bkey_s_c k;
struct bch_inode_unpacked u;
- struct pathbuf path = { 0, 0, NULL };
+ pathbuf path = { 0, };
int ret;
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
@@ -2030,7 +1989,7 @@ static int check_directory_structure(struct bch_fs *c)
BUG_ON(ret == -EINTR);
- kfree(path.entries);
+ darray_exit(path);
bch2_trans_exit(&trans);
return ret;
diff --git a/libbcachefs/move.c b/libbcachefs/move.c
index 8eb49381..1de21350 100644
--- a/libbcachefs/move.c
+++ b/libbcachefs/move.c
@@ -92,10 +92,10 @@ next:
if (bch2_snapshot_is_ancestor(c, k.k->p.snapshot, old_pos.snapshot)) {
struct bkey_i *update;
- size_t i;
+ u32 *i;
- for (i = 0; i < s.nr; i++)
- if (bch2_snapshot_is_ancestor(c, k.k->p.snapshot, s.d[i]))
+ darray_for_each(s.ids, i)
+ if (bch2_snapshot_is_ancestor(c, k.k->p.snapshot, *i))
goto next;
update = bch2_trans_kmalloc(trans, sizeof(struct bkey_i));
@@ -125,7 +125,7 @@ next:
}
}
bch2_trans_iter_exit(trans, &iter);
- kfree(s.d);
+ darray_exit(s.ids);
return ret;
}
diff --git a/libbcachefs/subvolume.c b/libbcachefs/subvolume.c
index 666f1c88..cdb89ba2 100644
--- a/libbcachefs/subvolume.c
+++ b/libbcachefs/subvolume.c
@@ -545,36 +545,21 @@ err:
return ret;
}
-static int snapshot_id_add(struct snapshot_id_list *s, u32 id)
+static int snapshot_id_add(snapshot_id_list *s, u32 id)
{
BUG_ON(snapshot_list_has_id(s, id));
- if (s->nr == s->size) {
- size_t new_size = max(8U, s->size * 2);
- void *n = krealloc(s->d,
- new_size * sizeof(s->d[0]),
- GFP_KERNEL);
- if (!n) {
- pr_err("error allocating snapshot ID list");
- return -ENOMEM;
- }
-
- s->d = n;
- s->size = new_size;
- };
-
- s->d[s->nr++] = id;
- return 0;
+ return darray_push(*s, id);
}
static int bch2_snapshot_delete_keys_btree(struct btree_trans *trans,
- struct snapshot_id_list *deleted,
+ snapshot_id_list *deleted,
enum btree_id btree_id)
{
struct bch_fs *c = trans->c;
struct btree_iter iter;
struct bkey_s_c k;
- struct snapshot_id_list equiv_seen = { 0 };
+ snapshot_id_list equiv_seen = { 0 };
struct bpos last_pos = POS_MIN;
int ret = 0;
@@ -621,7 +606,7 @@ static int bch2_snapshot_delete_keys_btree(struct btree_trans *trans,
}
bch2_trans_iter_exit(trans, &iter);
- kfree(equiv_seen.d);
+ darray_exit(equiv_seen);
return ret;
}
@@ -633,7 +618,7 @@ static void bch2_delete_dead_snapshots_work(struct work_struct *work)
struct btree_iter iter;
struct bkey_s_c k;
struct bkey_s_c_snapshot snap;
- struct snapshot_id_list deleted = { 0 };
+ snapshot_id_list deleted = { 0 };
u32 i, id, children[2];
int ret = 0;
@@ -713,15 +698,15 @@ static void bch2_delete_dead_snapshots_work(struct work_struct *work)
for (i = 0; i < deleted.nr; i++) {
ret = __bch2_trans_do(&trans, NULL, NULL, 0,
- bch2_snapshot_node_delete(&trans, deleted.d[i]));
+ bch2_snapshot_node_delete(&trans, deleted.data[i]));
if (ret) {
bch_err(c, "error deleting snapshot %u: %i",
- deleted.d[i], ret);
+ deleted.data[i], ret);
goto err;
}
}
err:
- kfree(deleted.d);
+ darray_exit(deleted);
bch2_trans_exit(&trans);
percpu_ref_put(&c->writes);
}
@@ -876,14 +861,14 @@ void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
{
struct bch_fs *c = container_of(work, struct bch_fs,
snapshot_wait_for_pagecache_and_delete_work);
- struct snapshot_id_list s;
+ snapshot_id_list s;
u32 *id;
int ret = 0;
while (!ret) {
mutex_lock(&c->snapshots_unlinked_lock);
s = c->snapshots_unlinked;
- memset(&c->snapshots_unlinked, 0, sizeof(c->snapshots_unlinked));
+ darray_init(c->snapshots_unlinked);
mutex_unlock(&c->snapshots_unlinked_lock);
if (!s.nr)
@@ -891,7 +876,7 @@ void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
bch2_evict_subvolume_inodes(c, &s);
- for (id = s.d; id < s.d + s.nr; id++) {
+ for (id = s.data; id < s.data + s.nr; id++) {
ret = bch2_trans_do(c, NULL, NULL, BTREE_INSERT_NOFAIL,
bch2_subvolume_delete(&trans, *id));
if (ret) {
@@ -900,7 +885,7 @@ void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
}
}
- kfree(s.d);
+ darray_exit(s);
}
percpu_ref_put(&c->writes);
diff --git a/libbcachefs/subvolume.h b/libbcachefs/subvolume.h
index 4abe53df..f609291a 100644
--- a/libbcachefs/subvolume.h
+++ b/libbcachefs/subvolume.h
@@ -2,6 +2,7 @@
#ifndef _BCACHEFS_SUBVOLUME_H
#define _BCACHEFS_SUBVOLUME_H
+#include "darray.h"
#include "subvolume_types.h"
void bch2_snapshot_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
@@ -58,15 +59,13 @@ static inline bool bch2_snapshot_is_ancestor(struct bch_fs *c, u32 id, u32 ances
struct snapshots_seen {
struct bpos pos;
- size_t nr;
- size_t size;
- u32 *d;
+ DARRAY(u32) ids;
};
static inline void snapshots_seen_exit(struct snapshots_seen *s)
{
- kfree(s->d);
- s->d = NULL;
+ kfree(s->ids.data);
+ s->ids.data = NULL;
}
static inline void snapshots_seen_init(struct snapshots_seen *s)
@@ -76,30 +75,19 @@ static inline void snapshots_seen_init(struct snapshots_seen *s)
static inline int snapshots_seen_add(struct bch_fs *c, struct snapshots_seen *s, u32 id)
{
- if (s->nr == s->size) {
- size_t new_size = max(s->size, (size_t) 128) * 2;
- u32 *d = krealloc(s->d, new_size * sizeof(s->d[0]), GFP_KERNEL);
-
- if (!d) {
- bch_err(c, "error reallocating snapshots_seen table (new size %zu)",
- new_size);
- return -ENOMEM;
- }
-
- s->size = new_size;
- s->d = d;
- }
-
- s->d[s->nr++] = id;
- return 0;
+ int ret = darray_push(s->ids, id);
+ if (ret)
+ bch_err(c, "error reallocating snapshots_seen table (size %zu)",
+ s->ids.size);
+ return ret;
}
-static inline bool snapshot_list_has_id(struct snapshot_id_list *s, u32 id)
+static inline bool snapshot_list_has_id(snapshot_id_list *s, u32 id)
{
- unsigned i;
+ u32 *i;
- for (i = 0; i < s->nr; i++)
- if (id == s->d[i])
+ darray_for_each(*s, i)
+ if (*i == id)
return true;
return false;
}
diff --git a/libbcachefs/subvolume_types.h b/libbcachefs/subvolume_types.h
index 9410b958..f7562b5d 100644
--- a/libbcachefs/subvolume_types.h
+++ b/libbcachefs/subvolume_types.h
@@ -2,10 +2,8 @@
#ifndef _BCACHEFS_SUBVOLUME_TYPES_H
#define _BCACHEFS_SUBVOLUME_TYPES_H
-struct snapshot_id_list {
- u32 nr;
- u32 size;
- u32 *d;
-};
+#include "darray.h"
+
+typedef DARRAY(u32) snapshot_id_list;
#endif /* _BCACHEFS_SUBVOLUME_TYPES_H */