summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/bcachefs/alloc_background.c64
-rw-r--r--fs/bcachefs/backpointers.c28
-rw-r--r--fs/bcachefs/bcachefs.h4
-rw-r--r--fs/bcachefs/btree_cache.c2
-rw-r--r--fs/bcachefs/btree_cache.h8
-rw-r--r--fs/bcachefs/btree_gc.c35
-rw-r--r--fs/bcachefs/btree_iter.c4
-rw-r--r--fs/bcachefs/btree_key_cache.c1
-rw-r--r--fs/bcachefs/btree_types.h18
-rw-r--r--fs/bcachefs/btree_update.c6
-rw-r--r--fs/bcachefs/btree_update_interior.c8
-rw-r--r--fs/bcachefs/dirent.c17
-rw-r--r--fs/bcachefs/fsck.c31
-rw-r--r--fs/bcachefs/inode.c7
-rw-r--r--fs/bcachefs/io_misc.c14
-rw-r--r--fs/bcachefs/logged_ops.h2
-rw-r--r--fs/bcachefs/namei.c11
-rw-r--r--fs/bcachefs/sb-errors_format.h4
-rw-r--r--fs/bcachefs/super-io.c37
-rw-r--r--fs/bcachefs/super.c1
-rw-r--r--include/linux/workqueue.h12
-rw-r--r--kernel/workqueue.c14
22 files changed, 205 insertions, 123 deletions
diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c
index 7db904c7a7e8..3fc728efbf5c 100644
--- a/fs/bcachefs/alloc_background.c
+++ b/fs/bcachefs/alloc_background.c
@@ -2104,44 +2104,46 @@ static int invalidate_one_bucket(struct btree_trans *trans,
if (bch2_bucket_is_open_safe(c, bucket.inode, bucket.offset))
return 0;
- CLASS(btree_iter, alloc_iter)(trans, BTREE_ID_alloc, bucket, BTREE_ITER_cached);
- struct bkey_s_c alloc_k = bch2_btree_iter_peek_slot(&alloc_iter);
- ret = bkey_err(alloc_k);
- if (ret)
- return ret;
+ {
+ CLASS(btree_iter, alloc_iter)(trans, BTREE_ID_alloc, bucket, BTREE_ITER_cached);
+ struct bkey_s_c alloc_k = bch2_btree_iter_peek_slot(&alloc_iter);
+ ret = bkey_err(alloc_k);
+ if (ret)
+ return ret;
- struct bch_alloc_v4 a_convert;
- const struct bch_alloc_v4 *a = bch2_alloc_to_v4(alloc_k, &a_convert);
+ struct bch_alloc_v4 a_convert;
+ const struct bch_alloc_v4 *a = bch2_alloc_to_v4(alloc_k, &a_convert);
- /* We expect harmless races here due to the btree write buffer: */
- if (lru_pos_time(lru_iter->pos) != alloc_lru_idx_read(*a))
- return 0;
+ /* We expect harmless races here due to the btree write buffer: */
+ if (lru_pos_time(lru_iter->pos) != alloc_lru_idx_read(*a))
+ return 0;
- /*
- * Impossible since alloc_lru_idx_read() only returns nonzero if the
- * bucket is supposed to be on the cached bucket LRU (i.e.
- * BCH_DATA_cached)
- *
- * bch2_lru_validate() also disallows lru keys with lru_pos_time() == 0
- */
- BUG_ON(a->data_type != BCH_DATA_cached);
- BUG_ON(a->dirty_sectors);
+ /*
+ * Impossible since alloc_lru_idx_read() only returns nonzero if the
+ * bucket is supposed to be on the cached bucket LRU (i.e.
+ * BCH_DATA_cached)
+ *
+ * bch2_lru_validate() also disallows lru keys with lru_pos_time() == 0
+ */
+ BUG_ON(a->data_type != BCH_DATA_cached);
+ BUG_ON(a->dirty_sectors);
- if (!a->cached_sectors) {
- bch2_check_bucket_backpointer_mismatch(trans, ca, bucket.offset,
- true, last_flushed);
- return 0;
- }
+ if (!a->cached_sectors) {
+ bch2_check_bucket_backpointer_mismatch(trans, ca, bucket.offset,
+ true, last_flushed);
+ return 0;
+ }
- unsigned cached_sectors = a->cached_sectors;
- u8 gen = a->gen;
+ unsigned cached_sectors = a->cached_sectors;
+ u8 gen = a->gen;
- ret = invalidate_one_bucket_by_bps(trans, ca, bucket, gen, last_flushed);
- if (ret)
- return ret;
+ ret = invalidate_one_bucket_by_bps(trans, ca, bucket, gen, last_flushed);
+ if (ret)
+ return ret;
- trace_and_count(c, bucket_invalidate, c, bucket.inode, bucket.offset, cached_sectors);
- --*nr_to_invalidate;
+ trace_and_count(c, bucket_invalidate, c, bucket.inode, bucket.offset, cached_sectors);
+ --*nr_to_invalidate;
+ }
fsck_err:
return ret;
}
diff --git a/fs/bcachefs/backpointers.c b/fs/bcachefs/backpointers.c
index 1aab9a63d0cb..45d3db41225a 100644
--- a/fs/bcachefs/backpointers.c
+++ b/fs/bcachefs/backpointers.c
@@ -395,22 +395,24 @@ static int bch2_check_backpointer_has_valid_bucket(struct btree_trans *trans, st
return ret;
}
- CLASS(btree_iter, alloc_iter)(trans, BTREE_ID_alloc, bucket, 0);
- struct bkey_s_c alloc_k = bch2_btree_iter_peek_slot(&alloc_iter);
- ret = bkey_err(alloc_k);
- if (ret)
- return ret;
-
- if (alloc_k.k->type != KEY_TYPE_alloc_v4) {
- ret = bch2_backpointers_maybe_flush(trans, k, last_flushed);
+ {
+ CLASS(btree_iter, alloc_iter)(trans, BTREE_ID_alloc, bucket, 0);
+ struct bkey_s_c alloc_k = bch2_btree_iter_peek_slot(&alloc_iter);
+ ret = bkey_err(alloc_k);
if (ret)
return ret;
- if (fsck_err(trans, backpointer_to_missing_alloc,
- "backpointer for nonexistent alloc key: %llu:%llu:0\n%s",
- alloc_iter.pos.inode, alloc_iter.pos.offset,
- (bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
- ret = bch2_backpointer_del(trans, k.k->p);
+ if (alloc_k.k->type != KEY_TYPE_alloc_v4) {
+ ret = bch2_backpointers_maybe_flush(trans, k, last_flushed);
+ if (ret)
+ return ret;
+
+ if (fsck_err(trans, backpointer_to_missing_alloc,
+ "backpointer for nonexistent alloc key: %llu:%llu:0\n%s",
+ alloc_iter.pos.inode, alloc_iter.pos.offset,
+ (bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
+ ret = bch2_backpointer_del(trans, k.k->p);
+ }
}
fsck_err:
return ret;
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h
index 45c15bdaa6f4..cdf593c59922 100644
--- a/fs/bcachefs/bcachefs.h
+++ b/fs/bcachefs/bcachefs.h
@@ -845,8 +845,8 @@ struct bch_fs {
unsigned long errors_silent[BITS_TO_LONGS(BCH_FSCK_ERR_MAX)];
u64 btrees_lost_data;
} sb;
- DARRAY(enum bcachefs_metadata_version)
- incompat_versions_requested;
+
+ unsigned long incompat_versions_requested[BITS_TO_LONGS(BCH_VERSION_MINOR(bcachefs_metadata_version_current))];
struct unicode_map *cf_encoding;
diff --git a/fs/bcachefs/btree_cache.c b/fs/bcachefs/btree_cache.c
index 25b01e750880..9261ad043564 100644
--- a/fs/bcachefs/btree_cache.c
+++ b/fs/bcachefs/btree_cache.c
@@ -215,7 +215,7 @@ void bch2_node_pin(struct bch_fs *c, struct btree *b)
struct btree_cache *bc = &c->btree_cache;
guard(mutex)(&bc->lock);
- if (b != btree_node_root(c, b) && !btree_node_pinned(b)) {
+ if (!btree_node_is_root(c, b) && !btree_node_pinned(b)) {
set_btree_node_pinned(b);
list_move(&b->list, &bc->live[1].list);
bc->live[0].nr--;
diff --git a/fs/bcachefs/btree_cache.h b/fs/bcachefs/btree_cache.h
index 649e9dfd178a..035b2cb25077 100644
--- a/fs/bcachefs/btree_cache.h
+++ b/fs/bcachefs/btree_cache.h
@@ -144,6 +144,14 @@ static inline struct btree *btree_node_root(struct bch_fs *c, struct btree *b)
return r ? r->b : NULL;
}
+static inline bool btree_node_is_root(struct bch_fs *c, struct btree *b)
+{
+ struct btree *root = btree_node_root(c, b);
+
+ BUG_ON(b != root && b->c.level >= root->c.level);
+ return b == root;
+}
+
const char *bch2_btree_id_str(enum btree_id); /* avoid */
void bch2_btree_id_to_text(struct printbuf *, enum btree_id);
void bch2_btree_id_level_to_text(struct printbuf *, enum btree_id, unsigned);
diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c
index ce3c7750a922..e27536d315b1 100644
--- a/fs/bcachefs/btree_gc.c
+++ b/fs/bcachefs/btree_gc.c
@@ -282,6 +282,38 @@ fsck_err:
return ret;
}
+static int btree_check_root_boundaries(struct btree_trans *trans, struct btree *b)
+{
+ struct bch_fs *c = trans->c;
+ struct printbuf buf = PRINTBUF;
+ int ret = 0;
+
+ BUG_ON(b->key.k.type == KEY_TYPE_btree_ptr_v2 &&
+ !bpos_eq(bkey_i_to_btree_ptr_v2(&b->key)->v.min_key,
+ b->data->min_key));
+
+ if (mustfix_fsck_err_on(!bpos_eq(b->data->min_key, POS_MIN),
+ trans, btree_node_topology_bad_root_min_key,
+ "btree root with incorrect min_key%s", buf.buf)) {
+ ret = set_node_min(c, b, POS_MIN);
+ if (ret)
+ goto err;
+ }
+
+ if (mustfix_fsck_err_on(!bpos_eq(b->data->max_key, SPOS_MAX),
+ trans, btree_node_topology_bad_root_max_key,
+ "btree root with incorrect min_key%s", buf.buf)) {
+ ret = set_node_max(c, b, SPOS_MAX);
+ if (ret)
+ goto err;
+ }
+
+err:
+fsck_err:
+ printbuf_exit(&buf);
+ return ret;
+}
+
static int btree_repair_node_end(struct btree_trans *trans, struct btree *b,
struct btree *child, struct bpos *pulled_from_scan)
{
@@ -586,7 +618,8 @@ recover:
struct btree *b = r->b;
btree_node_lock_nopath_nofail(trans, &b->c, SIX_LOCK_read);
- ret = bch2_btree_repair_topology_recurse(trans, b, &pulled_from_scan);
+ ret = btree_check_root_boundaries(trans, b) ?:
+ bch2_btree_repair_topology_recurse(trans, b, &pulled_from_scan);
six_unlock_read(&b->c.lock);
if (bch2_err_matches(ret, BCH_ERR_topology_repair_drop_this_node)) {
diff --git a/fs/bcachefs/btree_iter.c b/fs/bcachefs/btree_iter.c
index ff580f76a641..a67babf69d39 100644
--- a/fs/bcachefs/btree_iter.c
+++ b/fs/bcachefs/btree_iter.c
@@ -2451,7 +2451,7 @@ struct bkey_s_c bch2_btree_iter_peek_max(struct btree_iter *iter, struct bpos en
}
if (bkey_whiteout(k.k) &&
- !(iter->flags & BTREE_ITER_key_cache_fill)) {
+ !(iter->flags & BTREE_ITER_nofilter_whiteouts)) {
search_key = bkey_successor(iter, k.k->p);
continue;
}
@@ -2867,7 +2867,7 @@ struct bkey_s_c bch2_btree_iter_peek_slot(struct btree_iter *iter)
if (unlikely(k.k->type == KEY_TYPE_whiteout &&
(iter->flags & BTREE_ITER_filter_snapshots) &&
- !(iter->flags & BTREE_ITER_key_cache_fill)))
+ !(iter->flags & BTREE_ITER_nofilter_whiteouts)))
iter->k.type = KEY_TYPE_deleted;
} else {
struct bpos next;
diff --git a/fs/bcachefs/btree_key_cache.c b/fs/bcachefs/btree_key_cache.c
index d69cf9435872..e3336ab27ccc 100644
--- a/fs/bcachefs/btree_key_cache.c
+++ b/fs/bcachefs/btree_key_cache.c
@@ -326,6 +326,7 @@ static noinline int btree_key_cache_fill(struct btree_trans *trans,
CLASS(btree_iter, iter)(trans, ck_path->btree_id, ck_path->pos,
BTREE_ITER_intent|
+ BTREE_ITER_nofilter_whiteouts|
BTREE_ITER_key_cache_fill|
BTREE_ITER_cached_nofill);
iter.flags &= ~BTREE_ITER_with_journal;
diff --git a/fs/bcachefs/btree_types.h b/fs/bcachefs/btree_types.h
index ffa250008d91..e893eb938bb3 100644
--- a/fs/bcachefs/btree_types.h
+++ b/fs/bcachefs/btree_types.h
@@ -229,6 +229,7 @@ struct btree_node_iter {
x(snapshot_field) \
x(all_snapshots) \
x(filter_snapshots) \
+ x(nofilter_whiteouts) \
x(nopreserve) \
x(cached_nofill) \
x(key_cache_fill) \
@@ -839,15 +840,15 @@ static inline bool btree_node_type_has_triggers(enum btree_node_type type)
return BIT_ULL(type) & BTREE_NODE_TYPE_HAS_TRIGGERS;
}
-static inline bool btree_id_is_extents(enum btree_id btree)
-{
- const u64 mask = 0
+static const u64 btree_is_extents_mask = 0
#define x(name, nr, flags, ...) |((!!((flags) & BTREE_IS_extents)) << nr)
- BCH_BTREE_IDS()
+BCH_BTREE_IDS()
#undef x
- ;
+;
- return BIT_ULL(btree) & mask;
+static inline bool btree_id_is_extents(enum btree_id btree)
+{
+ return BIT_ULL(btree) & btree_is_extents_mask;
}
static inline bool btree_node_type_is_extents(enum btree_node_type type)
@@ -866,6 +867,11 @@ static inline bool btree_type_has_snapshots(enum btree_id btree)
return BIT_ULL(btree) & btree_has_snapshots_mask;
}
+static inline bool btree_id_is_extents_snapshots(enum btree_id btree)
+{
+ return BIT_ULL(btree) & btree_has_snapshots_mask & btree_is_extents_mask;
+}
+
static inline bool btree_type_has_snapshot_field(enum btree_id btree)
{
const u64 mask = 0
diff --git a/fs/bcachefs/btree_update.c b/fs/bcachefs/btree_update.c
index 566478728aa2..6f3b57573cba 100644
--- a/fs/bcachefs/btree_update.c
+++ b/fs/bcachefs/btree_update.c
@@ -215,7 +215,7 @@ int bch2_trans_update_extent_overwrite(struct btree_trans *trans,
return ret;
}
- if (bkey_le(old.k->p, new.k->p)) {
+ if (!back_split) {
update = bch2_trans_kmalloc(trans, sizeof(*update));
if ((ret = PTR_ERR_OR_ZERO(update)))
return ret;
@@ -238,9 +238,7 @@ int bch2_trans_update_extent_overwrite(struct btree_trans *trans,
BTREE_UPDATE_internal_snapshot_node|flags);
if (ret)
return ret;
- }
-
- if (back_split) {
+ } else {
update = bch2_bkey_make_mut_noupdate(trans, old);
if ((ret = PTR_ERR_OR_ZERO(update)))
return ret;
diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c
index 5f4f82967105..76897cf15946 100644
--- a/fs/bcachefs/btree_update_interior.c
+++ b/fs/bcachefs/btree_update_interior.c
@@ -66,6 +66,10 @@ int bch2_btree_node_check_topology(struct btree_trans *trans, struct btree *b)
bkey_init(&prev.k->k);
bch2_btree_and_journal_iter_init_node_iter(trans, &iter, b);
+ /*
+ * Don't use btree_node_is_root(): we're called by btree split, after
+ * creating a new root but before setting it
+ */
if (b == btree_node_root(c, b)) {
if (!bpos_eq(b->data->min_key, POS_MIN)) {
bch2_log_msg_start(c, &buf);
@@ -1655,7 +1659,7 @@ static int btree_split(struct btree_update *as, struct btree_trans *trans,
int ret = 0;
bch2_verify_btree_nr_keys(b);
- BUG_ON(!parent && (b != btree_node_root(c, b)));
+ BUG_ON(!parent && !btree_node_is_root(c, b));
BUG_ON(parent && !btree_node_intent_locked(trans->paths + path, b->c.level + 1));
ret = bch2_btree_node_check_topology(trans, b);
@@ -2527,7 +2531,7 @@ static int __bch2_btree_node_update_key(struct btree_trans *trans,
if (ret)
goto err;
} else {
- BUG_ON(btree_node_root(c, b) != b);
+ BUG_ON(!btree_node_is_root(c, b));
struct jset_entry *e = bch2_trans_jset_entry_alloc(trans,
jset_u64s(new_key->k.u64s));
diff --git a/fs/bcachefs/dirent.c b/fs/bcachefs/dirent.c
index 982d8ec17803..cb44b35e0f1d 100644
--- a/fs/bcachefs/dirent.c
+++ b/fs/bcachefs/dirent.c
@@ -740,21 +740,22 @@ found:
int bch2_fsck_remove_dirent(struct btree_trans *trans, struct bpos pos)
{
struct bch_fs *c = trans->c;
- struct bch_inode_unpacked dir_inode;
- struct bch_hash_info dir_hash_info;
+ struct bch_inode_unpacked dir_inode;
int ret = lookup_first_inode(trans, pos.inode, &dir_inode);
if (ret)
goto err;
- dir_hash_info = bch2_hash_info_init(c, &dir_inode);
+ {
+ struct bch_hash_info dir_hash_info = bch2_hash_info_init(c, &dir_inode);
- CLASS(btree_iter, iter)(trans, BTREE_ID_dirents, pos, BTREE_ITER_intent);
+ CLASS(btree_iter, iter)(trans, BTREE_ID_dirents, pos, BTREE_ITER_intent);
- ret = bch2_btree_iter_traverse(&iter) ?:
- bch2_hash_delete_at(trans, bch2_dirent_hash_desc,
- &dir_hash_info, &iter,
- BTREE_UPDATE_internal_snapshot_node);
+ ret = bch2_btree_iter_traverse(&iter) ?:
+ bch2_hash_delete_at(trans, bch2_dirent_hash_desc,
+ &dir_hash_info, &iter,
+ BTREE_UPDATE_internal_snapshot_node);
+ }
err:
bch_err_fn(c, ret);
return ret;
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
index d6fd25f1db1f..6ccea09243ab 100644
--- a/fs/bcachefs/fsck.c
+++ b/fs/bcachefs/fsck.c
@@ -923,9 +923,10 @@ lookup_inode_for_snapshot(struct btree_trans *trans, struct inode_walker *w, str
bkey_init(&whiteout.k);
whiteout.k.type = KEY_TYPE_whiteout;
whiteout.k.p = SPOS(0, i->inode.bi_inum, k.k->p.snapshot);
- ret = bch2_btree_insert_nonextent(trans, BTREE_ID_inodes,
- &whiteout,
- BTREE_UPDATE_internal_snapshot_node);
+ ret = bch2_btree_insert_trans(trans, BTREE_ID_inodes,
+ &whiteout,
+ BTREE_ITER_cached|
+ BTREE_UPDATE_internal_snapshot_node);
}
if (ret)
@@ -2121,6 +2122,7 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
struct bkey_s_c_dirent d)
{
struct bch_fs *c = trans->c;
+ struct btree_iter subvol_iter = {};
struct bch_inode_unpacked subvol_root;
u32 parent_subvol = le32_to_cpu(d.v->d_parent_subvol);
u32 target_subvol = le32_to_cpu(d.v->d_child_subvol);
@@ -2177,18 +2179,19 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
new_dirent->v.d_parent_subvol = cpu_to_le32(new_parent_subvol);
}
- CLASS(btree_iter, subvol_iter)(trans, BTREE_ID_subvolumes, POS(0, target_subvol), 0);
+ bch2_trans_iter_init(trans, &subvol_iter, BTREE_ID_subvolumes, POS(0, target_subvol), 0);
struct bkey_s_c_subvolume s = bch2_bkey_get_typed(&subvol_iter, subvolume);
ret = bkey_err(s.s_c);
if (ret && !bch2_err_matches(ret, ENOENT))
- return ret;
+ goto err;
if (ret) {
if (fsck_err(trans, dirent_to_missing_subvol,
"dirent points to missing subvolume\n%s",
(bch2_bkey_val_to_text(&buf, c, d.s_c), buf.buf)))
return bch2_fsck_remove_dirent(trans, d.k->p);
- return 0;
+ ret = 0;
+ goto out;
}
if (le32_to_cpu(s.v->fs_path_parent) != parent_subvol) {
@@ -2200,7 +2203,7 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
ret = bch2_inum_to_path(trans, (subvol_inum) { s.k->p.offset,
le64_to_cpu(s.v->inode) }, &buf);
if (ret)
- return ret;
+ goto err;
prt_newline(&buf);
bch2_bkey_val_to_text(&buf, c, s.s_c);
@@ -2209,7 +2212,7 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
bch2_bkey_make_mut_typed(trans, &subvol_iter, &s.s_c, 0, subvolume);
ret = PTR_ERR_OR_ZERO(n);
if (ret)
- return ret;
+ goto err;
n->v.fs_path_parent = cpu_to_le32(parent_subvol);
}
@@ -2221,11 +2224,12 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
ret = bch2_inode_find_by_inum_snapshot(trans, target_inum, target_snapshot,
&subvol_root, 0);
if (ret && !bch2_err_matches(ret, ENOENT))
- return ret;
+ goto err;
if (ret) {
bch_err(c, "subvol %u points to missing inode root %llu", target_subvol, target_inum);
- return bch_err_throw(c, fsck_repair_unimplemented);
+ ret = bch_err_throw(c, fsck_repair_unimplemented);
+ goto err;
}
if (fsck_err_on(!ret && parent_subvol != subvol_root.bi_parent_subvol,
@@ -2237,13 +2241,16 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
subvol_root.bi_snapshot = le32_to_cpu(s.v->snapshot);
ret = __bch2_fsck_write_inode(trans, &subvol_root);
if (ret)
- return ret;
+ goto err;
}
ret = bch2_check_dirent_target(trans, iter, d, &subvol_root, true);
if (ret)
- return ret;
+ goto err;
+out:
+err:
fsck_err:
+ bch2_trans_iter_exit(&subvol_iter);
return ret;
}
diff --git a/fs/bcachefs/inode.c b/fs/bcachefs/inode.c
index 85013e8d6166..d5e5190f0663 100644
--- a/fs/bcachefs/inode.c
+++ b/fs/bcachefs/inode.c
@@ -463,9 +463,10 @@ int __bch2_fsck_write_inode(struct btree_trans *trans, struct bch_inode_unpacked
bch2_inode_pack(inode_p, inode);
inode_p->inode.k.p.snapshot = inode->bi_snapshot;
- return bch2_btree_insert_nonextent(trans, BTREE_ID_inodes,
- &inode_p->inode.k_i,
- BTREE_UPDATE_internal_snapshot_node);
+ return bch2_btree_insert_trans(trans, BTREE_ID_inodes,
+ &inode_p->inode.k_i,
+ BTREE_ITER_cached|
+ BTREE_UPDATE_internal_snapshot_node);
}
int bch2_fsck_write_inode(struct btree_trans *trans, struct bch_inode_unpacked *inode)
diff --git a/fs/bcachefs/io_misc.c b/fs/bcachefs/io_misc.c
index 3f9defd144a4..fa0b06e17d17 100644
--- a/fs/bcachefs/io_misc.c
+++ b/fs/bcachefs/io_misc.c
@@ -274,13 +274,15 @@ static int __bch2_resume_logged_op_truncate(struct btree_trans *trans,
if (ret)
goto err;
- CLASS(btree_iter, fpunch_iter)(trans, BTREE_ID_extents,
- POS(inum.inum, round_up(new_i_size, block_bytes(c)) >> 9),
- BTREE_ITER_intent);
- ret = bch2_fpunch_at(trans, &fpunch_iter, inum, U64_MAX, i_sectors_delta);
+ {
+ CLASS(btree_iter, fpunch_iter)(trans, BTREE_ID_extents,
+ POS(inum.inum, round_up(new_i_size, block_bytes(c)) >> 9),
+ BTREE_ITER_intent);
+ ret = bch2_fpunch_at(trans, &fpunch_iter, inum, U64_MAX, i_sectors_delta);
- if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
- ret = 0;
+ if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
+ ret = 0;
+ }
err:
if (warn_errors)
bch_err_fn(c, ret);
diff --git a/fs/bcachefs/logged_ops.h b/fs/bcachefs/logged_ops.h
index 30ae9ef737dd..6dea6e2ac7a8 100644
--- a/fs/bcachefs/logged_ops.h
+++ b/fs/bcachefs/logged_ops.h
@@ -10,7 +10,7 @@
static inline int bch2_logged_op_update(struct btree_trans *trans, struct bkey_i *op)
{
- return bch2_btree_insert_nonextent(trans, BTREE_ID_logged_ops, op, 0);
+ return bch2_btree_insert_trans(trans, BTREE_ID_logged_ops, op, BTREE_ITER_cached);
}
int bch2_resume_logged_ops(struct bch_fs *);
diff --git a/fs/bcachefs/namei.c b/fs/bcachefs/namei.c
index da758c2767ea..d1019052f182 100644
--- a/fs/bcachefs/namei.c
+++ b/fs/bcachefs/namei.c
@@ -743,6 +743,7 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans,
{
struct bch_fs *c = trans->c;
CLASS(printbuf, buf)();
+ struct btree_iter bp_iter = {};
int ret = 0;
if (inode_points_to_dirent(target, d))
@@ -773,8 +774,8 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans,
return __bch2_fsck_write_inode(trans, target);
}
- CLASS(btree_iter, bp_iter)(trans, BTREE_ID_dirents,
- SPOS(target->bi_dir, target->bi_dir_offset, target->bi_snapshot), 0);
+ bch2_trans_iter_init(trans, &bp_iter, BTREE_ID_dirents,
+ SPOS(target->bi_dir, target->bi_dir_offset, target->bi_snapshot), 0);
struct bkey_s_c_dirent bp_dirent = bch2_bkey_get_typed(&bp_iter, dirent);
ret = bkey_err(bp_dirent);
if (ret && !bch2_err_matches(ret, ENOENT))
@@ -824,6 +825,8 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans,
S_ISDIR(target->bi_mode) ? "directory" : "subvolume",
target->bi_inum, target->bi_snapshot, buf.buf);
}
+
+ goto out;
} else {
/*
* hardlinked file with nlink 0:
@@ -837,11 +840,15 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans,
target->bi_nlink++;
target->bi_flags &= ~BCH_INODE_unlinked;
ret = __bch2_fsck_write_inode(trans, target);
+ if (ret)
+ goto err;
}
}
}
+out:
err:
fsck_err:
+ bch2_trans_iter_exit(&bp_iter);
bch_err_fn(c, ret);
return ret;
}
diff --git a/fs/bcachefs/sb-errors_format.h b/fs/bcachefs/sb-errors_format.h
index dd4ee46606d7..5317b1bfe2e5 100644
--- a/fs/bcachefs/sb-errors_format.h
+++ b/fs/bcachefs/sb-errors_format.h
@@ -76,6 +76,8 @@ enum bch_fsck_flags {
x(btree_node_read_error, 62, FSCK_AUTOFIX) \
x(btree_node_topology_bad_min_key, 63, FSCK_AUTOFIX) \
x(btree_node_topology_bad_max_key, 64, FSCK_AUTOFIX) \
+ x(btree_node_topology_bad_root_min_key, 323, FSCK_AUTOFIX) \
+ x(btree_node_topology_bad_root_max_key, 324, FSCK_AUTOFIX) \
x(btree_node_topology_overwritten_by_prev_node, 65, FSCK_AUTOFIX) \
x(btree_node_topology_overwritten_by_next_node, 66, FSCK_AUTOFIX) \
x(btree_node_topology_interior_node_empty, 67, FSCK_AUTOFIX) \
@@ -334,7 +336,7 @@ enum bch_fsck_flags {
x(dirent_stray_data_after_cf_name, 305, 0) \
x(rebalance_work_incorrectly_set, 309, FSCK_AUTOFIX) \
x(rebalance_work_incorrectly_unset, 310, FSCK_AUTOFIX) \
- x(MAX, 323, 0)
+ x(MAX, 325, 0)
enum bch_sb_error_id {
#define x(t, n, ...) BCH_FSCK_ERR_##t = n,
diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c
index c88759964575..be7ed612d28f 100644
--- a/fs/bcachefs/super-io.c
+++ b/fs/bcachefs/super-io.c
@@ -68,28 +68,33 @@ enum bcachefs_metadata_version bch2_latest_compatible_version(enum bcachefs_meta
int bch2_set_version_incompat(struct bch_fs *c, enum bcachefs_metadata_version version)
{
- guard(mutex)(&c->sb_lock);
-
if (((c->sb.features & BIT_ULL(BCH_FEATURE_incompat_version_field)) &&
version <= c->sb.version_incompat_allowed)) {
- SET_BCH_SB_VERSION_INCOMPAT(c->disk_sb.sb,
- max(BCH_SB_VERSION_INCOMPAT(c->disk_sb.sb), version));
- bch2_write_super(c);
+ guard(mutex)(&c->sb_lock);
+
+ if (version > c->sb.version_incompat) {
+ SET_BCH_SB_VERSION_INCOMPAT(c->disk_sb.sb,
+ max(BCH_SB_VERSION_INCOMPAT(c->disk_sb.sb), version));
+ bch2_write_super(c);
+ }
return 0;
} else {
- darray_for_each(c->incompat_versions_requested, i)
- if (version == *i)
- return bch_err_throw(c, may_not_use_incompat_feature);
+ BUILD_BUG_ON(BCH_VERSION_MAJOR(bcachefs_metadata_version_current) != 1);
- darray_push(&c->incompat_versions_requested, version);
- CLASS(printbuf, buf)();
- prt_str(&buf, "requested incompat feature ");
- bch2_version_to_text(&buf, version);
- prt_str(&buf, " currently not enabled, allowed up to ");
- bch2_version_to_text(&buf, version);
- prt_printf(&buf, "\n set version_upgrade=incompat to enable");
+ unsigned minor = BCH_VERSION_MINOR(version);
+
+ if (!test_bit(minor, c->incompat_versions_requested) &&
+ !test_and_set_bit(minor, c->incompat_versions_requested)) {
+ CLASS(printbuf, buf)();
+ prt_str(&buf, "requested incompat feature ");
+ bch2_version_to_text(&buf, version);
+ prt_str(&buf, " currently not enabled, allowed up to ");
+ bch2_version_to_text(&buf, version);
+ prt_printf(&buf, "\n set version_upgrade=incompat to enable");
+
+ bch_notice(c, "%s", buf.buf);
+ }
- bch_notice(c, "%s", buf.buf);
return bch_err_throw(c, may_not_use_incompat_feature);
}
}
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
index b3b2d8353a36..b0019488f586 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -653,7 +653,6 @@ static void __bch2_fs_free(struct bch_fs *c)
free_percpu(c->online_reserved);
}
- darray_exit(&c->incompat_versions_requested);
darray_exit(&c->btree_roots_extra);
free_percpu(c->pcpu);
free_percpu(c->usage);
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 6e30f275da77..e907c9bb840c 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -6,6 +6,7 @@
#ifndef _LINUX_WORKQUEUE_H
#define _LINUX_WORKQUEUE_H
+#include <linux/alloc_tag.h>
#include <linux/timer.h>
#include <linux/linkage.h>
#include <linux/bitops.h>
@@ -505,7 +506,8 @@ void workqueue_softirq_dead(unsigned int cpu);
* Pointer to the allocated workqueue on success, %NULL on failure.
*/
__printf(1, 4) struct workqueue_struct *
-alloc_workqueue(const char *fmt, unsigned int flags, int max_active, ...);
+alloc_workqueue_noprof(const char *fmt, unsigned int flags, int max_active, ...);
+#define alloc_workqueue(...) alloc_hooks(alloc_workqueue_noprof(__VA_ARGS__))
#ifdef CONFIG_LOCKDEP
/**
@@ -544,8 +546,8 @@ alloc_workqueue_lockdep_map(const char *fmt, unsigned int flags, int max_active,
* Pointer to the allocated workqueue on success, %NULL on failure.
*/
#define alloc_ordered_workqueue_lockdep_map(fmt, flags, lockdep_map, args...) \
- alloc_workqueue_lockdep_map(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), \
- 1, lockdep_map, ##args)
+ alloc_hooks(alloc_workqueue_lockdep_map(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags),\
+ 1, lockdep_map, ##args))
#endif
/**
@@ -577,7 +579,9 @@ alloc_workqueue_lockdep_map(const char *fmt, unsigned int flags, int max_active,
extern void destroy_workqueue(struct workqueue_struct *wq);
-struct workqueue_attrs *alloc_workqueue_attrs(void);
+struct workqueue_attrs *alloc_workqueue_attrs_noprof(void);
+#define alloc_workqueue_attrs(...) alloc_hooks(alloc_workqueue_attrs_noprof(__VA_ARGS__))
+
void free_workqueue_attrs(struct workqueue_attrs *attrs);
int apply_workqueue_attrs(struct workqueue_struct *wq,
const struct workqueue_attrs *attrs);
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 9f9148075828..992cb0467c21 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -4629,7 +4629,7 @@ void free_workqueue_attrs(struct workqueue_attrs *attrs)
*
* Return: The allocated new workqueue_attr on success. %NULL on failure.
*/
-struct workqueue_attrs *alloc_workqueue_attrs(void)
+struct workqueue_attrs *alloc_workqueue_attrs_noprof(void)
{
struct workqueue_attrs *attrs;
@@ -5682,12 +5682,12 @@ static struct workqueue_struct *__alloc_workqueue(const char *fmt,
else
wq_size = sizeof(*wq);
- wq = kzalloc(wq_size, GFP_KERNEL);
+ wq = kzalloc_noprof(wq_size, GFP_KERNEL);
if (!wq)
return NULL;
if (flags & WQ_UNBOUND) {
- wq->unbound_attrs = alloc_workqueue_attrs();
+ wq->unbound_attrs = alloc_workqueue_attrs_noprof();
if (!wq->unbound_attrs)
goto err_free_wq;
}
@@ -5777,9 +5777,9 @@ err_destroy:
}
__printf(1, 4)
-struct workqueue_struct *alloc_workqueue(const char *fmt,
- unsigned int flags,
- int max_active, ...)
+struct workqueue_struct *alloc_workqueue_noprof(const char *fmt,
+ unsigned int flags,
+ int max_active, ...)
{
struct workqueue_struct *wq;
va_list args;
@@ -5794,7 +5794,7 @@ struct workqueue_struct *alloc_workqueue(const char *fmt,
return wq;
}
-EXPORT_SYMBOL_GPL(alloc_workqueue);
+EXPORT_SYMBOL_GPL(alloc_workqueue_noprof);
#ifdef CONFIG_LOCKDEP
__printf(1, 5)