summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/bcachefs/backpointers.c2
-rw-r--r--fs/bcachefs/bcachefs_format.h6
-rw-r--r--fs/bcachefs/dirent.c2
-rw-r--r--fs/bcachefs/fs-io-buffered.c16
-rw-r--r--fs/bcachefs/fsck.c5
-rw-r--r--fs/bcachefs/inode.c11
-rw-r--r--fs/bcachefs/inode.h2
-rw-r--r--fs/bcachefs/inode_format.h3
-rw-r--r--fs/bcachefs/migrate.c4
-rw-r--r--fs/bcachefs/move.c4
-rw-r--r--fs/bcachefs/namei.c3
-rw-r--r--fs/bcachefs/opts.h2
-rw-r--r--fs/bcachefs/snapshot.c3
-rw-r--r--fs/bcachefs/snapshot.h15
-rw-r--r--fs/bcachefs/str_hash.h14
-rw-r--r--fs/bcachefs/super-io.c2
-rw-r--r--fs/bcachefs/xattr.c19
17 files changed, 87 insertions, 26 deletions
diff --git a/fs/bcachefs/backpointers.c b/fs/bcachefs/backpointers.c
index 45d3db41225a..c43aaab4c108 100644
--- a/fs/bcachefs/backpointers.c
+++ b/fs/bcachefs/backpointers.c
@@ -809,6 +809,8 @@ static int bch2_check_extents_to_backpointers_pass(struct btree_trans *trans,
for (enum btree_id btree_id = 0;
btree_id < btree_id_nr_alive(c);
btree_id++) {
+ /* btree_type_has_ptrs should probably include BTREE_ID_stripes,
+ * definitely her... */
int level, depth = btree_type_has_ptrs(btree_id) ? 0 : 1;
ret = commit_do(trans, NULL, NULL,
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h
index 7a0b602c1b27..b2de993d802b 100644
--- a/fs/bcachefs/bcachefs_format.h
+++ b/fs/bcachefs/bcachefs_format.h
@@ -706,7 +706,8 @@ struct bch_sb_field_ext {
x(snapshot_deletion_v2, BCH_VERSION(1, 26)) \
x(fast_device_removal, BCH_VERSION(1, 27)) \
x(inode_has_case_insensitive, BCH_VERSION(1, 28)) \
- x(extent_snapshot_whiteouts, BCH_VERSION(1, 29))
+ x(extent_snapshot_whiteouts, BCH_VERSION(1, 29)) \
+ x(31bit_dirent_offset, BCH_VERSION(1, 30))
enum bcachefs_metadata_version {
bcachefs_metadata_version_min = 9,
@@ -1378,7 +1379,8 @@ enum btree_id_flags {
BIT_ULL(KEY_TYPE_alloc_v4)) \
x(quotas, 5, 0, \
BIT_ULL(KEY_TYPE_quota)) \
- x(stripes, 6, 0, \
+ x(stripes, 6, \
+ BTREE_IS_data, \
BIT_ULL(KEY_TYPE_stripe)) \
x(reflink, 7, \
BTREE_IS_extents| \
diff --git a/fs/bcachefs/dirent.c b/fs/bcachefs/dirent.c
index cb44b35e0f1d..fe6f3d874a47 100644
--- a/fs/bcachefs/dirent.c
+++ b/fs/bcachefs/dirent.c
@@ -95,7 +95,7 @@ static u64 bch2_dirent_hash(const struct bch_hash_info *info,
bch2_str_hash_update(&ctx, info, name->name, name->len);
/* [0,2) reserved for dots */
- return max_t(u64, bch2_str_hash_end(&ctx, info), 2);
+ return max_t(u64, bch2_str_hash_end(&ctx, info, true), 2);
}
static u64 dirent_hash_key(const struct bch_hash_info *info, const void *key)
diff --git a/fs/bcachefs/fs-io-buffered.c b/fs/bcachefs/fs-io-buffered.c
index 9f6f9f0f21ff..fd8beb5167ee 100644
--- a/fs/bcachefs/fs-io-buffered.c
+++ b/fs/bcachefs/fs-io-buffered.c
@@ -42,6 +42,14 @@ struct readpages_iter {
folios folios;
};
+static inline void readpages_iter_folio_revert(struct readahead_control *ractl,
+ struct folio *folio)
+{
+ bch2_folio_release(folio);
+ ractl->_nr_pages += folio_nr_pages(folio);
+ ractl->_index -= folio_nr_pages(folio);
+}
+
static int readpages_iter_init(struct readpages_iter *iter,
struct readahead_control *ractl)
{
@@ -52,9 +60,7 @@ static int readpages_iter_init(struct readpages_iter *iter,
while ((folio = __readahead_folio(ractl))) {
if (!bch2_folio_create(folio, GFP_KERNEL) ||
darray_push(&iter->folios, folio)) {
- bch2_folio_release(folio);
- ractl->_nr_pages += folio_nr_pages(folio);
- ractl->_index -= folio_nr_pages(folio);
+ readpages_iter_folio_revert(ractl, folio);
return iter->folios.nr ? 0 : -ENOMEM;
}
@@ -68,9 +74,7 @@ static void readpages_iter_exit(struct readpages_iter *iter,
struct readahead_control *ractl)
{
darray_for_each_reverse(iter->folios, folio) {
- bch2_folio_release(*folio);
- ractl->_nr_pages += folio_nr_pages(*folio);
- ractl->_index -= folio_nr_pages(*folio);
+ readpages_iter_folio_revert(ractl, *folio);
folio_get(*folio);
}
}
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
index 01c1c6372229..ccc44b1fc178 100644
--- a/fs/bcachefs/fsck.c
+++ b/fs/bcachefs/fsck.c
@@ -266,7 +266,8 @@ create_lostfound:
root_inode.bi_nlink++;
- ret = bch2_inode_create(trans, &lostfound_iter, lostfound, snapshot, cpu);
+ ret = bch2_inode_create(trans, &lostfound_iter, lostfound, snapshot, cpu,
+ inode_opt_get(c, &root_inode, inodes_32bit));
if (ret)
goto err;
@@ -573,7 +574,7 @@ static int reconstruct_subvol(struct btree_trans *trans, u32 snapshotid, u32 sub
new_inode.bi_subvol = subvolid;
- int ret = bch2_inode_create(trans, &inode_iter, &new_inode, snapshotid, cpu) ?:
+ int ret = bch2_inode_create(trans, &inode_iter, &new_inode, snapshotid, cpu, false) ?:
bch2_btree_iter_traverse(&inode_iter) ?:
bch2_inode_write(trans, &inode_iter, &new_inode);
bch2_trans_iter_exit(&inode_iter);
diff --git a/fs/bcachefs/inode.c b/fs/bcachefs/inode.c
index d5e5190f0663..4aa130ff7cf6 100644
--- a/fs/bcachefs/inode.c
+++ b/fs/bcachefs/inode.c
@@ -944,11 +944,12 @@ void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
}
static struct bkey_i_inode_alloc_cursor *
-bch2_inode_alloc_cursor_get(struct btree_trans *trans, u64 cpu, u64 *min, u64 *max)
+bch2_inode_alloc_cursor_get(struct btree_trans *trans, u64 cpu, u64 *min, u64 *max,
+ bool is_32bit)
{
struct bch_fs *c = trans->c;
- u64 cursor_idx = c->opts.inodes_32bit ? 0 : cpu + 1;
+ u64 cursor_idx = is_32bit ? 0 : cpu + 1;
cursor_idx &= ~(~0ULL << c->opts.shard_inode_numbers_bits);
@@ -967,7 +968,7 @@ bch2_inode_alloc_cursor_get(struct btree_trans *trans, u64 cpu, u64 *min, u64 *m
if (IS_ERR(cursor))
return cursor;
- if (c->opts.inodes_32bit) {
+ if (is_32bit) {
*min = BLOCKDEV_INODE_MAX;
*max = INT_MAX;
} else {
@@ -996,11 +997,11 @@ bch2_inode_alloc_cursor_get(struct btree_trans *trans, u64 cpu, u64 *min, u64 *m
int bch2_inode_create(struct btree_trans *trans,
struct btree_iter *iter,
struct bch_inode_unpacked *inode_u,
- u32 snapshot, u64 cpu)
+ u32 snapshot, u64 cpu, bool is_32bit)
{
u64 min, max;
struct bkey_i_inode_alloc_cursor *cursor =
- bch2_inode_alloc_cursor_get(trans, cpu, &min, &max);
+ bch2_inode_alloc_cursor_get(trans, cpu, &min, &max, is_32bit);
int ret = PTR_ERR_OR_ZERO(cursor);
if (ret)
return ret;
diff --git a/fs/bcachefs/inode.h b/fs/bcachefs/inode.h
index b8ec3e628d90..79092ea74844 100644
--- a/fs/bcachefs/inode.h
+++ b/fs/bcachefs/inode.h
@@ -172,7 +172,7 @@ void bch2_inode_init(struct bch_fs *, struct bch_inode_unpacked *,
struct bch_inode_unpacked *);
int bch2_inode_create(struct btree_trans *, struct btree_iter *,
- struct bch_inode_unpacked *, u32, u64);
+ struct bch_inode_unpacked *, u32, u64, bool);
int bch2_inode_rm(struct bch_fs *, subvol_inum);
diff --git a/fs/bcachefs/inode_format.h b/fs/bcachefs/inode_format.h
index 1f00938b1bdc..e07fa6cc99bd 100644
--- a/fs/bcachefs/inode_format.h
+++ b/fs/bcachefs/inode_format.h
@@ -144,7 +144,8 @@ enum inode_opt_id {
x(unlinked, 7) \
x(backptr_untrusted, 8) \
x(has_child_snapshot, 9) \
- x(has_case_insensitive, 10)
+ x(has_case_insensitive, 10) \
+ x(31bit_dirent_offset, 11)
/* bits 20+ reserved for packed fields below: */
diff --git a/fs/bcachefs/migrate.c b/fs/bcachefs/migrate.c
index a66d01d04e57..892990b4a6a6 100644
--- a/fs/bcachefs/migrate.c
+++ b/fs/bcachefs/migrate.c
@@ -125,6 +125,10 @@ static int bch2_dev_usrdata_drop(struct bch_fs *c,
if (!btree_type_has_ptrs(id))
continue;
+ /* Stripe keys have pointers, but are handled separately */
+ if (id == BTREE_ID_stripes)
+ continue;
+
int ret = for_each_btree_key_commit(trans, iter, id, POS_MIN,
BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k,
NULL, NULL, BCH_TRANS_COMMIT_no_enospc, ({
diff --git a/fs/bcachefs/move.c b/fs/bcachefs/move.c
index df6833416855..4f41f1f6ec6c 100644
--- a/fs/bcachefs/move.c
+++ b/fs/bcachefs/move.c
@@ -819,7 +819,9 @@ static int bch2_move_data(struct bch_fs *c,
unsigned min_depth_this_btree = min_depth;
- if (!btree_type_has_ptrs(id))
+ /* Stripe keys have pointers, but are handled separately */
+ if (!btree_type_has_ptrs(id) ||
+ id == BTREE_ID_stripes)
min_depth_this_btree = max(min_depth_this_btree, 1);
for (unsigned level = min_depth_this_btree;
diff --git a/fs/bcachefs/namei.c b/fs/bcachefs/namei.c
index d1019052f182..5c321a0d1f89 100644
--- a/fs/bcachefs/namei.c
+++ b/fs/bcachefs/namei.c
@@ -62,7 +62,8 @@ int bch2_create_trans(struct btree_trans *trans,
if (flags & BCH_CREATE_TMPFILE)
new_inode->bi_flags |= BCH_INODE_unlinked;
- ret = bch2_inode_create(trans, &inode_iter, new_inode, snapshot, cpu);
+ ret = bch2_inode_create(trans, &inode_iter, new_inode, snapshot, cpu,
+ inode_opt_get(c, dir_u, inodes_32bit));
if (ret)
goto err;
diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h
index 84ce69a7f131..03e22fb83d17 100644
--- a/fs/bcachefs/opts.h
+++ b/fs/bcachefs/opts.h
@@ -242,7 +242,7 @@ enum fsck_err_opts {
x(inodes_32bit, u8, \
OPT_FS|OPT_INODE|OPT_FORMAT|OPT_MOUNT|OPT_RUNTIME, \
OPT_BOOL(), \
- BCH_SB_INODE_32BIT, true, \
+ BCH_SB_INODE_32BIT, false, \
NULL, "Constrain inode numbers to 32 bits") \
x(shard_inode_numbers_bits, u8, \
OPT_FS|OPT_FORMAT, \
diff --git a/fs/bcachefs/snapshot.c b/fs/bcachefs/snapshot.c
index 84f987d3a02a..eab0c1e3ff56 100644
--- a/fs/bcachefs/snapshot.c
+++ b/fs/bcachefs/snapshot.c
@@ -1673,7 +1673,8 @@ static int bch2_fix_child_of_deleted_snapshot(struct btree_trans *trans,
return ret;
darray_for_each(*deleted, i)
- nr_deleted_ancestors += bch2_snapshot_is_ancestor(c, s->k.p.offset, i->id);
+ nr_deleted_ancestors += bch2_snapshots_same_tree(c, s->k.p.offset, i->id) &&
+ bch2_snapshot_is_ancestor(c, s->k.p.offset, i->id);
if (!nr_deleted_ancestors)
return 0;
diff --git a/fs/bcachefs/snapshot.h b/fs/bcachefs/snapshot.h
index fef32a0118c4..28d9a29a1fd0 100644
--- a/fs/bcachefs/snapshot.h
+++ b/fs/bcachefs/snapshot.h
@@ -51,6 +51,17 @@ static inline u32 bch2_snapshot_tree(struct bch_fs *c, u32 id)
return s ? s->tree : 0;
}
+static inline bool bch2_snapshots_same_tree(struct bch_fs *c, u32 id1, u32 id2)
+{
+ if (id1 == id2)
+ return true;
+
+ guard(rcu)();
+ const struct snapshot_t *s1 = snapshot_t(c, id1);
+ const struct snapshot_t *s2 = snapshot_t(c, id2);
+ return s1 && s2 && s1->tree == s2->tree;
+}
+
static inline u32 __bch2_snapshot_parent_early(struct bch_fs *c, u32 id)
{
const struct snapshot_t *s = snapshot_t(c, id);
@@ -157,6 +168,10 @@ bool __bch2_snapshot_is_ancestor(struct bch_fs *, u32, u32);
static inline bool bch2_snapshot_is_ancestor(struct bch_fs *c, u32 id, u32 ancestor)
{
+ EBUG_ON(!id);
+ EBUG_ON(!ancestor);
+ EBUG_ON(!bch2_snapshots_same_tree(c, id, ancestor));
+
return id == ancestor
? true
: __bch2_snapshot_is_ancestor(c, id, ancestor);
diff --git a/fs/bcachefs/str_hash.h b/fs/bcachefs/str_hash.h
index 8c0fb44929cc..2a61cc36ddbf 100644
--- a/fs/bcachefs/str_hash.h
+++ b/fs/bcachefs/str_hash.h
@@ -34,6 +34,7 @@ bch2_str_hash_opt_to_type(struct bch_fs *c, enum bch_str_hash_opts opt)
struct bch_hash_info {
u32 inum_snapshot;
u8 type;
+ bool is_31bit;
struct unicode_map *cf_encoding;
/*
* For crc32 or crc64 string hashes the first key value of
@@ -48,6 +49,7 @@ bch2_hash_info_init(struct bch_fs *c, const struct bch_inode_unpacked *bi)
struct bch_hash_info info = {
.inum_snapshot = bi->bi_snapshot,
.type = INODE_STR_HASH(bi),
+ .is_31bit = bi->bi_flags & BCH_INODE_31bit_dirent_offset,
.cf_encoding = bch2_inode_casefold(c, bi) ? c->cf_encoding : NULL,
.siphash_key = { .k0 = bi->bi_hash_seed }
};
@@ -112,8 +114,8 @@ static inline void bch2_str_hash_update(struct bch_str_hash_ctx *ctx,
}
}
-static inline u64 bch2_str_hash_end(struct bch_str_hash_ctx *ctx,
- const struct bch_hash_info *info)
+static inline u64 __bch2_str_hash_end(struct bch_str_hash_ctx *ctx,
+ const struct bch_hash_info *info)
{
switch (info->type) {
case BCH_STR_HASH_crc32c:
@@ -128,6 +130,14 @@ static inline u64 bch2_str_hash_end(struct bch_str_hash_ctx *ctx,
}
}
+static inline u64 bch2_str_hash_end(struct bch_str_hash_ctx *ctx,
+ const struct bch_hash_info *info,
+ bool maybe_31bit)
+{
+ return __bch2_str_hash_end(ctx, info) &
+ (maybe_31bit && info->is_31bit ? INT_MAX : U64_MAX);
+}
+
struct bch_hash_desc {
enum btree_id btree_id;
u8 key_type;
diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c
index be7ed612d28f..369465a4de77 100644
--- a/fs/bcachefs/super-io.c
+++ b/fs/bcachefs/super-io.c
@@ -89,7 +89,7 @@ int bch2_set_version_incompat(struct bch_fs *c, enum bcachefs_metadata_version v
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);
+ bch2_version_to_text(&buf, c->sb.version_incompat_allowed);
prt_printf(&buf, "\n set version_upgrade=incompat to enable");
bch_notice(c, "%s", buf.buf);
diff --git a/fs/bcachefs/xattr.c b/fs/bcachefs/xattr.c
index 6094b568dd33..6d7303008b19 100644
--- a/fs/bcachefs/xattr.c
+++ b/fs/bcachefs/xattr.c
@@ -4,6 +4,7 @@
#include "acl.h"
#include "bkey_methods.h"
#include "btree_update.h"
+#include "dirent.h"
#include "extents.h"
#include "fs.h"
#include "rebalance.h"
@@ -25,7 +26,7 @@ static u64 bch2_xattr_hash(const struct bch_hash_info *info,
bch2_str_hash_update(&ctx, info, &key->type, sizeof(key->type));
bch2_str_hash_update(&ctx, info, key->name.name, key->name.len);
- return bch2_str_hash_end(&ctx, info);
+ return bch2_str_hash_end(&ctx, info, false);
}
static u64 xattr_hash_key(const struct bch_hash_info *info, const void *key)
@@ -484,6 +485,22 @@ static int inode_opt_set_fn(struct btree_trans *trans,
return ret;
}
+ if (s->id == Inode_opt_inodes_32bit &&
+ !bch2_request_incompat_feature(trans->c, bcachefs_metadata_version_31bit_dirent_offset)) {
+ /*
+ * Make sure the dir is empty, as otherwise we'd need to
+ * rehash everything and update the dirent keys.
+ */
+ int ret = bch2_empty_dir_trans(trans, inode_inum(inode));
+ if (ret < 0)
+ return ret;
+
+ if (s->defined)
+ bi->bi_flags |= BCH_INODE_31bit_dirent_offset;
+ else
+ bi->bi_flags &= ~BCH_INODE_31bit_dirent_offset;
+ }
+
if (s->defined)
bi->bi_fields_set |= 1U << s->id;
else