mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-02 00:00:03 +03:00
Update bcachefs sources to 9017d85854 bcachefs: btree_ptr_v2
This commit is contained in:
parent
e0eb64c846
commit
7c4552717f
@ -1 +1 @@
|
||||
3cd63315a62c8e2da15aa9fd59fa74ef40c9dc14
|
||||
9017d858547faedabdef6ca21317e317791526bd
|
||||
|
@ -211,33 +211,31 @@ void bch2_alloc_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
int bch2_alloc_read(struct bch_fs *c, struct journal_keys *journal_keys)
|
||||
{
|
||||
struct btree_trans trans;
|
||||
struct btree_iter *iter;
|
||||
struct btree_and_journal_iter iter;
|
||||
struct bkey_s_c k;
|
||||
struct bch_dev *ca;
|
||||
struct journal_key *j;
|
||||
unsigned i;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_ALLOC, POS_MIN, 0, k, ret)
|
||||
bch2_btree_and_journal_iter_init(&iter, &trans, journal_keys,
|
||||
BTREE_ID_ALLOC, POS_MIN);
|
||||
|
||||
while ((k = bch2_btree_and_journal_iter_peek(&iter)).k) {
|
||||
bch2_mark_key(c, k, 0, 0, NULL, 0,
|
||||
BTREE_TRIGGER_ALLOC_READ|
|
||||
BTREE_TRIGGER_NOATOMIC);
|
||||
|
||||
bch2_btree_and_journal_iter_advance(&iter);
|
||||
}
|
||||
|
||||
ret = bch2_trans_exit(&trans) ?: ret;
|
||||
if (ret) {
|
||||
bch_err(c, "error reading alloc info: %i", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for_each_journal_key(*journal_keys, j)
|
||||
if (j->btree_id == BTREE_ID_ALLOC)
|
||||
bch2_mark_key(c, bkey_i_to_s_c(j->k),
|
||||
0, 0, NULL, 0,
|
||||
BTREE_TRIGGER_ALLOC_READ|
|
||||
BTREE_TRIGGER_NOATOMIC);
|
||||
|
||||
percpu_down_write(&c->mark_lock);
|
||||
bch2_dev_usage_from_buckets(c);
|
||||
percpu_up_write(&c->mark_lock);
|
||||
|
@ -339,7 +339,8 @@ static inline void bkey_init(struct bkey *k)
|
||||
x(stripe, 14) \
|
||||
x(reflink_p, 15) \
|
||||
x(reflink_v, 16) \
|
||||
x(inline_data, 17)
|
||||
x(inline_data, 17) \
|
||||
x(btree_ptr_v2, 18)
|
||||
|
||||
enum bch_bkey_type {
|
||||
#define x(name, nr) KEY_TYPE_##name = nr,
|
||||
@ -595,6 +596,19 @@ struct bch_btree_ptr {
|
||||
__u64 _data[0];
|
||||
} __attribute__((packed, aligned(8)));
|
||||
|
||||
struct bch_btree_ptr_v2 {
|
||||
struct bch_val v;
|
||||
|
||||
__u64 mem_ptr;
|
||||
__le64 seq;
|
||||
__le16 sectors_written;
|
||||
/* In case we ever decide to do variable size btree nodes: */
|
||||
__le16 sectors;
|
||||
struct bpos min_key;
|
||||
struct bch_extent_ptr start[0];
|
||||
__u64 _data[0];
|
||||
} __attribute__((packed, aligned(8)));
|
||||
|
||||
struct bch_extent {
|
||||
struct bch_val v;
|
||||
|
||||
@ -626,7 +640,8 @@ struct bch_reservation {
|
||||
|
||||
/* Btree pointers don't carry around checksums: */
|
||||
#define BKEY_BTREE_PTR_VAL_U64s_MAX \
|
||||
((sizeof(struct bch_extent_ptr)) / sizeof(u64) * BCH_REPLICAS_MAX)
|
||||
((sizeof(struct bch_btree_ptr_v2) + \
|
||||
sizeof(struct bch_extent_ptr) * BCH_REPLICAS_MAX) / sizeof(u64))
|
||||
#define BKEY_BTREE_PTR_U64s_MAX \
|
||||
(BKEY_U64s + BKEY_BTREE_PTR_VAL_U64s_MAX)
|
||||
|
||||
@ -1295,7 +1310,8 @@ LE64_BITMASK(BCH_SB_ERASURE_CODE, struct bch_sb, flags[3], 0, 16);
|
||||
x(new_siphash, 7) \
|
||||
x(inline_data, 8) \
|
||||
x(new_extent_overwrite, 9) \
|
||||
x(incompressible, 10)
|
||||
x(incompressible, 10) \
|
||||
x(btree_ptr_v2, 11)
|
||||
|
||||
enum bch_sb_feature {
|
||||
#define x(f, n) BCH_FEATURE_##f,
|
||||
|
@ -565,6 +565,7 @@ BKEY_VAL_ACCESSORS(stripe);
|
||||
BKEY_VAL_ACCESSORS(reflink_p);
|
||||
BKEY_VAL_ACCESSORS(reflink_v);
|
||||
BKEY_VAL_ACCESSORS(inline_data);
|
||||
BKEY_VAL_ACCESSORS(btree_ptr_v2);
|
||||
|
||||
/* byte order helpers */
|
||||
|
||||
|
@ -202,15 +202,12 @@ void bch2_bkey_val_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
bch2_val_to_text(out, c, k);
|
||||
}
|
||||
|
||||
void bch2_bkey_swab(const struct bkey_format *f,
|
||||
struct bkey_packed *k)
|
||||
void bch2_bkey_swab_val(struct bkey_s k)
|
||||
{
|
||||
const struct bkey_ops *ops = &bch2_bkey_ops[k->type];
|
||||
|
||||
bch2_bkey_swab_key(f, k);
|
||||
const struct bkey_ops *ops = &bch2_bkey_ops[k.k->type];
|
||||
|
||||
if (ops->swab)
|
||||
ops->swab(f, k);
|
||||
ops->swab(k);
|
||||
}
|
||||
|
||||
bool bch2_bkey_normalize(struct bch_fs *c, struct bkey_s k)
|
||||
|
@ -29,7 +29,7 @@ struct bkey_ops {
|
||||
void (*key_debugcheck)(struct bch_fs *, struct bkey_s_c);
|
||||
void (*val_to_text)(struct printbuf *, struct bch_fs *,
|
||||
struct bkey_s_c);
|
||||
void (*swab)(const struct bkey_format *, struct bkey_packed *);
|
||||
void (*swab)(struct bkey_s);
|
||||
bool (*key_normalize)(struct bch_fs *, struct bkey_s);
|
||||
enum merge_result (*key_merge)(struct bch_fs *,
|
||||
struct bkey_s, struct bkey_s);
|
||||
@ -51,7 +51,7 @@ void bch2_val_to_text(struct printbuf *, struct bch_fs *,
|
||||
void bch2_bkey_val_to_text(struct printbuf *, struct bch_fs *,
|
||||
struct bkey_s_c);
|
||||
|
||||
void bch2_bkey_swab(const struct bkey_format *, struct bkey_packed *);
|
||||
void bch2_bkey_swab_val(struct bkey_s);
|
||||
|
||||
bool bch2_bkey_normalize(struct bch_fs *, struct bkey_s);
|
||||
|
||||
|
@ -1206,7 +1206,8 @@ void bch2_bset_insert(struct btree *b,
|
||||
memcpy_u64s(bkeyp_val(f, where), &insert->v,
|
||||
bkeyp_val_u64s(f, src));
|
||||
|
||||
bch2_bset_fix_lookup_table(b, t, where, clobber_u64s, src->u64s);
|
||||
if (src->u64s != clobber_u64s)
|
||||
bch2_bset_fix_lookup_table(b, t, where, clobber_u64s, src->u64s);
|
||||
|
||||
bch2_verify_btree_nr_keys(b);
|
||||
}
|
||||
|
@ -62,13 +62,13 @@ static int bch2_btree_cache_cmp_fn(struct rhashtable_compare_arg *arg,
|
||||
const struct btree *b = obj;
|
||||
const u64 *v = arg->key;
|
||||
|
||||
return PTR_HASH(&b->key) == *v ? 0 : 1;
|
||||
return b->hash_val == *v ? 0 : 1;
|
||||
}
|
||||
|
||||
static const struct rhashtable_params bch_btree_cache_params = {
|
||||
.head_offset = offsetof(struct btree, hash),
|
||||
.key_offset = offsetof(struct btree, key.v),
|
||||
.key_len = sizeof(struct bch_extent_ptr),
|
||||
.key_offset = offsetof(struct btree, hash_val),
|
||||
.key_len = sizeof(u64),
|
||||
.obj_cmpfn = bch2_btree_cache_cmp_fn,
|
||||
};
|
||||
|
||||
@ -114,11 +114,14 @@ void bch2_btree_node_hash_remove(struct btree_cache *bc, struct btree *b)
|
||||
rhashtable_remove_fast(&bc->table, &b->hash, bch_btree_cache_params);
|
||||
|
||||
/* Cause future lookups for this node to fail: */
|
||||
PTR_HASH(&b->key) = 0;
|
||||
b->hash_val = 0;
|
||||
}
|
||||
|
||||
int __bch2_btree_node_hash_insert(struct btree_cache *bc, struct btree *b)
|
||||
{
|
||||
BUG_ON(b->hash_val);
|
||||
b->hash_val = btree_ptr_hash_val(&b->key);
|
||||
|
||||
return rhashtable_lookup_insert_fast(&bc->table, &b->hash,
|
||||
bch_btree_cache_params);
|
||||
}
|
||||
@ -144,8 +147,9 @@ __flatten
|
||||
static inline struct btree *btree_cache_find(struct btree_cache *bc,
|
||||
const struct bkey_i *k)
|
||||
{
|
||||
return rhashtable_lookup_fast(&bc->table, &PTR_HASH(k),
|
||||
bch_btree_cache_params);
|
||||
u64 v = btree_ptr_hash_val(k);
|
||||
|
||||
return rhashtable_lookup_fast(&bc->table, &v, bch_btree_cache_params);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -199,7 +203,7 @@ static int __btree_node_reclaim(struct bch_fs *c, struct btree *b, bool flush)
|
||||
btree_node_wait_on_io(b);
|
||||
}
|
||||
out:
|
||||
if (PTR_HASH(&b->key) && !ret)
|
||||
if (b->hash_val && !ret)
|
||||
trace_btree_node_reap(c, b);
|
||||
return ret;
|
||||
out_unlock:
|
||||
@ -607,7 +611,7 @@ static noinline struct btree *bch2_btree_node_fill(struct bch_fs *c,
|
||||
/* raced with another fill: */
|
||||
|
||||
/* mark as unhashed... */
|
||||
PTR_HASH(&b->key) = 0;
|
||||
b->hash_val = 0;
|
||||
|
||||
mutex_lock(&bc->lock);
|
||||
list_add(&b->list, &bc->freeable);
|
||||
@ -710,7 +714,7 @@ retry:
|
||||
* free it:
|
||||
*
|
||||
* To guard against this, btree nodes are evicted from the cache
|
||||
* when they're freed - and PTR_HASH() is zeroed out, which we
|
||||
* when they're freed - and b->hash_val is zeroed out, which we
|
||||
* check for after we lock the node.
|
||||
*
|
||||
* Then, bch2_btree_node_relock() on the parent will fail - because
|
||||
@ -723,7 +727,7 @@ retry:
|
||||
if (!btree_node_lock(b, k->k.p, level, iter, lock_type))
|
||||
return ERR_PTR(-EINTR);
|
||||
|
||||
if (unlikely(PTR_HASH(&b->key) != PTR_HASH(k) ||
|
||||
if (unlikely(b->hash_val != btree_ptr_hash_val(k) ||
|
||||
b->level != level ||
|
||||
race_fault())) {
|
||||
six_unlock_type(&b->lock, lock_type);
|
||||
|
@ -35,13 +35,22 @@ void bch2_fs_btree_cache_exit(struct bch_fs *);
|
||||
int bch2_fs_btree_cache_init(struct bch_fs *);
|
||||
void bch2_fs_btree_cache_init_early(struct btree_cache *);
|
||||
|
||||
#define PTR_HASH(_k) *((u64 *) &bkey_i_to_btree_ptr_c(_k)->v)
|
||||
static inline u64 btree_ptr_hash_val(const struct bkey_i *k)
|
||||
{
|
||||
switch (k->k.type) {
|
||||
case KEY_TYPE_btree_ptr:
|
||||
return *((u64 *) bkey_i_to_btree_ptr_c(k)->v.start);
|
||||
case KEY_TYPE_btree_ptr_v2:
|
||||
return bkey_i_to_btree_ptr_v2_c(k)->v.seq;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* is btree node in hash table? */
|
||||
static inline bool btree_node_hashed(struct btree *b)
|
||||
{
|
||||
return b->key.k.type == KEY_TYPE_btree_ptr &&
|
||||
PTR_HASH(&b->key);
|
||||
return b->hash_val != 0;
|
||||
}
|
||||
|
||||
#define for_each_cached_btree(_b, _c, _tbl, _iter, _pos) \
|
||||
|
@ -124,7 +124,11 @@ static int bch2_gc_mark_key(struct bch_fs *c, struct bkey_s_c k,
|
||||
BUG_ON(journal_seq_verify(c) &&
|
||||
k.k->version.lo > journal_cur_seq(&c->journal));
|
||||
|
||||
if (k.k->version.lo > atomic64_read(&c->key_version))
|
||||
/* XXX change to fsck check */
|
||||
if (fsck_err_on(k.k->version.lo > atomic64_read(&c->key_version), c,
|
||||
"key version number higher than recorded: %llu > %llu",
|
||||
k.k->version.lo,
|
||||
atomic64_read(&c->key_version)))
|
||||
atomic64_set(&c->key_version, k.k->version.lo);
|
||||
|
||||
if (test_bit(BCH_FS_REBUILD_REPLICAS, &c->flags) ||
|
||||
|
@ -735,6 +735,15 @@ static int validate_bset(struct bch_fs *c, struct btree *b,
|
||||
bch2_bpos_swab(&b->data->max_key);
|
||||
}
|
||||
|
||||
if (b->key.k.type == KEY_TYPE_btree_ptr_v2) {
|
||||
struct bch_btree_ptr_v2 *bp =
|
||||
&bkey_i_to_btree_ptr_v2(&b->key)->v;
|
||||
|
||||
btree_err_on(bkey_cmp(b->data->min_key, bp->min_key),
|
||||
BTREE_ERR_MUST_RETRY, c, b, NULL,
|
||||
"incorrect min_key");
|
||||
}
|
||||
|
||||
btree_err_on(bkey_cmp(b->data->max_key, b->key.k.p),
|
||||
BTREE_ERR_MUST_RETRY, c, b, i,
|
||||
"incorrect max key");
|
||||
@ -784,7 +793,7 @@ static int validate_bset(struct bch_fs *c, struct btree *b,
|
||||
|
||||
for (k = i->start;
|
||||
k != vstruct_last(i);) {
|
||||
struct bkey_s_c u;
|
||||
struct bkey_s u;
|
||||
struct bkey tmp;
|
||||
const char *invalid;
|
||||
|
||||
@ -805,21 +814,24 @@ static int validate_bset(struct bch_fs *c, struct btree *b,
|
||||
}
|
||||
|
||||
if (BSET_BIG_ENDIAN(i) != CPU_BIG_ENDIAN)
|
||||
bch2_bkey_swab(&b->format, k);
|
||||
bch2_bkey_swab_key(&b->format, k);
|
||||
|
||||
if (!write &&
|
||||
version < bcachefs_metadata_version_bkey_renumber)
|
||||
bch2_bkey_renumber(btree_node_type(b), k, write);
|
||||
|
||||
u = bkey_disassemble(b, k, &tmp);
|
||||
u = __bkey_disassemble(b, k, &tmp);
|
||||
|
||||
invalid = __bch2_bkey_invalid(c, u, btree_node_type(b)) ?:
|
||||
bch2_bkey_in_btree_node(b, u) ?:
|
||||
(write ? bch2_bkey_val_invalid(c, u) : NULL);
|
||||
if (BSET_BIG_ENDIAN(i) != CPU_BIG_ENDIAN)
|
||||
bch2_bkey_swab_val(u);
|
||||
|
||||
invalid = __bch2_bkey_invalid(c, u.s_c, btree_node_type(b)) ?:
|
||||
bch2_bkey_in_btree_node(b, u.s_c) ?:
|
||||
(write ? bch2_bkey_val_invalid(c, u.s_c) : NULL);
|
||||
if (invalid) {
|
||||
char buf[160];
|
||||
|
||||
bch2_bkey_val_to_text(&PBUF(buf), c, u);
|
||||
bch2_bkey_val_to_text(&PBUF(buf), c, u.s_c);
|
||||
btree_err(BTREE_ERR_FIXABLE, c, b, i,
|
||||
"invalid bkey:\n%s\n%s", invalid, buf);
|
||||
|
||||
@ -895,6 +907,15 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
|
||||
BTREE_ERR_MUST_RETRY, c, b, NULL,
|
||||
"bad btree header");
|
||||
|
||||
if (b->key.k.type == KEY_TYPE_btree_ptr_v2) {
|
||||
struct bch_btree_ptr_v2 *bp =
|
||||
&bkey_i_to_btree_ptr_v2(&b->key)->v;
|
||||
|
||||
btree_err_on(b->data->keys.seq != bp->seq,
|
||||
BTREE_ERR_MUST_RETRY, c, b, NULL,
|
||||
"got wrong btree node");
|
||||
}
|
||||
|
||||
while (b->written < c->opts.btree_node_size) {
|
||||
unsigned sectors, whiteout_u64s = 0;
|
||||
struct nonce nonce;
|
||||
@ -1002,15 +1023,15 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
|
||||
i = &b->data->keys;
|
||||
for (k = i->start; k != vstruct_last(i);) {
|
||||
struct bkey tmp;
|
||||
struct bkey_s_c u = bkey_disassemble(b, k, &tmp);
|
||||
const char *invalid = bch2_bkey_val_invalid(c, u);
|
||||
struct bkey_s u = __bkey_disassemble(b, k, &tmp);
|
||||
const char *invalid = bch2_bkey_val_invalid(c, u.s_c);
|
||||
|
||||
if (invalid ||
|
||||
(inject_invalid_keys(c) &&
|
||||
!bversion_cmp(u.k->version, MAX_VERSION))) {
|
||||
char buf[160];
|
||||
|
||||
bch2_bkey_val_to_text(&PBUF(buf), c, u);
|
||||
bch2_bkey_val_to_text(&PBUF(buf), c, u.s_c);
|
||||
btree_err(BTREE_ERR_FIXABLE, c, b, i,
|
||||
"invalid bkey %s: %s", buf, invalid);
|
||||
|
||||
@ -1023,6 +1044,12 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry
|
||||
continue;
|
||||
}
|
||||
|
||||
if (u.k->type == KEY_TYPE_btree_ptr_v2) {
|
||||
struct bkey_s_btree_ptr_v2 bp = bkey_s_to_btree_ptr_v2(u);
|
||||
|
||||
bp.v->mem_ptr = 0;
|
||||
}
|
||||
|
||||
k = bkey_next_skip_noops(k, vstruct_last(i));
|
||||
}
|
||||
|
||||
@ -1252,8 +1279,6 @@ static void bch2_btree_node_write_error(struct bch_fs *c,
|
||||
{
|
||||
struct btree *b = wbio->wbio.bio.bi_private;
|
||||
__BKEY_PADDED(k, BKEY_BTREE_PTR_VAL_U64s_MAX) tmp;
|
||||
struct bkey_i_btree_ptr *new_key;
|
||||
struct bkey_s_btree_ptr bp;
|
||||
struct bch_extent_ptr *ptr;
|
||||
struct btree_trans trans;
|
||||
struct btree_iter *iter;
|
||||
@ -1279,16 +1304,13 @@ retry:
|
||||
|
||||
bkey_copy(&tmp.k, &b->key);
|
||||
|
||||
new_key = bkey_i_to_btree_ptr(&tmp.k);
|
||||
bp = btree_ptr_i_to_s(new_key);
|
||||
|
||||
bch2_bkey_drop_ptrs(bkey_i_to_s(&tmp.k), ptr,
|
||||
bch2_dev_list_has_dev(wbio->wbio.failed, ptr->dev));
|
||||
|
||||
if (!bch2_bkey_nr_ptrs(bp.s_c))
|
||||
if (!bch2_bkey_nr_ptrs(bkey_i_to_s_c(&tmp.k)))
|
||||
goto err;
|
||||
|
||||
ret = bch2_btree_node_update_key(c, iter, b, new_key);
|
||||
ret = bch2_btree_node_update_key(c, iter, b, &tmp.k);
|
||||
if (ret == -EINTR)
|
||||
goto retry;
|
||||
if (ret)
|
||||
|
@ -408,7 +408,7 @@ static void __bch2_btree_iter_verify(struct btree_iter *iter,
|
||||
* For extents, the iterator may have skipped past deleted keys (but not
|
||||
* whiteouts)
|
||||
*/
|
||||
k = b->level || iter->flags & BTREE_ITER_IS_EXTENTS
|
||||
k = b->level || btree_node_type_is_extents(iter->btree_id)
|
||||
? bch2_btree_node_iter_prev_filter(&tmp, b, KEY_TYPE_discard)
|
||||
: bch2_btree_node_iter_prev_all(&tmp, b);
|
||||
if (k && bkey_iter_pos_cmp(b, k, &pos) >= 0) {
|
||||
@ -563,7 +563,7 @@ fixup_done:
|
||||
if (!bch2_btree_node_iter_end(node_iter) &&
|
||||
iter_current_key_modified &&
|
||||
(b->level ||
|
||||
(iter->flags & BTREE_ITER_IS_EXTENTS))) {
|
||||
btree_node_type_is_extents(iter->btree_id))) {
|
||||
struct bset_tree *t;
|
||||
struct bkey_packed *k, *k2, *p;
|
||||
|
||||
@ -1271,6 +1271,29 @@ static unsigned btree_iter_pos_changed(struct btree_iter *iter, int cmp)
|
||||
return l;
|
||||
}
|
||||
|
||||
void __bch2_btree_iter_set_pos(struct btree_iter *iter, struct bpos new_pos,
|
||||
bool strictly_greater)
|
||||
{
|
||||
struct bpos old = btree_iter_search_key(iter);
|
||||
unsigned l;
|
||||
int cmp;
|
||||
|
||||
iter->flags &= ~BTREE_ITER_IS_EXTENTS;
|
||||
iter->flags |= strictly_greater ? BTREE_ITER_IS_EXTENTS : 0;
|
||||
iter->pos = new_pos;
|
||||
|
||||
cmp = bkey_cmp(btree_iter_search_key(iter), old);
|
||||
if (!cmp)
|
||||
return;
|
||||
|
||||
l = btree_iter_pos_changed(iter, cmp);
|
||||
|
||||
if (l != iter->level)
|
||||
btree_iter_set_dirty(iter, BTREE_ITER_NEED_TRAVERSE);
|
||||
else
|
||||
btree_iter_set_dirty(iter, BTREE_ITER_NEED_PEEK);
|
||||
}
|
||||
|
||||
void bch2_btree_iter_set_pos(struct btree_iter *iter, struct bpos new_pos)
|
||||
{
|
||||
int cmp = bkey_cmp(new_pos, iter->pos);
|
||||
@ -1709,8 +1732,7 @@ static inline void bch2_btree_iter_init(struct btree_trans *trans,
|
||||
iter->nodes_locked = 0;
|
||||
iter->nodes_intent_locked = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(iter->l); i++)
|
||||
iter->l[i].b = NULL;
|
||||
iter->l[iter->level].b = BTREE_ITER_NO_NODE_INIT;
|
||||
iter->l[i].b = BTREE_ITER_NO_NODE_INIT;
|
||||
|
||||
prefetch(c->btree_roots[btree_id].b);
|
||||
}
|
||||
@ -1729,7 +1751,12 @@ static inline void __bch2_trans_iter_free(struct btree_trans *trans,
|
||||
int bch2_trans_iter_put(struct btree_trans *trans,
|
||||
struct btree_iter *iter)
|
||||
{
|
||||
int ret = btree_iter_err(iter);
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(iter))
|
||||
return 0;
|
||||
|
||||
ret = btree_iter_err(iter);
|
||||
|
||||
if (!(trans->iters_touched & (1ULL << iter->idx)) &&
|
||||
!(iter->flags & BTREE_ITER_KEEP_UNTIL_COMMIT))
|
||||
@ -1742,6 +1769,9 @@ int bch2_trans_iter_put(struct btree_trans *trans,
|
||||
int bch2_trans_iter_free(struct btree_trans *trans,
|
||||
struct btree_iter *iter)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(iter))
|
||||
return 0;
|
||||
|
||||
trans->iters_touched &= ~(1ULL << iter->idx);
|
||||
|
||||
return bch2_trans_iter_put(trans, iter);
|
||||
@ -1939,7 +1969,8 @@ struct btree_iter *bch2_trans_get_iter(struct btree_trans *trans,
|
||||
__btree_trans_get_iter(trans, btree_id, pos, flags);
|
||||
|
||||
if (!IS_ERR(iter))
|
||||
bch2_btree_iter_set_pos(iter, pos);
|
||||
__bch2_btree_iter_set_pos(iter, pos,
|
||||
btree_node_type_is_extents(btree_id));
|
||||
return iter;
|
||||
}
|
||||
|
||||
@ -1981,8 +2012,8 @@ struct btree_iter *bch2_trans_copy_iter(struct btree_trans *trans,
|
||||
|
||||
trans->iters_live |= 1ULL << iter->idx;
|
||||
/*
|
||||
* Don't mark it as touched, we don't need to preserve this iter since
|
||||
* it's cheap to copy it again:
|
||||
* We don't need to preserve this iter since it's cheap to copy it
|
||||
* again - this will cause trans_iter_put() to free it right away:
|
||||
*/
|
||||
trans->iters_touched &= ~(1ULL << iter->idx);
|
||||
|
||||
|
@ -166,6 +166,7 @@ struct bkey_s_c bch2_btree_iter_peek_slot(struct btree_iter *);
|
||||
struct bkey_s_c bch2_btree_iter_next_slot(struct btree_iter *);
|
||||
|
||||
void bch2_btree_iter_set_pos_same_leaf(struct btree_iter *, struct bpos);
|
||||
void __bch2_btree_iter_set_pos(struct btree_iter *, struct bpos, bool);
|
||||
void bch2_btree_iter_set_pos(struct btree_iter *, struct bpos);
|
||||
|
||||
static inline struct bpos btree_type_successor(enum btree_id id,
|
||||
|
@ -64,9 +64,7 @@ struct btree_alloc {
|
||||
struct btree {
|
||||
/* Hottest entries first */
|
||||
struct rhash_head hash;
|
||||
|
||||
/* Key/pointer for this btree node */
|
||||
__BKEY_PADDED(key, BKEY_BTREE_PTR_VAL_U64s_MAX);
|
||||
u64 hash_val;
|
||||
|
||||
struct six_lock lock;
|
||||
|
||||
@ -133,6 +131,9 @@ struct btree {
|
||||
#ifdef CONFIG_BCACHEFS_DEBUG
|
||||
bool *expensive_debug_checks;
|
||||
#endif
|
||||
|
||||
/* Key/pointer for this btree node */
|
||||
__BKEY_PADDED(key, BKEY_BTREE_PTR_VAL_U64s_MAX);
|
||||
};
|
||||
|
||||
struct btree_cache {
|
||||
|
@ -70,7 +70,7 @@ int bch2_btree_delete_range(struct bch_fs *, enum btree_id,
|
||||
int bch2_btree_node_rewrite(struct bch_fs *c, struct btree_iter *,
|
||||
__le64, unsigned);
|
||||
int bch2_btree_node_update_key(struct bch_fs *, struct btree_iter *,
|
||||
struct btree *, struct bkey_i_btree_ptr *);
|
||||
struct btree *, struct bkey_i *);
|
||||
|
||||
int bch2_trans_update(struct btree_trans *, struct btree_iter *,
|
||||
struct bkey_i *, enum btree_trigger_flags);
|
||||
|
@ -332,7 +332,11 @@ retry:
|
||||
goto retry;
|
||||
}
|
||||
|
||||
bkey_btree_ptr_init(&tmp.k);
|
||||
if (c->sb.features & (1ULL << BCH_FEATURE_btree_ptr_v2))
|
||||
bkey_btree_ptr_v2_init(&tmp.k);
|
||||
else
|
||||
bkey_btree_ptr_init(&tmp.k);
|
||||
|
||||
bch2_alloc_sectors_append_ptrs(c, wp, &tmp.k, c->opts.btree_node_size);
|
||||
|
||||
bch2_open_bucket_get(c, wp, &ob);
|
||||
@ -354,14 +358,13 @@ static struct btree *bch2_btree_node_alloc(struct btree_update *as, unsigned lev
|
||||
{
|
||||
struct bch_fs *c = as->c;
|
||||
struct btree *b;
|
||||
int ret;
|
||||
|
||||
BUG_ON(level >= BTREE_MAX_DEPTH);
|
||||
BUG_ON(!as->reserve->nr);
|
||||
|
||||
b = as->reserve->b[--as->reserve->nr];
|
||||
|
||||
BUG_ON(bch2_btree_node_hash_insert(&c->btree_cache, b, level, as->btree_id));
|
||||
|
||||
set_btree_node_accessed(b);
|
||||
set_btree_node_dirty(b);
|
||||
set_btree_node_need_write(b);
|
||||
@ -372,7 +375,16 @@ static struct btree *bch2_btree_node_alloc(struct btree_update *as, unsigned lev
|
||||
b->data->flags = 0;
|
||||
SET_BTREE_NODE_ID(b->data, as->btree_id);
|
||||
SET_BTREE_NODE_LEVEL(b->data, level);
|
||||
b->data->ptr = bkey_i_to_btree_ptr(&b->key)->v.start[0];
|
||||
b->data->ptr = bch2_bkey_ptrs_c(bkey_i_to_s_c(&b->key)).start->ptr;
|
||||
|
||||
if (b->key.k.type == KEY_TYPE_btree_ptr_v2) {
|
||||
struct bkey_i_btree_ptr_v2 *bp = bkey_i_to_btree_ptr_v2(&b->key);
|
||||
|
||||
bp->v.mem_ptr = 0;
|
||||
bp->v.seq = b->data->keys.seq;
|
||||
bp->v.sectors_written = 0;
|
||||
bp->v.sectors = cpu_to_le16(c->opts.btree_node_size);
|
||||
}
|
||||
|
||||
if (c->sb.features & (1ULL << BCH_FEATURE_new_extent_overwrite))
|
||||
SET_BTREE_NODE_NEW_EXTENT_OVERWRITE(b->data, true);
|
||||
@ -385,10 +397,26 @@ static struct btree *bch2_btree_node_alloc(struct btree_update *as, unsigned lev
|
||||
|
||||
btree_node_will_make_reachable(as, b);
|
||||
|
||||
ret = bch2_btree_node_hash_insert(&c->btree_cache, b, level, as->btree_id);
|
||||
BUG_ON(ret);
|
||||
|
||||
trace_btree_node_alloc(c, b);
|
||||
return b;
|
||||
}
|
||||
|
||||
static void btree_set_min(struct btree *b, struct bpos pos)
|
||||
{
|
||||
if (b->key.k.type == KEY_TYPE_btree_ptr_v2)
|
||||
bkey_i_to_btree_ptr_v2(&b->key)->v.min_key = pos;
|
||||
b->data->min_key = pos;
|
||||
}
|
||||
|
||||
static void btree_set_max(struct btree *b, struct bpos pos)
|
||||
{
|
||||
b->key.k.p = pos;
|
||||
b->data->max_key = pos;
|
||||
}
|
||||
|
||||
struct btree *__bch2_btree_node_alloc_replacement(struct btree_update *as,
|
||||
struct btree *b,
|
||||
struct bkey_format format)
|
||||
@ -397,11 +425,12 @@ struct btree *__bch2_btree_node_alloc_replacement(struct btree_update *as,
|
||||
|
||||
n = bch2_btree_node_alloc(as, b->level);
|
||||
|
||||
n->data->min_key = b->data->min_key;
|
||||
n->data->max_key = b->data->max_key;
|
||||
n->data->format = format;
|
||||
SET_BTREE_NODE_SEQ(n->data, BTREE_NODE_SEQ(b->data) + 1);
|
||||
|
||||
btree_set_min(n, b->data->min_key);
|
||||
btree_set_max(n, b->data->max_key);
|
||||
|
||||
n->data->format = format;
|
||||
btree_node_set_format(n, format);
|
||||
|
||||
bch2_btree_sort_into(as->c, n, b);
|
||||
@ -431,10 +460,9 @@ static struct btree *__btree_root_alloc(struct btree_update *as, unsigned level)
|
||||
{
|
||||
struct btree *b = bch2_btree_node_alloc(as, level);
|
||||
|
||||
b->data->min_key = POS_MIN;
|
||||
b->data->max_key = POS_MAX;
|
||||
btree_set_min(b, POS_MIN);
|
||||
btree_set_max(b, POS_MAX);
|
||||
b->data->format = bch2_btree_calc_format(b);
|
||||
b->key.k.p = POS_MAX;
|
||||
|
||||
btree_node_set_format(b, b->data->format);
|
||||
bch2_btree_build_aux_trees(b);
|
||||
@ -1263,10 +1291,8 @@ static struct btree *__btree_split_node(struct btree_update *as,
|
||||
|
||||
BUG_ON(!prev);
|
||||
|
||||
n1->key.k.p = bkey_unpack_pos(n1, prev);
|
||||
n1->data->max_key = n1->key.k.p;
|
||||
n2->data->min_key =
|
||||
btree_type_successor(n1->btree_id, n1->key.k.p);
|
||||
btree_set_max(n1, bkey_unpack_pos(n1, prev));
|
||||
btree_set_min(n2, btree_type_successor(n1->btree_id, n1->key.k.p));
|
||||
|
||||
set2->u64s = cpu_to_le16((u64 *) vstruct_end(set1) - (u64 *) k);
|
||||
set1->u64s = cpu_to_le16(le16_to_cpu(set1->u64s) - le16_to_cpu(set2->u64s));
|
||||
@ -1749,10 +1775,9 @@ retry:
|
||||
|
||||
n = bch2_btree_node_alloc(as, b->level);
|
||||
|
||||
n->data->min_key = prev->data->min_key;
|
||||
n->data->max_key = next->data->max_key;
|
||||
btree_set_min(n, prev->data->min_key);
|
||||
btree_set_max(n, next->data->max_key);
|
||||
n->data->format = new_f;
|
||||
n->key.k.p = next->key.k.p;
|
||||
|
||||
btree_node_set_format(n, new_f);
|
||||
|
||||
@ -1944,7 +1969,7 @@ static void __bch2_btree_node_update_key(struct bch_fs *c,
|
||||
struct btree_update *as,
|
||||
struct btree_iter *iter,
|
||||
struct btree *b, struct btree *new_hash,
|
||||
struct bkey_i_btree_ptr *new_key)
|
||||
struct bkey_i *new_key)
|
||||
{
|
||||
struct btree *parent;
|
||||
int ret;
|
||||
@ -1989,20 +2014,20 @@ static void __bch2_btree_node_update_key(struct bch_fs *c,
|
||||
*/
|
||||
ret = bch2_disk_reservation_add(c, &as->reserve->disk_res,
|
||||
c->opts.btree_node_size *
|
||||
bch2_bkey_nr_ptrs(bkey_i_to_s_c(&new_key->k_i)),
|
||||
bch2_bkey_nr_ptrs(bkey_i_to_s_c(new_key)),
|
||||
BCH_DISK_RESERVATION_NOFAIL);
|
||||
BUG_ON(ret);
|
||||
|
||||
parent = btree_node_parent(iter, b);
|
||||
if (parent) {
|
||||
if (new_hash) {
|
||||
bkey_copy(&new_hash->key, &new_key->k_i);
|
||||
bkey_copy(&new_hash->key, new_key);
|
||||
ret = bch2_btree_node_hash_insert(&c->btree_cache,
|
||||
new_hash, b->level, b->btree_id);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
|
||||
bch2_keylist_add(&as->parent_keys, &new_key->k_i);
|
||||
bch2_keylist_add(&as->parent_keys, new_key);
|
||||
bch2_btree_insert_node(as, parent, iter, &as->parent_keys, 0);
|
||||
|
||||
if (new_hash) {
|
||||
@ -2011,12 +2036,12 @@ static void __bch2_btree_node_update_key(struct bch_fs *c,
|
||||
|
||||
bch2_btree_node_hash_remove(&c->btree_cache, b);
|
||||
|
||||
bkey_copy(&b->key, &new_key->k_i);
|
||||
bkey_copy(&b->key, new_key);
|
||||
ret = __bch2_btree_node_hash_insert(&c->btree_cache, b);
|
||||
BUG_ON(ret);
|
||||
mutex_unlock(&c->btree_cache.lock);
|
||||
} else {
|
||||
bkey_copy(&b->key, &new_key->k_i);
|
||||
bkey_copy(&b->key, new_key);
|
||||
}
|
||||
} else {
|
||||
struct bch_fs_usage *fs_usage;
|
||||
@ -2029,11 +2054,11 @@ static void __bch2_btree_node_update_key(struct bch_fs *c,
|
||||
percpu_down_read(&c->mark_lock);
|
||||
fs_usage = bch2_fs_usage_scratch_get(c);
|
||||
|
||||
bch2_mark_key_locked(c, bkey_i_to_s_c(&new_key->k_i),
|
||||
bch2_mark_key_locked(c, bkey_i_to_s_c(new_key),
|
||||
0, 0, fs_usage, 0,
|
||||
BTREE_TRIGGER_INSERT);
|
||||
if (gc_visited(c, gc_pos_btree_root(b->btree_id)))
|
||||
bch2_mark_key_locked(c, bkey_i_to_s_c(&new_key->k_i),
|
||||
bch2_mark_key_locked(c, bkey_i_to_s_c(new_key),
|
||||
0, 0, NULL, 0,
|
||||
BTREE_TRIGGER_INSERT||
|
||||
BTREE_TRIGGER_GC);
|
||||
@ -2047,16 +2072,16 @@ static void __bch2_btree_node_update_key(struct bch_fs *c,
|
||||
percpu_up_read(&c->mark_lock);
|
||||
mutex_unlock(&c->btree_interior_update_lock);
|
||||
|
||||
if (PTR_HASH(&new_key->k_i) != PTR_HASH(&b->key)) {
|
||||
if (btree_ptr_hash_val(new_key) != b->hash_val) {
|
||||
mutex_lock(&c->btree_cache.lock);
|
||||
bch2_btree_node_hash_remove(&c->btree_cache, b);
|
||||
|
||||
bkey_copy(&b->key, &new_key->k_i);
|
||||
bkey_copy(&b->key, new_key);
|
||||
ret = __bch2_btree_node_hash_insert(&c->btree_cache, b);
|
||||
BUG_ON(ret);
|
||||
mutex_unlock(&c->btree_cache.lock);
|
||||
} else {
|
||||
bkey_copy(&b->key, &new_key->k_i);
|
||||
bkey_copy(&b->key, new_key);
|
||||
}
|
||||
|
||||
btree_update_updated_root(as);
|
||||
@ -2068,7 +2093,7 @@ static void __bch2_btree_node_update_key(struct bch_fs *c,
|
||||
|
||||
int bch2_btree_node_update_key(struct bch_fs *c, struct btree_iter *iter,
|
||||
struct btree *b,
|
||||
struct bkey_i_btree_ptr *new_key)
|
||||
struct bkey_i *new_key)
|
||||
{
|
||||
struct btree *parent = btree_node_parent(iter, b);
|
||||
struct btree_update *as = NULL;
|
||||
@ -2091,8 +2116,11 @@ int bch2_btree_node_update_key(struct bch_fs *c, struct btree_iter *iter,
|
||||
}
|
||||
}
|
||||
|
||||
/* check PTR_HASH() after @b is locked by btree_iter_traverse(): */
|
||||
if (PTR_HASH(&new_key->k_i) != PTR_HASH(&b->key)) {
|
||||
/*
|
||||
* check btree_ptr_hash_val() after @b is locked by
|
||||
* btree_iter_traverse():
|
||||
*/
|
||||
if (btree_ptr_hash_val(new_key) != b->hash_val) {
|
||||
/* bch2_btree_reserve_get will unlock */
|
||||
ret = bch2_btree_cache_cannibalize_lock(c, &cl);
|
||||
if (ret) {
|
||||
@ -2134,7 +2162,7 @@ int bch2_btree_node_update_key(struct bch_fs *c, struct btree_iter *iter,
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = bch2_mark_bkey_replicas(c, bkey_i_to_s_c(&new_key->k_i));
|
||||
ret = bch2_mark_bkey_replicas(c, bkey_i_to_s_c(new_key));
|
||||
if (ret)
|
||||
goto err_free_update;
|
||||
|
||||
@ -2193,14 +2221,14 @@ void bch2_btree_root_alloc(struct bch_fs *c, enum btree_id id)
|
||||
|
||||
bkey_btree_ptr_init(&b->key);
|
||||
b->key.k.p = POS_MAX;
|
||||
PTR_HASH(&b->key) = U64_MAX - id;
|
||||
*((u64 *) bkey_i_to_btree_ptr(&b->key)->v.start) = U64_MAX - id;
|
||||
|
||||
bch2_bset_init_first(b, &b->data->keys);
|
||||
bch2_btree_build_aux_trees(b);
|
||||
|
||||
b->data->flags = 0;
|
||||
b->data->min_key = POS_MIN;
|
||||
b->data->max_key = POS_MAX;
|
||||
btree_set_min(b, POS_MIN);
|
||||
btree_set_max(b, POS_MAX);
|
||||
b->data->format = bch2_btree_calc_format(b);
|
||||
btree_node_set_format(b, b->data->format);
|
||||
|
||||
|
@ -53,9 +53,8 @@ bool bch2_btree_bset_insert_key(struct btree_iter *iter,
|
||||
struct btree_node_iter *node_iter,
|
||||
struct bkey_i *insert)
|
||||
{
|
||||
const struct bkey_format *f = &b->format;
|
||||
struct bkey_packed *k;
|
||||
unsigned clobber_u64s;
|
||||
unsigned clobber_u64s = 0, new_u64s = 0;
|
||||
|
||||
EBUG_ON(btree_node_just_written(b));
|
||||
EBUG_ON(bset_written(b, btree_bset_last(b)));
|
||||
@ -68,30 +67,25 @@ bool bch2_btree_bset_insert_key(struct btree_iter *iter,
|
||||
k = NULL;
|
||||
|
||||
/* @k is the key being overwritten/deleted, if any: */
|
||||
|
||||
EBUG_ON(k && bkey_whiteout(k));
|
||||
|
||||
/* Deleting, but not found? nothing to do: */
|
||||
if (bkey_whiteout(&insert->k) && !k)
|
||||
return false;
|
||||
|
||||
if (bkey_whiteout(&insert->k)) {
|
||||
/* Deleting: */
|
||||
|
||||
/* Not found? Nothing to do: */
|
||||
if (!k)
|
||||
return false;
|
||||
|
||||
btree_account_key_drop(b, k);
|
||||
k->type = KEY_TYPE_deleted;
|
||||
|
||||
if (k->needs_whiteout) {
|
||||
if (k->needs_whiteout)
|
||||
push_whiteout(iter->trans->c, b, k);
|
||||
k->needs_whiteout = false;
|
||||
}
|
||||
k->needs_whiteout = false;
|
||||
|
||||
if (k >= btree_bset_last(b)->start) {
|
||||
clobber_u64s = k->u64s;
|
||||
|
||||
bch2_bset_delete(b, k, clobber_u64s);
|
||||
bch2_btree_node_iter_fix(iter, b, node_iter, k,
|
||||
clobber_u64s, 0);
|
||||
goto fix_iter;
|
||||
} else {
|
||||
bch2_btree_iter_fix_key_modified(iter, b, k);
|
||||
}
|
||||
@ -101,14 +95,6 @@ bool bch2_btree_bset_insert_key(struct btree_iter *iter,
|
||||
|
||||
if (k) {
|
||||
/* Overwriting: */
|
||||
if (!bkey_written(b, k) &&
|
||||
bkey_val_u64s(&insert->k) == bkeyp_val_u64s(f, k)) {
|
||||
k->type = insert->k.type;
|
||||
memcpy_u64s(bkeyp_val(f, k), &insert->v,
|
||||
bkey_val_u64s(&insert->k));
|
||||
return true;
|
||||
}
|
||||
|
||||
btree_account_key_drop(b, k);
|
||||
k->type = KEY_TYPE_deleted;
|
||||
|
||||
@ -124,11 +110,13 @@ bool bch2_btree_bset_insert_key(struct btree_iter *iter,
|
||||
}
|
||||
|
||||
k = bch2_btree_node_iter_bset_pos(node_iter, b, bset_tree_last(b));
|
||||
clobber_u64s = 0;
|
||||
overwrite:
|
||||
bch2_bset_insert(b, node_iter, k, insert, clobber_u64s);
|
||||
bch2_btree_node_iter_fix(iter, b, node_iter, k,
|
||||
clobber_u64s, k->u64s);
|
||||
new_u64s = k->u64s;
|
||||
fix_iter:
|
||||
if (clobber_u64s != new_u64s)
|
||||
bch2_btree_node_iter_fix(iter, b, node_iter, k,
|
||||
clobber_u64s, new_u64s);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -792,7 +780,7 @@ int bch2_trans_update(struct btree_trans *trans, struct btree_iter *iter,
|
||||
|
||||
iter->flags |= BTREE_ITER_KEEP_UNTIL_COMMIT;
|
||||
|
||||
if (iter->flags & BTREE_ITER_IS_EXTENTS) {
|
||||
if (btree_node_type_is_extents(iter->btree_id)) {
|
||||
iter->pos_after_commit = k->k.p;
|
||||
iter->flags |= BTREE_ITER_SET_POS_AFTER_COMMIT;
|
||||
}
|
||||
@ -910,7 +898,7 @@ retry:
|
||||
*/
|
||||
delete.k.p = iter->pos;
|
||||
|
||||
if (iter->flags & BTREE_ITER_IS_EXTENTS) {
|
||||
if (btree_node_type_is_extents(iter->btree_id)) {
|
||||
unsigned max_sectors =
|
||||
KEY_SIZE_MAX & (~0 << trans->c->block_bits);
|
||||
|
||||
|
@ -1194,6 +1194,7 @@ int bch2_mark_key_locked(struct bch_fs *c,
|
||||
ret = bch2_mark_alloc(c, k, fs_usage, journal_seq, flags);
|
||||
break;
|
||||
case KEY_TYPE_btree_ptr:
|
||||
case KEY_TYPE_btree_ptr_v2:
|
||||
sectors = !(flags & BTREE_TRIGGER_OVERWRITE)
|
||||
? c->opts.btree_node_size
|
||||
: -c->opts.btree_node_size;
|
||||
@ -1729,6 +1730,7 @@ int bch2_trans_mark_key(struct btree_trans *trans, struct bkey_s_c k,
|
||||
|
||||
switch (k.k->type) {
|
||||
case KEY_TYPE_btree_ptr:
|
||||
case KEY_TYPE_btree_ptr_v2:
|
||||
sectors = !(flags & BTREE_TRIGGER_OVERWRITE)
|
||||
? c->opts.btree_node_size
|
||||
: -c->opts.btree_node_size;
|
||||
|
@ -97,7 +97,8 @@ static inline struct bucket *PTR_BUCKET(struct bch_dev *ca,
|
||||
static inline enum bch_data_type ptr_data_type(const struct bkey *k,
|
||||
const struct bch_extent_ptr *ptr)
|
||||
{
|
||||
if (k->type == KEY_TYPE_btree_ptr)
|
||||
if (k->type == KEY_TYPE_btree_ptr ||
|
||||
k->type == KEY_TYPE_btree_ptr_v2)
|
||||
return BCH_DATA_BTREE;
|
||||
|
||||
return ptr->cached ? BCH_DATA_CACHED : BCH_DATA_USER;
|
||||
|
@ -1280,9 +1280,8 @@ int bch2_stripes_write(struct bch_fs *c, unsigned flags, bool *wrote)
|
||||
int bch2_stripes_read(struct bch_fs *c, struct journal_keys *journal_keys)
|
||||
{
|
||||
struct btree_trans trans;
|
||||
struct btree_iter *btree_iter;
|
||||
struct journal_iter journal_iter;
|
||||
struct bkey_s_c btree_k, journal_k;
|
||||
struct btree_and_journal_iter iter;
|
||||
struct bkey_s_c k;
|
||||
int ret;
|
||||
|
||||
ret = bch2_fs_ec_start(c);
|
||||
@ -1291,38 +1290,16 @@ int bch2_stripes_read(struct bch_fs *c, struct journal_keys *journal_keys)
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
btree_iter = bch2_trans_get_iter(&trans, BTREE_ID_EC, POS_MIN, 0);
|
||||
journal_iter = bch2_journal_iter_init(journal_keys, BTREE_ID_EC);
|
||||
bch2_btree_and_journal_iter_init(&iter, &trans, journal_keys,
|
||||
BTREE_ID_EC, POS_MIN);
|
||||
|
||||
btree_k = bch2_btree_iter_peek(btree_iter);
|
||||
journal_k = bch2_journal_iter_peek(&journal_iter);
|
||||
|
||||
while (1) {
|
||||
bool btree;
|
||||
|
||||
if (btree_k.k && journal_k.k) {
|
||||
int cmp = bkey_cmp(btree_k.k->p, journal_k.k->p);
|
||||
|
||||
if (!cmp)
|
||||
btree_k = bch2_btree_iter_next(btree_iter);
|
||||
btree = cmp < 0;
|
||||
} else if (btree_k.k) {
|
||||
btree = true;
|
||||
} else if (journal_k.k) {
|
||||
btree = false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
bch2_mark_key(c, btree ? btree_k : journal_k,
|
||||
0, 0, NULL, 0,
|
||||
while ((k = bch2_btree_and_journal_iter_peek(&iter)).k) {
|
||||
bch2_mark_key(c, k, 0, 0, NULL, 0,
|
||||
BTREE_TRIGGER_ALLOC_READ|
|
||||
BTREE_TRIGGER_NOATOMIC);
|
||||
|
||||
if (btree)
|
||||
btree_k = bch2_btree_iter_next(btree_iter);
|
||||
else
|
||||
journal_k = bch2_journal_iter_next(&journal_iter);
|
||||
bch2_btree_and_journal_iter_advance(&iter);
|
||||
}
|
||||
|
||||
ret = bch2_trans_exit(&trans) ?: ret;
|
||||
|
@ -12,6 +12,7 @@ void bch2_stripe_to_text(struct printbuf *, struct bch_fs *,
|
||||
#define bch2_bkey_ops_stripe (struct bkey_ops) { \
|
||||
.key_invalid = bch2_stripe_invalid, \
|
||||
.val_to_text = bch2_stripe_to_text, \
|
||||
.swab = bch2_ptr_swab, \
|
||||
}
|
||||
|
||||
static inline unsigned stripe_csums_per_device(const struct bch_stripe *s)
|
||||
|
@ -749,6 +749,7 @@ void bch2_bkey_append_ptr(struct bkey_i *k,
|
||||
|
||||
switch (k->k.type) {
|
||||
case KEY_TYPE_btree_ptr:
|
||||
case KEY_TYPE_btree_ptr_v2:
|
||||
case KEY_TYPE_extent:
|
||||
EBUG_ON(bkey_val_u64s(&k->k) >= BKEY_EXTENT_VAL_U64s_MAX);
|
||||
|
||||
@ -1031,6 +1032,8 @@ const char *bch2_bkey_ptrs_invalid(const struct bch_fs *c, struct bkey_s_c k)
|
||||
|
||||
if (k.k->type == KEY_TYPE_btree_ptr)
|
||||
size_ondisk = c->opts.btree_node_size;
|
||||
if (k.k->type == KEY_TYPE_btree_ptr_v2)
|
||||
size_ondisk = le16_to_cpu(bkey_s_c_to_btree_ptr_v2(k).v->sectors);
|
||||
|
||||
bkey_extent_entry_for_each(ptrs, entry) {
|
||||
if (__extent_entry_type(entry) >= BCH_EXTENT_ENTRY_MAX)
|
||||
@ -1079,17 +1082,19 @@ const char *bch2_bkey_ptrs_invalid(const struct bch_fs *c, struct bkey_s_c k)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bch2_ptr_swab(const struct bkey_format *f, struct bkey_packed *k)
|
||||
void bch2_ptr_swab(struct bkey_s k)
|
||||
{
|
||||
struct bkey_ptrs ptrs = bch2_bkey_ptrs(k);
|
||||
union bch_extent_entry *entry;
|
||||
u64 *d = (u64 *) bkeyp_val(f, k);
|
||||
unsigned i;
|
||||
u64 *d;
|
||||
|
||||
for (i = 0; i < bkeyp_val_u64s(f, k); i++)
|
||||
d[i] = swab64(d[i]);
|
||||
for (d = (u64 *) ptrs.start;
|
||||
d != (u64 *) ptrs.end;
|
||||
d++)
|
||||
*d = swab64(*d);
|
||||
|
||||
for (entry = (union bch_extent_entry *) d;
|
||||
entry < (union bch_extent_entry *) (d + bkeyp_val_u64s(f, k));
|
||||
for (entry = ptrs.start;
|
||||
entry < ptrs.end;
|
||||
entry = extent_entry_next(entry)) {
|
||||
switch (extent_entry_type(entry)) {
|
||||
case BCH_EXTENT_ENTRY_ptr:
|
||||
|
@ -225,6 +225,13 @@ static inline struct bkey_ptrs_c bch2_bkey_ptrs_c(struct bkey_s_c k)
|
||||
bkey_val_end(r),
|
||||
};
|
||||
}
|
||||
case KEY_TYPE_btree_ptr_v2: {
|
||||
struct bkey_s_c_btree_ptr_v2 e = bkey_s_c_to_btree_ptr_v2(k);
|
||||
return (struct bkey_ptrs_c) {
|
||||
to_entry(&e.v->start[0]),
|
||||
to_entry(extent_entry_last(e))
|
||||
};
|
||||
}
|
||||
default:
|
||||
return (struct bkey_ptrs_c) { NULL, NULL };
|
||||
}
|
||||
@ -372,6 +379,13 @@ void bch2_btree_ptr_to_text(struct printbuf *, struct bch_fs *,
|
||||
.swab = bch2_ptr_swab, \
|
||||
}
|
||||
|
||||
#define bch2_bkey_ops_btree_ptr_v2 (struct bkey_ops) { \
|
||||
.key_invalid = bch2_btree_ptr_invalid, \
|
||||
.key_debugcheck = bch2_btree_ptr_debugcheck, \
|
||||
.val_to_text = bch2_btree_ptr_to_text, \
|
||||
.swab = bch2_ptr_swab, \
|
||||
}
|
||||
|
||||
/* KEY_TYPE_extent: */
|
||||
|
||||
const char *bch2_extent_invalid(const struct bch_fs *, struct bkey_s_c);
|
||||
@ -416,6 +430,7 @@ static inline bool bkey_extent_is_direct_data(const struct bkey *k)
|
||||
{
|
||||
switch (k->type) {
|
||||
case KEY_TYPE_btree_ptr:
|
||||
case KEY_TYPE_btree_ptr_v2:
|
||||
case KEY_TYPE_extent:
|
||||
case KEY_TYPE_reflink_v:
|
||||
return true;
|
||||
@ -532,7 +547,7 @@ void bch2_bkey_ptrs_to_text(struct printbuf *, struct bch_fs *,
|
||||
struct bkey_s_c);
|
||||
const char *bch2_bkey_ptrs_invalid(const struct bch_fs *, struct bkey_s_c);
|
||||
|
||||
void bch2_ptr_swab(const struct bkey_format *, struct bkey_packed *);
|
||||
void bch2_ptr_swab(struct bkey_s);
|
||||
|
||||
/* Generic extent code: */
|
||||
|
||||
|
@ -19,14 +19,15 @@ int bch2_create_trans(struct btree_trans *trans, u64 dir_inum,
|
||||
struct posix_acl *acl)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct btree_iter *dir_iter;
|
||||
struct btree_iter *dir_iter = NULL;
|
||||
struct bch_hash_info hash = bch2_hash_info_init(c, new_inode);
|
||||
u64 now = bch2_current_time(trans->c);
|
||||
int ret;
|
||||
|
||||
dir_iter = bch2_inode_peek(trans, dir_u, dir_inum, BTREE_ITER_INTENT);
|
||||
if (IS_ERR(dir_iter))
|
||||
return PTR_ERR(dir_iter);
|
||||
ret = PTR_ERR_OR_ZERO(dir_iter);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
bch2_inode_init_late(new_inode, now, uid, gid, mode, rdev, dir_u);
|
||||
|
||||
@ -37,20 +38,20 @@ int bch2_create_trans(struct btree_trans *trans, u64 dir_inum,
|
||||
BLOCKDEV_INODE_MAX, 0,
|
||||
&c->unused_inode_hint);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
if (default_acl) {
|
||||
ret = bch2_set_acl_trans(trans, new_inode, &hash,
|
||||
default_acl, ACL_TYPE_DEFAULT);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (acl) {
|
||||
ret = bch2_set_acl_trans(trans, new_inode, &hash,
|
||||
acl, ACL_TYPE_ACCESS);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
@ -62,48 +63,55 @@ int bch2_create_trans(struct btree_trans *trans, u64 dir_inum,
|
||||
|
||||
ret = bch2_inode_write(trans, dir_iter, dir_u);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
ret = bch2_dirent_create(trans, dir_inum, &dir_hash,
|
||||
mode_to_type(new_inode->bi_mode),
|
||||
name, new_inode->bi_inum,
|
||||
BCH_HASH_SET_MUST_CREATE);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
bch2_trans_iter_put(trans, dir_iter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bch2_link_trans(struct btree_trans *trans, u64 dir_inum,
|
||||
u64 inum, struct bch_inode_unpacked *dir_u,
|
||||
struct bch_inode_unpacked *inode_u, const struct qstr *name)
|
||||
{
|
||||
struct btree_iter *dir_iter, *inode_iter;
|
||||
struct btree_iter *dir_iter = NULL, *inode_iter = NULL;
|
||||
struct bch_hash_info dir_hash;
|
||||
u64 now = bch2_current_time(trans->c);
|
||||
int ret;
|
||||
|
||||
inode_iter = bch2_inode_peek(trans, inode_u, inum, BTREE_ITER_INTENT);
|
||||
if (IS_ERR(inode_iter))
|
||||
return PTR_ERR(inode_iter);
|
||||
ret = PTR_ERR_OR_ZERO(inode_iter);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
inode_u->bi_ctime = now;
|
||||
bch2_inode_nlink_inc(inode_u);
|
||||
|
||||
dir_iter = bch2_inode_peek(trans, dir_u, dir_inum, 0);
|
||||
if (IS_ERR(dir_iter))
|
||||
return PTR_ERR(dir_iter);
|
||||
ret = PTR_ERR_OR_ZERO(dir_iter);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
dir_u->bi_mtime = dir_u->bi_ctime = now;
|
||||
|
||||
dir_hash = bch2_hash_info_init(trans->c, dir_u);
|
||||
bch2_trans_iter_put(trans, dir_iter);
|
||||
|
||||
return bch2_dirent_create(trans, dir_inum, &dir_hash,
|
||||
ret = bch2_dirent_create(trans, dir_inum, &dir_hash,
|
||||
mode_to_type(inode_u->bi_mode),
|
||||
name, inum, BCH_HASH_SET_MUST_CREATE) ?:
|
||||
bch2_inode_write(trans, dir_iter, dir_u) ?:
|
||||
bch2_inode_write(trans, inode_iter, inode_u);
|
||||
err:
|
||||
bch2_trans_iter_put(trans, dir_iter);
|
||||
bch2_trans_iter_put(trans, inode_iter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bch2_unlink_trans(struct btree_trans *trans,
|
||||
@ -111,39 +119,49 @@ int bch2_unlink_trans(struct btree_trans *trans,
|
||||
struct bch_inode_unpacked *inode_u,
|
||||
const struct qstr *name)
|
||||
{
|
||||
struct btree_iter *dir_iter, *dirent_iter, *inode_iter;
|
||||
struct btree_iter *dir_iter = NULL, *dirent_iter = NULL,
|
||||
*inode_iter = NULL;
|
||||
struct bch_hash_info dir_hash;
|
||||
u64 inum, now = bch2_current_time(trans->c);
|
||||
struct bkey_s_c k;
|
||||
int ret;
|
||||
|
||||
dir_iter = bch2_inode_peek(trans, dir_u, dir_inum, BTREE_ITER_INTENT);
|
||||
if (IS_ERR(dir_iter))
|
||||
return PTR_ERR(dir_iter);
|
||||
ret = PTR_ERR_OR_ZERO(dir_iter);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
dir_hash = bch2_hash_info_init(trans->c, dir_u);
|
||||
|
||||
dirent_iter = __bch2_dirent_lookup_trans(trans, dir_inum, &dir_hash,
|
||||
name, BTREE_ITER_INTENT);
|
||||
if (IS_ERR(dirent_iter))
|
||||
return PTR_ERR(dirent_iter);
|
||||
ret = PTR_ERR_OR_ZERO(dirent_iter);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
k = bch2_btree_iter_peek_slot(dirent_iter);
|
||||
inum = le64_to_cpu(bkey_s_c_to_dirent(k).v->d_inum);
|
||||
|
||||
inode_iter = bch2_inode_peek(trans, inode_u, inum, BTREE_ITER_INTENT);
|
||||
if (IS_ERR(inode_iter))
|
||||
return PTR_ERR(inode_iter);
|
||||
ret = PTR_ERR_OR_ZERO(inode_iter);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
dir_u->bi_mtime = dir_u->bi_ctime = inode_u->bi_ctime = now;
|
||||
dir_u->bi_nlink -= S_ISDIR(inode_u->bi_mode);
|
||||
bch2_inode_nlink_dec(inode_u);
|
||||
|
||||
return (S_ISDIR(inode_u->bi_mode)
|
||||
ret = (S_ISDIR(inode_u->bi_mode)
|
||||
? bch2_empty_dir_trans(trans, inum)
|
||||
: 0) ?:
|
||||
bch2_dirent_delete_at(trans, &dir_hash, dirent_iter) ?:
|
||||
bch2_inode_write(trans, dir_iter, dir_u) ?:
|
||||
bch2_inode_write(trans, inode_iter, inode_u);
|
||||
err:
|
||||
bch2_trans_iter_put(trans, inode_iter);
|
||||
bch2_trans_iter_put(trans, dirent_iter);
|
||||
bch2_trans_iter_put(trans, dir_iter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool bch2_reinherit_attrs(struct bch_inode_unpacked *dst_u,
|
||||
@ -179,24 +197,26 @@ int bch2_rename_trans(struct btree_trans *trans,
|
||||
const struct qstr *dst_name,
|
||||
enum bch_rename_mode mode)
|
||||
{
|
||||
struct btree_iter *src_dir_iter, *dst_dir_iter = NULL;
|
||||
struct btree_iter *src_inode_iter, *dst_inode_iter = NULL;
|
||||
struct btree_iter *src_dir_iter = NULL, *dst_dir_iter = NULL;
|
||||
struct btree_iter *src_inode_iter = NULL, *dst_inode_iter = NULL;
|
||||
struct bch_hash_info src_hash, dst_hash;
|
||||
u64 src_inode, dst_inode, now = bch2_current_time(trans->c);
|
||||
int ret;
|
||||
|
||||
src_dir_iter = bch2_inode_peek(trans, src_dir_u, src_dir,
|
||||
BTREE_ITER_INTENT);
|
||||
if (IS_ERR(src_dir_iter))
|
||||
return PTR_ERR(src_dir_iter);
|
||||
ret = PTR_ERR_OR_ZERO(src_dir_iter);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
src_hash = bch2_hash_info_init(trans->c, src_dir_u);
|
||||
|
||||
if (dst_dir != src_dir) {
|
||||
dst_dir_iter = bch2_inode_peek(trans, dst_dir_u, dst_dir,
|
||||
BTREE_ITER_INTENT);
|
||||
if (IS_ERR(dst_dir_iter))
|
||||
return PTR_ERR(dst_dir_iter);
|
||||
ret = PTR_ERR_OR_ZERO(dst_dir_iter);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
dst_hash = bch2_hash_info_init(trans->c, dst_dir_u);
|
||||
} else {
|
||||
@ -211,38 +231,48 @@ int bch2_rename_trans(struct btree_trans *trans,
|
||||
dst_name, &dst_inode,
|
||||
mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
src_inode_iter = bch2_inode_peek(trans, src_inode_u, src_inode,
|
||||
BTREE_ITER_INTENT);
|
||||
if (IS_ERR(src_inode_iter))
|
||||
return PTR_ERR(src_inode_iter);
|
||||
ret = PTR_ERR_OR_ZERO(src_inode_iter);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (dst_inode) {
|
||||
dst_inode_iter = bch2_inode_peek(trans, dst_inode_u, dst_inode,
|
||||
BTREE_ITER_INTENT);
|
||||
if (IS_ERR(dst_inode_iter))
|
||||
return PTR_ERR(dst_inode_iter);
|
||||
ret = PTR_ERR_OR_ZERO(dst_inode_iter);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (mode == BCH_RENAME_OVERWRITE) {
|
||||
if (S_ISDIR(src_inode_u->bi_mode) !=
|
||||
S_ISDIR(dst_inode_u->bi_mode))
|
||||
return -ENOTDIR;
|
||||
S_ISDIR(dst_inode_u->bi_mode)) {
|
||||
ret = -ENOTDIR;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (S_ISDIR(dst_inode_u->bi_mode) &&
|
||||
bch2_empty_dir_trans(trans, dst_inode))
|
||||
return -ENOTEMPTY;
|
||||
bch2_empty_dir_trans(trans, dst_inode)) {
|
||||
ret = -ENOTEMPTY;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (bch2_reinherit_attrs(src_inode_u, dst_dir_u) &&
|
||||
S_ISDIR(src_inode_u->bi_mode))
|
||||
return -EXDEV;
|
||||
S_ISDIR(src_inode_u->bi_mode)) {
|
||||
ret = -EXDEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (mode == BCH_RENAME_EXCHANGE &&
|
||||
bch2_reinherit_attrs(dst_inode_u, src_dir_u) &&
|
||||
S_ISDIR(dst_inode_u->bi_mode))
|
||||
return -EXDEV;
|
||||
S_ISDIR(dst_inode_u->bi_mode)) {
|
||||
ret = -EXDEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (S_ISDIR(src_inode_u->bi_mode)) {
|
||||
src_dir_u->bi_nlink--;
|
||||
@ -270,7 +300,7 @@ int bch2_rename_trans(struct btree_trans *trans,
|
||||
if (dst_inode)
|
||||
dst_inode_u->bi_ctime = now;
|
||||
|
||||
return bch2_inode_write(trans, src_dir_iter, src_dir_u) ?:
|
||||
ret = bch2_inode_write(trans, src_dir_iter, src_dir_u) ?:
|
||||
(src_dir != dst_dir
|
||||
? bch2_inode_write(trans, dst_dir_iter, dst_dir_u)
|
||||
: 0 ) ?:
|
||||
@ -278,4 +308,10 @@ int bch2_rename_trans(struct btree_trans *trans,
|
||||
(dst_inode
|
||||
? bch2_inode_write(trans, dst_inode_iter, dst_inode_u)
|
||||
: 0 );
|
||||
err:
|
||||
bch2_trans_iter_put(trans, dst_inode_iter);
|
||||
bch2_trans_iter_put(trans, src_inode_iter);
|
||||
bch2_trans_iter_put(trans, dst_dir_iter);
|
||||
bch2_trans_iter_put(trans, src_dir_iter);
|
||||
return ret;
|
||||
}
|
||||
|
@ -362,16 +362,16 @@ int bch2_inode_create(struct btree_trans *trans,
|
||||
struct bch_inode_unpacked *inode_u,
|
||||
u64 min, u64 max, u64 *hint)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct bkey_inode_buf *inode_p;
|
||||
struct btree_iter *iter;
|
||||
struct btree_iter *iter = NULL;
|
||||
struct bkey_s_c k;
|
||||
u64 start;
|
||||
int ret;
|
||||
|
||||
if (!max)
|
||||
max = ULLONG_MAX;
|
||||
|
||||
if (c->opts.inodes_32bit)
|
||||
if (trans->c->opts.inodes_32bit)
|
||||
max = min_t(u64, max, U32_MAX);
|
||||
|
||||
start = READ_ONCE(*hint);
|
||||
@ -382,48 +382,37 @@ int bch2_inode_create(struct btree_trans *trans,
|
||||
inode_p = bch2_trans_kmalloc(trans, sizeof(*inode_p));
|
||||
if (IS_ERR(inode_p))
|
||||
return PTR_ERR(inode_p);
|
||||
|
||||
iter = bch2_trans_get_iter(trans,
|
||||
BTREE_ID_INODES, POS(start, 0),
|
||||
BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
|
||||
if (IS_ERR(iter))
|
||||
return PTR_ERR(iter);
|
||||
again:
|
||||
while (1) {
|
||||
struct bkey_s_c k = bch2_btree_iter_peek_slot(iter);
|
||||
|
||||
ret = bkey_err(k);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (k.k->type) {
|
||||
case KEY_TYPE_inode:
|
||||
/* slot used */
|
||||
if (iter->pos.inode >= max)
|
||||
goto out;
|
||||
|
||||
bch2_btree_iter_next_slot(iter);
|
||||
for_each_btree_key(trans, iter, BTREE_ID_INODES, POS(start, 0),
|
||||
BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
|
||||
if (iter->pos.inode > max)
|
||||
break;
|
||||
|
||||
default:
|
||||
*hint = k.k->p.inode;
|
||||
inode_u->bi_inum = k.k->p.inode;
|
||||
inode_u->bi_generation = bkey_generation(k);
|
||||
|
||||
bch2_inode_pack(inode_p, inode_u);
|
||||
bch2_trans_update(trans, iter, &inode_p->inode.k_i, 0);
|
||||
return 0;
|
||||
}
|
||||
if (k.k->type != KEY_TYPE_inode)
|
||||
goto found_slot;
|
||||
}
|
||||
out:
|
||||
|
||||
bch2_trans_iter_put(trans, iter);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (start != min) {
|
||||
/* Retry from start */
|
||||
start = min;
|
||||
bch2_btree_iter_set_pos(iter, POS(start, 0));
|
||||
goto again;
|
||||
}
|
||||
|
||||
return -ENOSPC;
|
||||
found_slot:
|
||||
*hint = k.k->p.inode;
|
||||
inode_u->bi_inum = k.k->p.inode;
|
||||
inode_u->bi_generation = bkey_generation(k);
|
||||
|
||||
bch2_inode_pack(inode_p, inode_u);
|
||||
bch2_trans_update(trans, iter, &inode_p->inode.k_i, 0);
|
||||
bch2_trans_iter_put(trans, iter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bch2_inode_rm(struct bch_fs *c, u64 inode_nr)
|
||||
@ -518,14 +507,13 @@ int bch2_inode_find_by_inum_trans(struct btree_trans *trans, u64 inode_nr,
|
||||
k = bch2_btree_iter_peek_slot(iter);
|
||||
ret = bkey_err(k);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
ret = k.k->type == KEY_TYPE_inode
|
||||
? bch2_inode_unpack(bkey_s_c_to_inode(k), inode)
|
||||
: -ENOENT;
|
||||
|
||||
err:
|
||||
bch2_trans_iter_put(trans, iter);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -942,7 +942,7 @@ static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp,
|
||||
|
||||
if (bch2_csum_type_is_encryption(op->csum_type)) {
|
||||
if (bversion_zero(version)) {
|
||||
version.lo = atomic64_inc_return(&c->key_version) + 1;
|
||||
version.lo = atomic64_inc_return(&c->key_version);
|
||||
} else {
|
||||
crc.nonce = op->nonce;
|
||||
op->nonce += src_len >> 9;
|
||||
|
@ -78,6 +78,7 @@ static inline void bch2_write_op_init(struct bch_write_op *op, struct bch_fs *c,
|
||||
op->nr_replicas = 0;
|
||||
op->nr_replicas_required = c->opts.data_replicas_required;
|
||||
op->alloc_reserve = RESERVE_NONE;
|
||||
op->incompressible = 0;
|
||||
op->open_buckets.nr = 0;
|
||||
op->devs_have.nr = 0;
|
||||
op->target = 0;
|
||||
|
@ -104,7 +104,7 @@ struct bch_write_op {
|
||||
unsigned compression_type:4;
|
||||
unsigned nr_replicas:4;
|
||||
unsigned nr_replicas_required:4;
|
||||
unsigned alloc_reserve:4;
|
||||
unsigned alloc_reserve:3;
|
||||
unsigned incompressible:1;
|
||||
|
||||
struct bch_devs_list devs_have;
|
||||
|
@ -171,8 +171,10 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (JSET_BIG_ENDIAN(jset) != CPU_BIG_ENDIAN)
|
||||
bch2_bkey_swab(NULL, bkey_to_packed(k));
|
||||
if (JSET_BIG_ENDIAN(jset) != CPU_BIG_ENDIAN) {
|
||||
bch2_bkey_swab_key(NULL, bkey_to_packed(k));
|
||||
bch2_bkey_swab_val(bkey_i_to_s(k));
|
||||
}
|
||||
|
||||
if (!write &&
|
||||
version < bcachefs_metadata_version_bkey_renumber)
|
||||
|
@ -123,23 +123,21 @@ static int bch2_dev_metadata_drop(struct bch_fs *c, unsigned dev_idx, int flags)
|
||||
for_each_btree_node(&trans, iter, id, POS_MIN,
|
||||
BTREE_ITER_PREFETCH, b) {
|
||||
__BKEY_PADDED(k, BKEY_BTREE_PTR_VAL_U64s_MAX) tmp;
|
||||
struct bkey_i_btree_ptr *new_key;
|
||||
retry:
|
||||
if (!bch2_bkey_has_device(bkey_i_to_s_c(&b->key),
|
||||
dev_idx))
|
||||
continue;
|
||||
|
||||
bkey_copy(&tmp.k, &b->key);
|
||||
new_key = bkey_i_to_btree_ptr(&tmp.k);
|
||||
|
||||
ret = drop_dev_ptrs(c, bkey_i_to_s(&new_key->k_i),
|
||||
ret = drop_dev_ptrs(c, bkey_i_to_s(&tmp.k),
|
||||
dev_idx, flags, true);
|
||||
if (ret) {
|
||||
bch_err(c, "Cannot drop device without losing data");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = bch2_btree_node_update_key(c, iter, b, new_key);
|
||||
ret = bch2_btree_node_update_key(c, iter, b, &tmp.k);
|
||||
if (ret == -EINTR) {
|
||||
b = bch2_btree_iter_peek_node(iter);
|
||||
goto retry;
|
||||
|
@ -27,26 +27,15 @@
|
||||
|
||||
/* iterate over keys read from the journal: */
|
||||
|
||||
struct journal_iter bch2_journal_iter_init(struct journal_keys *keys,
|
||||
enum btree_id id)
|
||||
{
|
||||
return (struct journal_iter) {
|
||||
.keys = keys,
|
||||
.k = keys->d,
|
||||
.btree_id = id,
|
||||
};
|
||||
}
|
||||
|
||||
struct bkey_s_c bch2_journal_iter_peek(struct journal_iter *iter)
|
||||
{
|
||||
while (1) {
|
||||
if (iter->k == iter->keys->d + iter->keys->nr)
|
||||
return bkey_s_c_null;
|
||||
|
||||
while (iter->k) {
|
||||
if (iter->k->btree_id == iter->btree_id)
|
||||
return bkey_i_to_s_c(iter->k->k);
|
||||
|
||||
iter->k++;
|
||||
if (iter->k == iter->keys->d + iter->keys->nr)
|
||||
iter->k = NULL;
|
||||
}
|
||||
|
||||
return bkey_s_c_null;
|
||||
@ -54,13 +43,110 @@ struct bkey_s_c bch2_journal_iter_peek(struct journal_iter *iter)
|
||||
|
||||
struct bkey_s_c bch2_journal_iter_next(struct journal_iter *iter)
|
||||
{
|
||||
if (iter->k == iter->keys->d + iter->keys->nr)
|
||||
if (!iter->k)
|
||||
return bkey_s_c_null;
|
||||
|
||||
iter->k++;
|
||||
if (iter->k == iter->keys->d + iter->keys->nr)
|
||||
iter->k = NULL;
|
||||
|
||||
return bch2_journal_iter_peek(iter);
|
||||
}
|
||||
|
||||
void bch2_btree_and_journal_iter_advance(struct btree_and_journal_iter *iter)
|
||||
{
|
||||
switch (iter->last) {
|
||||
case none:
|
||||
break;
|
||||
case btree:
|
||||
bch2_btree_iter_next(iter->btree);
|
||||
break;
|
||||
case journal:
|
||||
bch2_journal_iter_next(&iter->journal);
|
||||
break;
|
||||
}
|
||||
|
||||
iter->last = none;
|
||||
}
|
||||
|
||||
struct bkey_s_c bch2_btree_and_journal_iter_peek(struct btree_and_journal_iter *iter)
|
||||
{
|
||||
struct bkey_s_c ret;
|
||||
|
||||
while (1) {
|
||||
struct bkey_s_c btree_k = bch2_btree_iter_peek(iter->btree);
|
||||
struct bkey_s_c journal_k = bch2_journal_iter_peek(&iter->journal);
|
||||
|
||||
if (btree_k.k && journal_k.k) {
|
||||
int cmp = bkey_cmp(btree_k.k->p, journal_k.k->p);
|
||||
|
||||
if (!cmp)
|
||||
bch2_btree_iter_next(iter->btree);
|
||||
|
||||
iter->last = cmp < 0 ? btree : journal;
|
||||
} else if (btree_k.k) {
|
||||
iter->last = btree;
|
||||
} else if (journal_k.k) {
|
||||
iter->last = journal;
|
||||
} else {
|
||||
iter->last = none;
|
||||
return bkey_s_c_null;
|
||||
}
|
||||
|
||||
ret = iter->last == journal ? journal_k : btree_k;
|
||||
if (!bkey_deleted(ret.k))
|
||||
break;
|
||||
|
||||
bch2_btree_and_journal_iter_advance(iter);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct bkey_s_c bch2_btree_and_journal_iter_next(struct btree_and_journal_iter *iter)
|
||||
{
|
||||
bch2_btree_and_journal_iter_advance(iter);
|
||||
|
||||
return bch2_btree_and_journal_iter_peek(iter);
|
||||
}
|
||||
|
||||
struct journal_key *journal_key_search(struct journal_keys *journal_keys,
|
||||
enum btree_id id, struct bpos pos)
|
||||
{
|
||||
size_t l = 0, r = journal_keys->nr, m;
|
||||
|
||||
while (l < r) {
|
||||
m = l + ((r - l) >> 1);
|
||||
if ((cmp_int(id, journal_keys->d[m].btree_id) ?:
|
||||
bkey_cmp(pos, journal_keys->d[m].k->k.p)) > 0)
|
||||
l = m + 1;
|
||||
else
|
||||
r = m;
|
||||
}
|
||||
|
||||
BUG_ON(l < journal_keys->nr &&
|
||||
(cmp_int(id, journal_keys->d[l].btree_id) ?:
|
||||
bkey_cmp(pos, journal_keys->d[l].k->k.p)) > 0);
|
||||
|
||||
BUG_ON(l &&
|
||||
(cmp_int(id, journal_keys->d[l - 1].btree_id) ?:
|
||||
bkey_cmp(pos, journal_keys->d[l - 1].k->k.p)) <= 0);
|
||||
|
||||
return l < journal_keys->nr ? journal_keys->d + l : NULL;
|
||||
}
|
||||
|
||||
void bch2_btree_and_journal_iter_init(struct btree_and_journal_iter *iter,
|
||||
struct btree_trans *trans,
|
||||
struct journal_keys *journal_keys,
|
||||
enum btree_id id, struct bpos pos)
|
||||
{
|
||||
iter->journal.keys = journal_keys;
|
||||
iter->journal.k = journal_key_search(journal_keys, id, pos);
|
||||
iter->journal.btree_id = id;
|
||||
|
||||
iter->btree = bch2_trans_get_iter(trans, id, pos, 0);
|
||||
}
|
||||
|
||||
/* sort and dedup all keys in the journal: */
|
||||
|
||||
static void journal_entries_free(struct list_head *list)
|
||||
@ -924,6 +1010,7 @@ int bch2_fs_recovery(struct bch_fs *c)
|
||||
c->disk_sb.sb->version = le16_to_cpu(bcachefs_metadata_version_current);
|
||||
c->disk_sb.sb->features[0] |= 1ULL << BCH_FEATURE_new_siphash;
|
||||
c->disk_sb.sb->features[0] |= 1ULL << BCH_FEATURE_new_extent_overwrite;
|
||||
c->disk_sb.sb->features[0] |= 1ULL << BCH_FEATURE_btree_ptr_v2;
|
||||
write_sb = true;
|
||||
}
|
||||
|
||||
|
@ -24,10 +24,28 @@ struct journal_iter {
|
||||
enum btree_id btree_id;
|
||||
};
|
||||
|
||||
struct journal_iter bch2_journal_iter_init(struct journal_keys *,
|
||||
enum btree_id);
|
||||
struct bkey_s_c bch2_journal_iter_peek(struct journal_iter *);
|
||||
struct bkey_s_c bch2_journal_iter_next(struct journal_iter *);
|
||||
struct btree_and_journal_iter {
|
||||
enum btree_id btree_id;
|
||||
|
||||
struct btree_iter *btree;
|
||||
struct journal_iter journal;
|
||||
|
||||
enum last_key_returned {
|
||||
none,
|
||||
btree,
|
||||
journal,
|
||||
} last;
|
||||
};
|
||||
|
||||
void bch2_btree_and_journal_iter_advance(struct btree_and_journal_iter *);
|
||||
struct bkey_s_c bch2_btree_and_journal_iter_peek(struct btree_and_journal_iter *);
|
||||
struct bkey_s_c bch2_btree_and_journal_iter_next(struct btree_and_journal_iter *);
|
||||
struct journal_key *journal_key_search(struct journal_keys *,
|
||||
enum btree_id, struct bpos);
|
||||
void bch2_btree_and_journal_iter_init(struct btree_and_journal_iter *,
|
||||
struct btree_trans *,
|
||||
struct journal_keys *,
|
||||
enum btree_id, struct bpos);
|
||||
|
||||
int bch2_fs_recovery(struct bch_fs *);
|
||||
int bch2_fs_initialize(struct bch_fs *);
|
||||
|
@ -128,10 +128,9 @@ static int bch2_make_extent_indirect(struct btree_trans *trans,
|
||||
|
||||
bch2_trans_update(trans, extent_iter, &r_p->k_i, 0);
|
||||
err:
|
||||
if (!IS_ERR(reflink_iter)) {
|
||||
if (!IS_ERR(reflink_iter))
|
||||
c->reflink_hint = reflink_iter->pos.offset;
|
||||
bch2_trans_iter_put(trans, reflink_iter);
|
||||
}
|
||||
bch2_trans_iter_put(trans, reflink_iter);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ void bch2_reflink_v_to_text(struct printbuf *, struct bch_fs *,
|
||||
#define bch2_bkey_ops_reflink_v (struct bkey_ops) { \
|
||||
.key_invalid = bch2_reflink_v_invalid, \
|
||||
.val_to_text = bch2_reflink_v_to_text, \
|
||||
.swab = bch2_ptr_swab, \
|
||||
}
|
||||
|
||||
s64 bch2_remap_range(struct bch_fs *, struct bpos, struct bpos,
|
||||
|
@ -112,6 +112,7 @@ void bch2_bkey_to_replicas(struct bch_replicas_entry *e,
|
||||
|
||||
switch (k.k->type) {
|
||||
case KEY_TYPE_btree_ptr:
|
||||
case KEY_TYPE_btree_ptr_v2:
|
||||
e->data_type = BCH_DATA_BTREE;
|
||||
extent_to_replicas(k, e);
|
||||
break;
|
||||
|
@ -262,10 +262,8 @@ int bch2_hash_set(struct btree_trans *trans,
|
||||
if (!ret)
|
||||
ret = -ENOSPC;
|
||||
out:
|
||||
if (!IS_ERR_OR_NULL(slot))
|
||||
bch2_trans_iter_put(trans, slot);
|
||||
if (!IS_ERR_OR_NULL(iter))
|
||||
bch2_trans_iter_put(trans, iter);
|
||||
bch2_trans_iter_put(trans, slot);
|
||||
bch2_trans_iter_put(trans, iter);
|
||||
|
||||
return ret;
|
||||
found:
|
||||
@ -319,13 +317,16 @@ int bch2_hash_delete(struct btree_trans *trans,
|
||||
u64 inode, const void *key)
|
||||
{
|
||||
struct btree_iter *iter;
|
||||
int ret;
|
||||
|
||||
iter = bch2_hash_lookup(trans, desc, info, inode, key,
|
||||
BTREE_ITER_INTENT);
|
||||
if (IS_ERR(iter))
|
||||
return PTR_ERR(iter);
|
||||
|
||||
return bch2_hash_delete_at(trans, desc, info, iter);
|
||||
ret = bch2_hash_delete_at(trans, desc, info, iter);
|
||||
bch2_trans_iter_put(trans, iter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* _BCACHEFS_STR_HASH_H */
|
||||
|
Loading…
Reference in New Issue
Block a user