static bool bch_extent_bad_expensive(struct btree *b, const struct bkey *k, unsigned ptr) { struct bucket *g = PTR_BUCKET(b->c, k, ptr); char buf[80]; if (mutex_trylock(&b->c->bucket_lock)) { if (b->c->gc_mark_valid && (!GC_MARK(g) || GC_MARK(g) == GC_MARK_METADATA || (GC_MARK(g) != GC_MARK_DIRTY && KEY_DIRTY(k)))) goto err; if (g->prio == BTREE_PRIO) goto err; mutex_unlock(&b->c->bucket_lock); } return false; err: mutex_unlock(&b->c->bucket_lock); bch_extent_to_text(buf, sizeof(buf), k); btree_bug(b, "inconsistent extent pointer %s:\nbucket %zu pin %i prio %i gen %i last_gc %i mark %llu", buf, PTR_BUCKET_NR(b->c, k, ptr), atomic_read(&g->pin), g->prio, g->gen, g->last_gc, GC_MARK(g)); return true; }
static bool btree_ptr_bad_expensive(struct btree *b, const struct bkey *k) { unsigned i; char buf[80]; struct bucket *g; if (mutex_trylock(&b->c->bucket_lock)) { for (i = 0; i < KEY_PTRS(k); i++) if (ptr_available(b->c, k, i)) { g = PTR_BUCKET(b->c, k, i); if (KEY_DIRTY(k) || g->prio != BTREE_PRIO || (b->c->gc_mark_valid && GC_MARK(g) != GC_MARK_METADATA)) goto err; } mutex_unlock(&b->c->bucket_lock); } return false; err: mutex_unlock(&b->c->bucket_lock); bch_extent_to_text(buf, sizeof(buf), k); btree_bug(b, "inconsistent btree pointer %s: bucket %zi pin %i prio %i gen %i last_gc %i mark %llu", buf, PTR_BUCKET_NR(b->c, k, i), atomic_read(&g->pin), g->prio, g->gen, g->last_gc, GC_MARK(g)); return true; }
static void dump_bset(struct btree *b, struct bset *i) { struct bkey *k; unsigned j; for (k = i->start; k < end(i); k = bkey_next(k)) { printk(KERN_ERR "block %zu key %zi/%u: %s", index(i, b), (uint64_t *) k - i->d, i->keys, pkey(k)); for (j = 0; j < KEY_PTRS(k); j++) { size_t n = PTR_BUCKET_NR(b->c, k, j); printk(" bucket %zu", n); if (n >= b->c->sb.first_bucket && n < b->c->sb.nbuckets) printk(" prio %i", PTR_BUCKET(b->c, k, j)->prio); } printk(" %s\n", bch_ptr_status(b->c, k)); if (bkey_next(k) < end(i) && skipped_backwards(b, k)) printk(KERN_ERR "Key skipped backwards\n"); } }
void bch_bucket_free(struct cache_set *c, struct bkey *k) { unsigned i; for (i = 0; i < KEY_PTRS(k); i++) __bch_bucket_free(PTR_CACHE(c, k, i), PTR_BUCKET(c, k, i)); }
void bch_bucket_free(struct cache_set *c, struct bkey *k) { unsigned i; for (i = 0; i < KEY_PTRS(k); i++) { struct bucket *b = PTR_BUCKET(c, k, i); SET_GC_MARK(b, GC_MARK_RECLAIMABLE); SET_GC_SECTORS_USED(b, 0); bch_bucket_add_unused(PTR_CACHE(c, k, i), b); } }
static void bch_bkey_dump(struct btree_keys *keys, const struct bkey *k) { struct btree *b = container_of(keys, struct btree, keys); unsigned j; char buf[80]; bch_extent_to_text(buf, sizeof(buf), k); printk(" %s", buf); for (j = 0; j < KEY_PTRS(k); j++) { size_t n = PTR_BUCKET_NR(b->c, k, j); printk(" bucket %zu", n); if (n >= b->c->sb.first_bucket && n < b->c->sb.nbuckets) printk(" prio %i", PTR_BUCKET(b->c, k, j)->prio); } printk(" %s\n", bch_ptr_status(b->c, k)); }
static bool bch_extent_bad(struct btree_keys *bk, const struct bkey *k) { struct btree *b = container_of(bk, struct btree, keys); struct bucket *g; unsigned i, stale; if (!KEY_PTRS(k) || bch_extent_invalid(bk, k)) return true; for (i = 0; i < KEY_PTRS(k); i++) if (!ptr_available(b->c, k, i)) return true; if (!expensive_debug_checks(b->c) && KEY_DIRTY(k)) return false; for (i = 0; i < KEY_PTRS(k); i++) { g = PTR_BUCKET(b->c, k, i); stale = ptr_stale(b->c, k, i); btree_bug_on(stale > 96, b, "key too stale: %i, need_gc %u", stale, b->c->need_gc); btree_bug_on(stale && KEY_DIRTY(k) && KEY_SIZE(k), b, "stale dirty pointer"); if (stale) return true; if (expensive_debug_checks(b->c) && bch_extent_bad_expensive(b, k, i)) return true; } return false; }