Commit 9432e90d authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: Check for invalid bucket from bucket_gen(), gc_bucket()

Turn more asserts into proper recoverable error paths.

Reported-by: syzbot+246b47da27f8e7e7d6fb@syzkaller.appspotmail.com
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 9c4acd19
...@@ -741,6 +741,7 @@ int bch2_trigger_alloc(struct btree_trans *trans, ...@@ -741,6 +741,7 @@ int bch2_trigger_alloc(struct btree_trans *trans,
enum btree_iter_update_trigger_flags flags) enum btree_iter_update_trigger_flags flags)
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
struct printbuf buf = PRINTBUF;
int ret = 0; int ret = 0;
struct bch_dev *ca = bch2_dev_bucket_tryget(c, new.k->p); struct bch_dev *ca = bch2_dev_bucket_tryget(c, new.k->p);
...@@ -860,8 +861,14 @@ int bch2_trigger_alloc(struct btree_trans *trans, ...@@ -860,8 +861,14 @@ int bch2_trigger_alloc(struct btree_trans *trans,
} }
percpu_down_read(&c->mark_lock); percpu_down_read(&c->mark_lock);
if (new_a->gen != old_a->gen) if (new_a->gen != old_a->gen) {
*bucket_gen(ca, new.k->p.offset) = new_a->gen; u8 *gen = bucket_gen(ca, new.k->p.offset);
if (unlikely(!gen)) {
percpu_up_read(&c->mark_lock);
goto invalid_bucket;
}
*gen = new_a->gen;
}
bch2_dev_usage_update(c, ca, old_a, new_a, journal_seq, false); bch2_dev_usage_update(c, ca, old_a, new_a, journal_seq, false);
percpu_up_read(&c->mark_lock); percpu_up_read(&c->mark_lock);
...@@ -895,6 +902,11 @@ int bch2_trigger_alloc(struct btree_trans *trans, ...@@ -895,6 +902,11 @@ int bch2_trigger_alloc(struct btree_trans *trans,
percpu_down_read(&c->mark_lock); percpu_down_read(&c->mark_lock);
struct bucket *g = gc_bucket(ca, new.k->p.offset); struct bucket *g = gc_bucket(ca, new.k->p.offset);
if (unlikely(!g)) {
percpu_up_read(&c->mark_lock);
goto invalid_bucket;
}
g->gen_valid = 1;
bucket_lock(g); bucket_lock(g);
...@@ -910,8 +922,14 @@ int bch2_trigger_alloc(struct btree_trans *trans, ...@@ -910,8 +922,14 @@ int bch2_trigger_alloc(struct btree_trans *trans,
percpu_up_read(&c->mark_lock); percpu_up_read(&c->mark_lock);
} }
err: err:
printbuf_exit(&buf);
bch2_dev_put(ca); bch2_dev_put(ca);
return ret; return ret;
invalid_bucket:
bch2_fs_inconsistent(c, "reference to invalid bucket\n %s",
(bch2_bkey_val_to_text(&buf, c, new.s_c), buf.buf));
ret = -EIO;
goto err;
} }
/* /*
......
...@@ -874,6 +874,9 @@ static int bch2_alloc_write_key(struct btree_trans *trans, ...@@ -874,6 +874,9 @@ static int bch2_alloc_write_key(struct btree_trans *trans,
const struct bch_alloc_v4 *old; const struct bch_alloc_v4 *old;
int ret; int ret;
if (!bucket_valid(ca, k.k->p.offset))
return 0;
old = bch2_alloc_to_v4(k, &old_convert); old = bch2_alloc_to_v4(k, &old_convert);
gc = new = *old; gc = new = *old;
...@@ -1005,12 +1008,14 @@ static int bch2_gc_alloc_start(struct bch_fs *c) ...@@ -1005,12 +1008,14 @@ static int bch2_gc_alloc_start(struct bch_fs *c)
continue; continue;
} }
struct bch_alloc_v4 a_convert; if (bucket_valid(ca, k.k->p.offset)) {
const struct bch_alloc_v4 *a = bch2_alloc_to_v4(k, &a_convert); struct bch_alloc_v4 a_convert;
const struct bch_alloc_v4 *a = bch2_alloc_to_v4(k, &a_convert);
struct bucket *g = gc_bucket(ca, k.k->p.offset); struct bucket *g = gc_bucket(ca, k.k->p.offset);
g->gen_valid = 1; g->gen_valid = 1;
g->gen = a->gen; g->gen = a->gen;
}
0; 0;
}))); })));
bch2_dev_put(ca); bch2_dev_put(ca);
......
...@@ -488,6 +488,17 @@ static int bch2_check_fix_ptr(struct btree_trans *trans, ...@@ -488,6 +488,17 @@ static int bch2_check_fix_ptr(struct btree_trans *trans,
} }
struct bucket *g = PTR_GC_BUCKET(ca, &p.ptr); struct bucket *g = PTR_GC_BUCKET(ca, &p.ptr);
if (!g) {
if (fsck_err(c, ptr_to_invalid_device,
"pointer to invalid bucket on device %u\n"
"while marking %s",
p.ptr.dev,
(printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
*do_update = true;
goto out;
}
enum bch_data_type data_type = bch2_bkey_ptr_data_type(k, p, entry); enum bch_data_type data_type = bch2_bkey_ptr_data_type(k, p, entry);
if (fsck_err_on(!g->gen_valid, if (fsck_err_on(!g->gen_valid,
...@@ -577,8 +588,8 @@ static int bch2_check_fix_ptr(struct btree_trans *trans, ...@@ -577,8 +588,8 @@ static int bch2_check_fix_ptr(struct btree_trans *trans,
if (p.has_ec) { if (p.has_ec) {
struct gc_stripe *m = genradix_ptr(&c->gc_stripes, p.ec.idx); struct gc_stripe *m = genradix_ptr(&c->gc_stripes, p.ec.idx);
if (fsck_err_on(!m || !m->alive, c, if (fsck_err_on(!m || !m->alive,
ptr_to_missing_stripe, c, ptr_to_missing_stripe,
"pointer to nonexistent stripe %llu\n" "pointer to nonexistent stripe %llu\n"
"while marking %s", "while marking %s",
(u64) p.ec.idx, (u64) p.ec.idx,
...@@ -586,8 +597,8 @@ static int bch2_check_fix_ptr(struct btree_trans *trans, ...@@ -586,8 +597,8 @@ static int bch2_check_fix_ptr(struct btree_trans *trans,
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
*do_update = true; *do_update = true;
if (fsck_err_on(m && m->alive && !bch2_ptr_matches_stripe_m(m, p), c, if (fsck_err_on(m && m->alive && !bch2_ptr_matches_stripe_m(m, p),
ptr_to_incorrect_stripe, c, ptr_to_incorrect_stripe,
"pointer does not match stripe %llu\n" "pointer does not match stripe %llu\n"
"while marking %s", "while marking %s",
(u64) p.ec.idx, (u64) p.ec.idx,
...@@ -1004,6 +1015,7 @@ static int bch2_trigger_pointer(struct btree_trans *trans, ...@@ -1004,6 +1015,7 @@ static int bch2_trigger_pointer(struct btree_trans *trans,
enum btree_iter_update_trigger_flags flags) enum btree_iter_update_trigger_flags flags)
{ {
bool insert = !(flags & BTREE_TRIGGER_overwrite); bool insert = !(flags & BTREE_TRIGGER_overwrite);
struct printbuf buf = PRINTBUF;
int ret = 0; int ret = 0;
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
...@@ -1036,6 +1048,13 @@ static int bch2_trigger_pointer(struct btree_trans *trans, ...@@ -1036,6 +1048,13 @@ static int bch2_trigger_pointer(struct btree_trans *trans,
if (flags & BTREE_TRIGGER_gc) { if (flags & BTREE_TRIGGER_gc) {
percpu_down_read(&c->mark_lock); percpu_down_read(&c->mark_lock);
struct bucket *g = gc_bucket(ca, bucket.offset); struct bucket *g = gc_bucket(ca, bucket.offset);
if (bch2_fs_inconsistent_on(!g, c, "reference to invalid bucket on device %u\n %s",
p.ptr.dev,
(bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
ret = -EIO;
goto err_unlock;
}
bucket_lock(g); bucket_lock(g);
struct bch_alloc_v4 old = bucket_m_to_alloc(*g), new = old; struct bch_alloc_v4 old = bucket_m_to_alloc(*g), new = old;
ret = __mark_pointer(trans, ca, k, &p.ptr, *sectors, bp.data_type, &new); ret = __mark_pointer(trans, ca, k, &p.ptr, *sectors, bp.data_type, &new);
...@@ -1044,10 +1063,12 @@ static int bch2_trigger_pointer(struct btree_trans *trans, ...@@ -1044,10 +1063,12 @@ static int bch2_trigger_pointer(struct btree_trans *trans,
bch2_dev_usage_update(c, ca, &old, &new, 0, true); bch2_dev_usage_update(c, ca, &old, &new, 0, true);
} }
bucket_unlock(g); bucket_unlock(g);
err_unlock:
percpu_up_read(&c->mark_lock); percpu_up_read(&c->mark_lock);
} }
err: err:
bch2_dev_put(ca); bch2_dev_put(ca);
printbuf_exit(&buf);
return ret; return ret;
} }
...@@ -1335,10 +1356,11 @@ static int bch2_mark_metadata_bucket(struct bch_fs *c, struct bch_dev *ca, ...@@ -1335,10 +1356,11 @@ static int bch2_mark_metadata_bucket(struct bch_fs *c, struct bch_dev *ca,
u64 b, enum bch_data_type data_type, unsigned sectors, u64 b, enum bch_data_type data_type, unsigned sectors,
enum btree_iter_update_trigger_flags flags) enum btree_iter_update_trigger_flags flags)
{ {
int ret = 0;
percpu_down_read(&c->mark_lock); percpu_down_read(&c->mark_lock);
struct bucket *g = gc_bucket(ca, b); struct bucket *g = gc_bucket(ca, b);
if (bch2_fs_inconsistent_on(!g, c, "reference to invalid bucket on device %u when marking metadata type %s",
ca->dev_idx, bch2_data_type_str(data_type)))
goto err_unlock;
bucket_lock(g); bucket_lock(g);
struct bch_alloc_v4 old = bucket_m_to_alloc(*g); struct bch_alloc_v4 old = bucket_m_to_alloc(*g);
...@@ -1347,29 +1369,27 @@ static int bch2_mark_metadata_bucket(struct bch_fs *c, struct bch_dev *ca, ...@@ -1347,29 +1369,27 @@ static int bch2_mark_metadata_bucket(struct bch_fs *c, struct bch_dev *ca,
g->data_type != data_type, c, g->data_type != data_type, c,
"different types of data in same bucket: %s, %s", "different types of data in same bucket: %s, %s",
bch2_data_type_str(g->data_type), bch2_data_type_str(g->data_type),
bch2_data_type_str(data_type))) { bch2_data_type_str(data_type)))
ret = -EIO;
goto err; goto err;
}
if (bch2_fs_inconsistent_on((u64) g->dirty_sectors + sectors > ca->mi.bucket_size, c, if (bch2_fs_inconsistent_on((u64) g->dirty_sectors + sectors > ca->mi.bucket_size, c,
"bucket %u:%llu gen %u data type %s sector count overflow: %u + %u > bucket size", "bucket %u:%llu gen %u data type %s sector count overflow: %u + %u > bucket size",
ca->dev_idx, b, g->gen, ca->dev_idx, b, g->gen,
bch2_data_type_str(g->data_type ?: data_type), bch2_data_type_str(g->data_type ?: data_type),
g->dirty_sectors, sectors)) { g->dirty_sectors, sectors))
ret = -EIO;
goto err; goto err;
}
g->data_type = data_type; g->data_type = data_type;
g->dirty_sectors += sectors; g->dirty_sectors += sectors;
struct bch_alloc_v4 new = bucket_m_to_alloc(*g); struct bch_alloc_v4 new = bucket_m_to_alloc(*g);
bch2_dev_usage_update(c, ca, &old, &new, 0, true);
percpu_up_read(&c->mark_lock);
return 0;
err: err:
bucket_unlock(g); bucket_unlock(g);
if (!ret) err_unlock:
bch2_dev_usage_update(c, ca, &old, &new, 0, true);
percpu_up_read(&c->mark_lock); percpu_up_read(&c->mark_lock);
return ret; return -EIO;
} }
int bch2_trans_mark_metadata_bucket(struct btree_trans *trans, int bch2_trans_mark_metadata_bucket(struct btree_trans *trans,
......
...@@ -172,19 +172,22 @@ static inline int gen_after(u8 a, u8 b) ...@@ -172,19 +172,22 @@ static inline int gen_after(u8 a, u8 b)
return r > 0 ? r : 0; return r > 0 ? r : 0;
} }
static inline u8 dev_ptr_stale_rcu(struct bch_dev *ca, const struct bch_extent_ptr *ptr) static inline int dev_ptr_stale_rcu(struct bch_dev *ca, const struct bch_extent_ptr *ptr)
{ {
return gen_after(*bucket_gen(ca, PTR_BUCKET_NR(ca, ptr)), ptr->gen); u8 *gen = bucket_gen(ca, PTR_BUCKET_NR(ca, ptr));
if (!gen)
return -1;
return gen_after(*gen, ptr->gen);
} }
/** /**
* dev_ptr_stale() - check if a pointer points into a bucket that has been * dev_ptr_stale() - check if a pointer points into a bucket that has been
* invalidated. * invalidated.
*/ */
static inline u8 dev_ptr_stale(struct bch_dev *ca, const struct bch_extent_ptr *ptr) static inline int dev_ptr_stale(struct bch_dev *ca, const struct bch_extent_ptr *ptr)
{ {
rcu_read_lock(); rcu_read_lock();
u8 ret = dev_ptr_stale_rcu(ca, ptr); int ret = dev_ptr_stale_rcu(ca, ptr);
rcu_read_unlock(); rcu_read_unlock();
return ret; return ret;
......
...@@ -268,6 +268,7 @@ static int mark_stripe_bucket(struct btree_trans *trans, ...@@ -268,6 +268,7 @@ static int mark_stripe_bucket(struct btree_trans *trans,
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
const struct bch_extent_ptr *ptr = s.v->ptrs + ptr_idx; const struct bch_extent_ptr *ptr = s.v->ptrs + ptr_idx;
struct printbuf buf = PRINTBUF;
int ret = 0; int ret = 0;
struct bch_dev *ca = bch2_dev_tryget(c, ptr->dev); struct bch_dev *ca = bch2_dev_tryget(c, ptr->dev);
...@@ -289,6 +290,13 @@ static int mark_stripe_bucket(struct btree_trans *trans, ...@@ -289,6 +290,13 @@ static int mark_stripe_bucket(struct btree_trans *trans,
if (flags & BTREE_TRIGGER_gc) { if (flags & BTREE_TRIGGER_gc) {
percpu_down_read(&c->mark_lock); percpu_down_read(&c->mark_lock);
struct bucket *g = gc_bucket(ca, bucket.offset); struct bucket *g = gc_bucket(ca, bucket.offset);
if (bch2_fs_inconsistent_on(!g, c, "reference to invalid bucket on device %u\n %s",
ptr->dev,
(bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf))) {
ret = -EIO;
goto err_unlock;
}
bucket_lock(g); bucket_lock(g);
struct bch_alloc_v4 old = bucket_m_to_alloc(*g), new = old; struct bch_alloc_v4 old = bucket_m_to_alloc(*g), new = old;
ret = __mark_stripe_bucket(trans, ca, s, ptr_idx, deleting, bucket, &new, flags); ret = __mark_stripe_bucket(trans, ca, s, ptr_idx, deleting, bucket, &new, flags);
...@@ -297,10 +305,12 @@ static int mark_stripe_bucket(struct btree_trans *trans, ...@@ -297,10 +305,12 @@ static int mark_stripe_bucket(struct btree_trans *trans,
bch2_dev_usage_update(c, ca, &old, &new, 0, true); bch2_dev_usage_update(c, ca, &old, &new, 0, true);
} }
bucket_unlock(g); bucket_unlock(g);
err_unlock:
percpu_up_read(&c->mark_lock); percpu_up_read(&c->mark_lock);
} }
err: err:
bch2_dev_put(ca); bch2_dev_put(ca);
printbuf_exit(&buf);
return ret; return ret;
} }
...@@ -714,10 +724,12 @@ static void ec_block_endio(struct bio *bio) ...@@ -714,10 +724,12 @@ static void ec_block_endio(struct bio *bio)
bch2_blk_status_to_str(bio->bi_status))) bch2_blk_status_to_str(bio->bi_status)))
clear_bit(ec_bio->idx, ec_bio->buf->valid); clear_bit(ec_bio->idx, ec_bio->buf->valid);
if (dev_ptr_stale(ca, ptr)) { int stale = dev_ptr_stale(ca, ptr);
if (stale) {
bch_err_ratelimited(ca->fs, bch_err_ratelimited(ca->fs,
"error %s stripe: stale pointer after io", "error %s stripe: stale/invalid pointer (%i) after io",
bio_data_dir(bio) == READ ? "reading from" : "writing to"); bio_data_dir(bio) == READ ? "reading from" : "writing to",
stale);
clear_bit(ec_bio->idx, ec_bio->buf->valid); clear_bit(ec_bio->idx, ec_bio->buf->valid);
} }
...@@ -743,10 +755,12 @@ static void ec_block_io(struct bch_fs *c, struct ec_stripe_buf *buf, ...@@ -743,10 +755,12 @@ static void ec_block_io(struct bch_fs *c, struct ec_stripe_buf *buf,
return; return;
} }
if (dev_ptr_stale(ca, ptr)) { int stale = dev_ptr_stale(ca, ptr);
if (stale) {
bch_err_ratelimited(c, bch_err_ratelimited(c,
"error %s stripe: stale pointer", "error %s stripe: stale pointer (%i)",
rw == READ ? "reading from" : "writing to"); rw == READ ? "reading from" : "writing to",
stale);
clear_bit(idx, buf->valid); clear_bit(idx, buf->valid);
return; return;
} }
......
...@@ -137,7 +137,7 @@ int bch2_bkey_pick_read_device(struct bch_fs *c, struct bkey_s_c k, ...@@ -137,7 +137,7 @@ int bch2_bkey_pick_read_device(struct bch_fs *c, struct bkey_s_c k,
struct bch_dev *ca = bch2_dev_rcu(c, p.ptr.dev); struct bch_dev *ca = bch2_dev_rcu(c, p.ptr.dev);
if (p.ptr.cached && (!ca || dev_ptr_stale(ca, &p.ptr))) if (p.ptr.cached && (!ca || dev_ptr_stale_rcu(ca, &p.ptr)))
continue; continue;
f = failed ? dev_io_failures(failed, p.ptr.dev) : NULL; f = failed ? dev_io_failures(failed, p.ptr.dev) : NULL;
...@@ -999,7 +999,7 @@ bool bch2_extent_normalize(struct bch_fs *c, struct bkey_s k) ...@@ -999,7 +999,7 @@ bool bch2_extent_normalize(struct bch_fs *c, struct bkey_s k)
bch2_bkey_drop_ptrs(k, ptr, bch2_bkey_drop_ptrs(k, ptr,
ptr->cached && ptr->cached &&
(ca = bch2_dev_rcu(c, ptr->dev)) && (ca = bch2_dev_rcu(c, ptr->dev)) &&
dev_ptr_stale_rcu(ca, ptr)); dev_ptr_stale_rcu(ca, ptr) > 0);
rcu_read_unlock(); rcu_read_unlock();
return bkey_deleted(k.k); return bkey_deleted(k.k);
...@@ -1024,8 +1024,11 @@ void bch2_extent_ptr_to_text(struct printbuf *out, struct bch_fs *c, const struc ...@@ -1024,8 +1024,11 @@ void bch2_extent_ptr_to_text(struct printbuf *out, struct bch_fs *c, const struc
prt_str(out, " cached"); prt_str(out, " cached");
if (ptr->unwritten) if (ptr->unwritten)
prt_str(out, " unwritten"); prt_str(out, " unwritten");
if (bucket_valid(ca, b) && dev_ptr_stale_rcu(ca, ptr)) int stale = dev_ptr_stale_rcu(ca, ptr);
if (stale > 0)
prt_printf(out, " stale"); prt_printf(out, " stale");
else if (stale)
prt_printf(out, " invalid");
} }
rcu_read_unlock(); rcu_read_unlock();
--out->atomic; --out->atomic;
......
...@@ -777,18 +777,32 @@ static noinline void read_from_stale_dirty_pointer(struct btree_trans *trans, ...@@ -777,18 +777,32 @@ static noinline void read_from_stale_dirty_pointer(struct btree_trans *trans,
PTR_BUCKET_POS(ca, &ptr), PTR_BUCKET_POS(ca, &ptr),
BTREE_ITER_cached); BTREE_ITER_cached);
prt_printf(&buf, "Attempting to read from stale dirty pointer:\n"); u8 *gen = bucket_gen(ca, iter.pos.offset);
printbuf_indent_add(&buf, 2); if (gen) {
bch2_bkey_val_to_text(&buf, c, k); prt_printf(&buf, "Attempting to read from stale dirty pointer:\n");
prt_newline(&buf); printbuf_indent_add(&buf, 2);
prt_printf(&buf, "memory gen: %u", *bucket_gen(ca, iter.pos.offset)); bch2_bkey_val_to_text(&buf, c, k);
ret = lockrestart_do(trans, bkey_err(k = bch2_btree_iter_peek_slot(&iter)));
if (!ret) {
prt_newline(&buf); prt_newline(&buf);
prt_printf(&buf, "memory gen: %u", *gen);
ret = lockrestart_do(trans, bkey_err(k = bch2_btree_iter_peek_slot(&iter)));
if (!ret) {
prt_newline(&buf);
bch2_bkey_val_to_text(&buf, c, k);
}
} else {
prt_printf(&buf, "Attempting to read from invalid bucket %llu:%llu:\n",
iter.pos.inode, iter.pos.offset);
printbuf_indent_add(&buf, 2);
prt_printf(&buf, "first bucket %u nbuckets %llu\n",
ca->mi.first_bucket, ca->mi.nbuckets);
bch2_bkey_val_to_text(&buf, c, k); bch2_bkey_val_to_text(&buf, c, k);
prt_newline(&buf);
} }
bch2_fs_inconsistent(c, "%s", buf.buf); bch2_fs_inconsistent(c, "%s", buf.buf);
......
...@@ -1220,7 +1220,7 @@ static void bch2_nocow_write(struct bch_write_op *op) ...@@ -1220,7 +1220,7 @@ static void bch2_nocow_write(struct bch_write_op *op)
DARRAY_PREALLOCATED(struct bucket_to_lock, 3) buckets; DARRAY_PREALLOCATED(struct bucket_to_lock, 3) buckets;
u32 snapshot; u32 snapshot;
struct bucket_to_lock *stale_at; struct bucket_to_lock *stale_at;
int ret; int stale, ret;
if (op->flags & BCH_WRITE_MOVE) if (op->flags & BCH_WRITE_MOVE)
return; return;
...@@ -1299,7 +1299,8 @@ static void bch2_nocow_write(struct bch_write_op *op) ...@@ -1299,7 +1299,8 @@ static void bch2_nocow_write(struct bch_write_op *op)
BUCKET_NOCOW_LOCK_UPDATE); BUCKET_NOCOW_LOCK_UPDATE);
rcu_read_lock(); rcu_read_lock();
bool stale = gen_after(*bucket_gen(ca, i->b.offset), i->gen); u8 *gen = bucket_gen(ca, i->b.offset);
stale = !gen ? -1 : gen_after(*gen, i->gen);
rcu_read_unlock(); rcu_read_unlock();
if (unlikely(stale)) { if (unlikely(stale)) {
...@@ -1380,8 +1381,18 @@ static void bch2_nocow_write(struct bch_write_op *op) ...@@ -1380,8 +1381,18 @@ static void bch2_nocow_write(struct bch_write_op *op)
break; break;
} }
/* We can retry this: */ struct printbuf buf = PRINTBUF;
ret = -BCH_ERR_transaction_restart; if (bch2_fs_inconsistent_on(stale < 0, c,
"pointer to invalid bucket in nocow path on device %llu\n %s",
stale_at->b.inode,
(bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
ret = -EIO;
} else {
/* We can retry this: */
ret = -BCH_ERR_transaction_restart;
}
printbuf_exit(&buf);
goto err_get_ioref; goto err_get_ioref;
} }
......
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