#include "lru.h"
#include "recovery.h"
+/* KEY_TYPE_lru is obsolete: */
int bch2_lru_invalid(const struct bch_fs *c, struct bkey_s_c k,
- int rw, struct printbuf *err)
+ unsigned flags, struct printbuf *err)
{
const struct bch_lru *lru = bkey_s_c_to_lru(k).v;
if (bkey_val_bytes(k.k) < sizeof(*lru)) {
- pr_buf(err, "incorrect value size (%zu < %zu)",
+ prt_printf(err, "incorrect value size (%zu < %zu)",
bkey_val_bytes(k.k), sizeof(*lru));
- return -EINVAL;
+ return -BCH_ERR_invalid_bkey;
+ }
+
+ if (!lru_pos_time(k.k->p)) {
+ prt_printf(err, "lru entry at time=0");
+ return -BCH_ERR_invalid_bkey;
+
}
return 0;
{
const struct bch_lru *lru = bkey_s_c_to_lru(k).v;
- pr_buf(out, "idx %llu", le64_to_cpu(lru->idx));
+ prt_printf(out, "idx %llu", le64_to_cpu(lru->idx));
}
-int bch2_lru_delete(struct btree_trans *trans, u64 id, u64 idx, u64 time,
- struct bkey_s_c orig_k)
+void bch2_lru_pos_to_text(struct printbuf *out, struct bpos lru)
+{
+ prt_printf(out, "%llu:%llu -> %llu:%llu",
+ lru_pos_id(lru),
+ lru_pos_time(lru),
+ u64_to_bucket(lru.offset).inode,
+ u64_to_bucket(lru.offset).offset);
+}
+
+static int __bch2_lru_set(struct btree_trans *trans, u16 lru_id,
+ u64 dev_bucket, u64 time, unsigned key_type)
{
struct btree_iter iter;
- struct bkey_s_c k;
- u64 existing_idx;
- struct printbuf buf = PRINTBUF;
+ struct bkey_i *k;
int ret = 0;
if (!time)
return 0;
- bch2_trans_iter_init(trans, &iter, BTREE_ID_lru,
- POS(id, time),
- BTREE_ITER_INTENT|
- BTREE_ITER_WITH_UPDATES);
- k = bch2_btree_iter_peek_slot(&iter);
- ret = bkey_err(k);
- if (ret)
- goto err;
+ k = bch2_trans_kmalloc_nomemzero(trans, sizeof(*k));
+ ret = PTR_ERR_OR_ZERO(k);
+ if (unlikely(ret))
+ return ret;
- if (k.k->type != KEY_TYPE_lru) {
- bch2_bkey_val_to_text(&buf, trans->c, orig_k);
- bch2_trans_inconsistent(trans,
- "pointer to nonexistent lru %llu:%llu\n%s",
- id, time, buf.buf);
- ret = -EIO;
- goto err;
- }
+ bkey_init(&k->k);
+ k->k.type = key_type;
+ k->k.p = lru_pos(lru_id, dev_bucket, time);
- existing_idx = le64_to_cpu(bkey_s_c_to_lru(k).v->idx);
- if (existing_idx != idx) {
- bch2_bkey_val_to_text(&buf, trans->c, orig_k);
- bch2_trans_inconsistent(trans,
- "lru %llu:%llu with wrong backpointer: got %llu, should be %llu\n%s",
- id, time, existing_idx, idx, buf.buf);
- ret = -EIO;
- goto err;
- }
+ EBUG_ON(lru_pos_id(k->k.p) != lru_id);
+ EBUG_ON(lru_pos_time(k->k.p) != time);
+ EBUG_ON(k->k.p.offset != dev_bucket);
- ret = bch2_btree_delete_at(trans, &iter, 0);
-err:
+ bch2_trans_iter_init(trans, &iter, BTREE_ID_lru,
+ k->k.p, BTREE_ITER_INTENT);
+
+ ret = bch2_btree_iter_traverse(&iter) ?:
+ bch2_trans_update(trans, &iter, k, 0);
bch2_trans_iter_exit(trans, &iter);
- printbuf_exit(&buf);
return ret;
}
-int bch2_lru_set(struct btree_trans *trans, u64 lru_id, u64 idx, u64 *time)
+int bch2_lru_del(struct btree_trans *trans, u16 lru_id, u64 dev_bucket, u64 time)
{
- struct btree_iter iter;
- struct bkey_s_c k;
- struct bkey_i_lru *lru;
- int ret = 0;
-
- if (!*time)
- return 0;
-
- for_each_btree_key_norestart(trans, iter, BTREE_ID_lru,
- POS(lru_id, *time),
- BTREE_ITER_SLOTS|
- BTREE_ITER_INTENT|
- BTREE_ITER_WITH_UPDATES, k, ret)
- if (bkey_deleted(k.k))
- break;
-
- if (ret)
- goto err;
-
- BUG_ON(iter.pos.inode != lru_id);
- *time = iter.pos.offset;
-
- lru = bch2_trans_kmalloc(trans, sizeof(*lru));
- ret = PTR_ERR_OR_ZERO(lru);
- if (ret)
- goto err;
-
- bkey_lru_init(&lru->k_i);
- lru->k.p = iter.pos;
- lru->v.idx = cpu_to_le64(idx);
+ return __bch2_lru_set(trans, lru_id, dev_bucket, time, KEY_TYPE_deleted);
+}
- ret = bch2_trans_update(trans, &iter, &lru->k_i, 0);
- if (ret)
- goto err;
-err:
- bch2_trans_iter_exit(trans, &iter);
- return ret;
+int bch2_lru_set(struct btree_trans *trans, u16 lru_id, u64 dev_bucket, u64 time)
+{
+ return __bch2_lru_set(trans, lru_id, dev_bucket, time, KEY_TYPE_set);
}
-int bch2_lru_change(struct btree_trans *trans, u64 id, u64 idx,
- u64 old_time, u64 *new_time,
- struct bkey_s_c k)
+int bch2_lru_change(struct btree_trans *trans,
+ u16 lru_id, u64 dev_bucket,
+ u64 old_time, u64 new_time)
{
- if (old_time == *new_time)
+ if (old_time == new_time)
return 0;
- return bch2_lru_delete(trans, id, idx, old_time, k) ?:
- bch2_lru_set(trans, id, idx, new_time);
+ return bch2_lru_del(trans, lru_id, dev_bucket, old_time) ?:
+ bch2_lru_set(trans, lru_id, dev_bucket, new_time);
}
static int bch2_check_lru_key(struct btree_trans *trans,
- struct btree_iter *lru_iter, bool initial)
+ struct btree_iter *lru_iter,
+ struct bkey_s_c lru_k)
{
struct bch_fs *c = trans->c;
struct btree_iter iter;
- struct bkey_s_c lru_k, k;
- struct bch_alloc_v4 a;
+ struct bkey_s_c k;
+ struct bch_alloc_v4 a_convert;
+ const struct bch_alloc_v4 *a;
struct printbuf buf1 = PRINTBUF;
struct printbuf buf2 = PRINTBUF;
- struct bpos alloc_pos;
+ struct bpos alloc_pos = u64_to_bucket(lru_k.k->p.offset);
int ret;
- lru_k = bch2_btree_iter_peek(lru_iter);
- if (!lru_k.k)
- return 0;
-
- ret = bkey_err(lru_k);
- if (ret)
- return ret;
-
- alloc_pos = POS(lru_k.k->p.inode,
- le64_to_cpu(bkey_s_c_to_lru(lru_k).v->idx));
-
if (fsck_err_on(!bch2_dev_bucket_exists(c, alloc_pos), c,
"lru key points to nonexistent device:bucket %llu:%llu",
alloc_pos.inode, alloc_pos.offset))
if (ret)
goto err;
- bch2_alloc_to_v4(k, &a);
+ a = bch2_alloc_to_v4(k, &a_convert);
- if (fsck_err_on(a.data_type != BCH_DATA_cached ||
- a.io_time[READ] != lru_k.k->p.offset, c,
- "incorrect lru entry %s\n"
+ if (fsck_err_on(lru_k.k->type != KEY_TYPE_set ||
+ a->data_type != BCH_DATA_cached ||
+ a->io_time[READ] != lru_pos_time(lru_k.k->p), c,
+ "incorrect lru entry (time %llu) %s\n"
" for %s",
+ lru_pos_time(lru_k.k->p),
(bch2_bkey_val_to_text(&buf1, c, lru_k), buf1.buf),
(bch2_bkey_val_to_text(&buf2, c, k), buf2.buf))) {
- struct bkey_i *update =
- bch2_trans_kmalloc(trans, sizeof(*update));
-
- ret = PTR_ERR_OR_ZERO(update);
- if (ret)
- goto err;
-
- bkey_init(&update->k);
- update->k.p = lru_iter->pos;
-
- ret = bch2_trans_update(trans, lru_iter, update, 0);
+ ret = bch2_btree_delete_at(trans, lru_iter, 0);
if (ret)
goto err;
}
return ret;
}
-int bch2_check_lrus(struct bch_fs *c, bool initial)
+int bch2_check_lrus(struct bch_fs *c)
{
struct btree_trans trans;
struct btree_iter iter;
bch2_trans_init(&trans, c, 0, 0);
- for_each_btree_key(&trans, iter, BTREE_ID_lru, POS_MIN,
- BTREE_ITER_PREFETCH, k, ret) {
- ret = __bch2_trans_do(&trans, NULL, NULL, 0,
- bch2_check_lru_key(&trans, &iter, initial));
- if (ret)
- break;
- }
- bch2_trans_iter_exit(&trans, &iter);
+ ret = for_each_btree_key_commit(&trans, iter,
+ BTREE_ID_lru, POS_MIN, BTREE_ITER_PREFETCH, k,
+ NULL, NULL, BTREE_INSERT_NOFAIL|BTREE_INSERT_LAZY_RW,
+ bch2_check_lru_key(&trans, &iter, k));
bch2_trans_exit(&trans);
return ret;