Commit 2e9940d4 authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: Handle cached data LRU wraparound

We only have 48 bits for the LRU time field, which is insufficient to
prevent wraparound.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent cff07e27
...@@ -2019,6 +2019,21 @@ static int invalidate_one_bucket(struct btree_trans *trans, ...@@ -2019,6 +2019,21 @@ static int invalidate_one_bucket(struct btree_trans *trans,
goto out; goto out;
} }
static struct bkey_s_c next_lru_key(struct btree_trans *trans, struct btree_iter *iter,
struct bch_dev *ca, bool *wrapped)
{
struct bkey_s_c k;
again:
k = bch2_btree_iter_peek_upto(iter, lru_pos(ca->dev_idx, U64_MAX, LRU_TIME_MAX));
if (!k.k && !*wrapped) {
bch2_btree_iter_set_pos(iter, lru_pos(ca->dev_idx, 0, 0));
*wrapped = true;
goto again;
}
return k;
}
static void bch2_do_invalidates_work(struct work_struct *work) static void bch2_do_invalidates_work(struct work_struct *work)
{ {
struct bch_fs *c = container_of(work, struct bch_fs, invalidate_work); struct bch_fs *c = container_of(work, struct bch_fs, invalidate_work);
...@@ -2032,12 +2047,33 @@ static void bch2_do_invalidates_work(struct work_struct *work) ...@@ -2032,12 +2047,33 @@ static void bch2_do_invalidates_work(struct work_struct *work)
for_each_member_device(c, ca) { for_each_member_device(c, ca) {
s64 nr_to_invalidate = s64 nr_to_invalidate =
should_invalidate_buckets(ca, bch2_dev_usage_read(ca)); should_invalidate_buckets(ca, bch2_dev_usage_read(ca));
struct btree_iter iter;
bool wrapped = false;
bch2_trans_iter_init(trans, &iter, BTREE_ID_lru,
lru_pos(ca->dev_idx, 0,
((bch2_current_io_time(c, READ) + U32_MAX) &
LRU_TIME_MAX)), 0);
ret = for_each_btree_key_upto(trans, iter, BTREE_ID_lru, while (true) {
lru_pos(ca->dev_idx, 0, 0), bch2_trans_begin(trans);
lru_pos(ca->dev_idx, U64_MAX, LRU_TIME_MAX),
BTREE_ITER_intent, k, struct bkey_s_c k = next_lru_key(trans, &iter, ca, &wrapped);
invalidate_one_bucket(trans, &iter, k, &nr_to_invalidate)); ret = bkey_err(k);
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
continue;
if (ret)
break;
if (!k.k)
break;
ret = invalidate_one_bucket(trans, &iter, k, &nr_to_invalidate);
if (ret)
break;
bch2_btree_iter_advance(&iter);
}
bch2_trans_iter_exit(trans, &iter);
if (ret < 0) { if (ret < 0) {
bch2_dev_put(ca); bch2_dev_put(ca);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment