Skip to content

Commit a34eef6

Browse files
author
Kent Overstreet
committed
bcachefs: Don't keep tons of cached pointers around
We had a bug report where the data update path was creating an extent that failed to validate because it had too many pointers; almost all of them were cached. To fix this, we have: - want_cached_ptr(), a new helper that checks if we even want a cached pointer (is on appropriate target, device is readable). - bch2_extent_set_ptr_cached() now only sets a pointer cached if we want it. - bch2_extent_normalize_by_opts() now ensures that we only have a single cached pointer that we want. While working on this, it was noticed that this doesn't work well with reflinked data and per-file options. Another patch series is coming that plumbs through additional io path options through bch_extent_rebalance, with improved option handling. Reported-by: Reed Riley <[email protected]> Signed-off-by: Kent Overstreet <[email protected]>
1 parent 3fd27e9 commit a34eef6

File tree

5 files changed

+89
-28
lines changed

5 files changed

+89
-28
lines changed

fs/bcachefs/data_update.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,8 @@ static int __bch2_data_update_index_update(struct btree_trans *trans,
236236
if (((1U << i) & m->data_opts.rewrite_ptrs) &&
237237
(ptr = bch2_extent_has_ptr(old, p, bkey_i_to_s(insert))) &&
238238
!ptr->cached) {
239-
bch2_extent_ptr_set_cached(bkey_i_to_s(insert), ptr);
239+
bch2_extent_ptr_set_cached(c, &m->op.opts,
240+
bkey_i_to_s(insert), ptr);
240241
rewrites_found |= 1U << i;
241242
}
242243
i++;
@@ -284,7 +285,8 @@ static int __bch2_data_update_index_update(struct btree_trans *trans,
284285
durability - ptr_durability >= m->op.opts.data_replicas) {
285286
durability -= ptr_durability;
286287

287-
bch2_extent_ptr_set_cached(bkey_i_to_s(insert), &entry->ptr);
288+
bch2_extent_ptr_set_cached(c, &m->op.opts,
289+
bkey_i_to_s(insert), &entry->ptr);
288290
goto restart_drop_extra_replicas;
289291
}
290292
}
@@ -295,7 +297,7 @@ static int __bch2_data_update_index_update(struct btree_trans *trans,
295297
bch2_extent_ptr_decoded_append(insert, &p);
296298

297299
bch2_bkey_narrow_crcs(insert, (struct bch_extent_crc_unpacked) { 0 });
298-
bch2_extent_normalize(c, bkey_i_to_s(insert));
300+
bch2_extent_normalize_by_opts(c, &m->op.opts, bkey_i_to_s(insert));
299301

300302
ret = bch2_sum_sector_overwrites(trans, &iter, insert,
301303
&should_check_enospc,
@@ -558,7 +560,8 @@ void bch2_data_update_to_text(struct printbuf *out, struct data_update *m)
558560
int bch2_extent_drop_ptrs(struct btree_trans *trans,
559561
struct btree_iter *iter,
560562
struct bkey_s_c k,
561-
struct data_update_opts data_opts)
563+
struct bch_io_opts *io_opts,
564+
struct data_update_opts *data_opts)
562565
{
563566
struct bch_fs *c = trans->c;
564567
struct bkey_i *n;
@@ -569,19 +572,19 @@ int bch2_extent_drop_ptrs(struct btree_trans *trans,
569572
if (ret)
570573
return ret;
571574

572-
while (data_opts.kill_ptrs) {
573-
unsigned i = 0, drop = __fls(data_opts.kill_ptrs);
575+
while (data_opts->kill_ptrs) {
576+
unsigned i = 0, drop = __fls(data_opts->kill_ptrs);
574577

575578
bch2_bkey_drop_ptrs_noerror(bkey_i_to_s(n), ptr, i++ == drop);
576-
data_opts.kill_ptrs ^= 1U << drop;
579+
data_opts->kill_ptrs ^= 1U << drop;
577580
}
578581

579582
/*
580583
* If the new extent no longer has any pointers, bch2_extent_normalize()
581584
* will do the appropriate thing with it (turning it into a
582585
* KEY_TYPE_error key, or just a discard if it was a cached extent)
583586
*/
584-
bch2_extent_normalize(c, bkey_i_to_s(n));
587+
bch2_extent_normalize_by_opts(c, io_opts, bkey_i_to_s(n));
585588

586589
/*
587590
* Since we're not inserting through an extent iterator
@@ -720,7 +723,7 @@ int bch2_data_update_init(struct btree_trans *trans,
720723
m->data_opts.rewrite_ptrs = 0;
721724
/* if iter == NULL, it's just a promote */
722725
if (iter)
723-
ret = bch2_extent_drop_ptrs(trans, iter, k, m->data_opts);
726+
ret = bch2_extent_drop_ptrs(trans, iter, k, &io_opts, &m->data_opts);
724727
goto out;
725728
}
726729

fs/bcachefs/data_update.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ void bch2_data_update_read_done(struct data_update *,
4040
int bch2_extent_drop_ptrs(struct btree_trans *,
4141
struct btree_iter *,
4242
struct bkey_s_c,
43-
struct data_update_opts);
43+
struct bch_io_opts *,
44+
struct data_update_opts *);
4445

4546
void bch2_data_update_exit(struct data_update *);
4647
int bch2_data_update_init(struct btree_trans *, struct btree_iter *,

fs/bcachefs/extents.c

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -978,31 +978,54 @@ bch2_extent_has_ptr(struct bkey_s_c k1, struct extent_ptr_decoded p1, struct bke
978978
return NULL;
979979
}
980980

981-
void bch2_extent_ptr_set_cached(struct bkey_s k, struct bch_extent_ptr *ptr)
981+
static bool want_cached_ptr(struct bch_fs *c, struct bch_io_opts *opts,
982+
struct bch_extent_ptr *ptr)
983+
{
984+
if (!opts->promote_target ||
985+
!bch2_dev_in_target(c, ptr->dev, opts->promote_target))
986+
return false;
987+
988+
struct bch_dev *ca = bch2_dev_rcu_noerror(c, ptr->dev);
989+
990+
return ca && bch2_dev_is_readable(ca) && !dev_ptr_stale_rcu(ca, ptr);
991+
}
992+
993+
void bch2_extent_ptr_set_cached(struct bch_fs *c,
994+
struct bch_io_opts *opts,
995+
struct bkey_s k,
996+
struct bch_extent_ptr *ptr)
982997
{
983998
struct bkey_ptrs ptrs = bch2_bkey_ptrs(k);
984999
union bch_extent_entry *entry;
985-
union bch_extent_entry *ec = NULL;
1000+
struct extent_ptr_decoded p;
9861001

987-
bkey_extent_entry_for_each(ptrs, entry) {
1002+
rcu_read_lock();
1003+
if (!want_cached_ptr(c, opts, ptr)) {
1004+
bch2_bkey_drop_ptr_noerror(k, ptr);
1005+
goto out;
1006+
}
1007+
1008+
/*
1009+
* Stripes can't contain cached data, for - reasons.
1010+
*
1011+
* Possibly something we can fix in the future?
1012+
*/
1013+
bkey_for_each_ptr_decode(k.k, ptrs, p, entry)
9881014
if (&entry->ptr == ptr) {
989-
ptr->cached = true;
990-
if (ec)
991-
extent_entry_drop(k, ec);
992-
return;
1015+
if (p.has_ec)
1016+
bch2_bkey_drop_ptr_noerror(k, ptr);
1017+
else
1018+
ptr->cached = true;
1019+
goto out;
9931020
}
9941021

995-
if (extent_entry_is_stripe_ptr(entry))
996-
ec = entry;
997-
else if (extent_entry_is_ptr(entry))
998-
ec = NULL;
999-
}
1000-
10011022
BUG();
1023+
out:
1024+
rcu_read_unlock();
10021025
}
10031026

10041027
/*
1005-
* bch_extent_normalize - clean up an extent, dropping stale pointers etc.
1028+
* bch2_extent_normalize - clean up an extent, dropping stale pointers etc.
10061029
*
10071030
* Returns true if @k should be dropped entirely
10081031
*
@@ -1016,8 +1039,39 @@ bool bch2_extent_normalize(struct bch_fs *c, struct bkey_s k)
10161039
rcu_read_lock();
10171040
bch2_bkey_drop_ptrs(k, ptr,
10181041
ptr->cached &&
1019-
(ca = bch2_dev_rcu(c, ptr->dev)) &&
1020-
dev_ptr_stale_rcu(ca, ptr) > 0);
1042+
(!(ca = bch2_dev_rcu(c, ptr->dev)) ||
1043+
dev_ptr_stale_rcu(ca, ptr) > 0));
1044+
rcu_read_unlock();
1045+
1046+
return bkey_deleted(k.k);
1047+
}
1048+
1049+
/*
1050+
* bch2_extent_normalize_by_opts - clean up an extent, dropping stale pointers etc.
1051+
*
1052+
* Like bch2_extent_normalize(), but also only keeps a single cached pointer on
1053+
* the promote target.
1054+
*/
1055+
bool bch2_extent_normalize_by_opts(struct bch_fs *c,
1056+
struct bch_io_opts *opts,
1057+
struct bkey_s k)
1058+
{
1059+
struct bkey_ptrs ptrs;
1060+
bool have_cached_ptr;
1061+
1062+
rcu_read_lock();
1063+
restart_drop_ptrs:
1064+
ptrs = bch2_bkey_ptrs(k);
1065+
have_cached_ptr = false;
1066+
1067+
bkey_for_each_ptr(ptrs, ptr)
1068+
if (ptr->cached) {
1069+
if (have_cached_ptr || !want_cached_ptr(c, opts, ptr)) {
1070+
bch2_bkey_drop_ptr(k, ptr);
1071+
goto restart_drop_ptrs;
1072+
}
1073+
have_cached_ptr = true;
1074+
}
10211075
rcu_read_unlock();
10221076

10231077
return bkey_deleted(k.k);

fs/bcachefs/extents.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,9 +686,12 @@ bool bch2_extents_match(struct bkey_s_c, struct bkey_s_c);
686686
struct bch_extent_ptr *
687687
bch2_extent_has_ptr(struct bkey_s_c, struct extent_ptr_decoded, struct bkey_s);
688688

689-
void bch2_extent_ptr_set_cached(struct bkey_s, struct bch_extent_ptr *);
689+
void bch2_extent_ptr_set_cached(struct bch_fs *, struct bch_io_opts *,
690+
struct bkey_s, struct bch_extent_ptr *);
690691

692+
bool bch2_extent_normalize_by_opts(struct bch_fs *, struct bch_io_opts *, struct bkey_s);
691693
bool bch2_extent_normalize(struct bch_fs *, struct bkey_s);
694+
692695
void bch2_extent_ptr_to_text(struct printbuf *out, struct bch_fs *, const struct bch_extent_ptr *);
693696
void bch2_bkey_ptrs_to_text(struct printbuf *, struct bch_fs *,
694697
struct bkey_s_c);

fs/bcachefs/move.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ int bch2_move_extent(struct moving_context *ctxt,
266266
if (!data_opts.rewrite_ptrs &&
267267
!data_opts.extra_replicas) {
268268
if (data_opts.kill_ptrs)
269-
return bch2_extent_drop_ptrs(trans, iter, k, data_opts);
269+
return bch2_extent_drop_ptrs(trans, iter, k, &io_opts, &data_opts);
270270
return 0;
271271
}
272272

0 commit comments

Comments
 (0)