]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/ec.c
Merge pull request #190 from Dikay900/fs_free_space
[bcachefs-tools-debian] / libbcachefs / ec.c
index 8646856e4539eae46fed2634154ebb340f841a46..bc8b556f19a90fbbd768f360b87b11e4bf7cf86b 100644 (file)
@@ -105,29 +105,26 @@ struct ec_bio {
 
 /* Stripes btree keys: */
 
-int bch2_stripe_invalid(const struct bch_fs *c, struct bkey_s_c k,
+int bch2_stripe_invalid(struct bch_fs *c, struct bkey_s_c k,
                        enum bkey_invalid_flags flags,
                        struct printbuf *err)
 {
        const struct bch_stripe *s = bkey_s_c_to_stripe(k).v;
+       int ret = 0;
 
-       if (bkey_eq(k.k->p, POS_MIN)) {
-               prt_printf(err, "stripe at POS_MIN");
-               return -BCH_ERR_invalid_bkey;
-       }
+       bkey_fsck_err_on(bkey_eq(k.k->p, POS_MIN) ||
+                        bpos_gt(k.k->p, POS(0, U32_MAX)), c, err,
+                        stripe_pos_bad,
+                        "stripe at bad pos");
 
-       if (k.k->p.inode) {
-               prt_printf(err, "nonzero inode field");
-               return -BCH_ERR_invalid_bkey;
-       }
-
-       if (bkey_val_u64s(k.k) < stripe_val_u64s(s)) {
-               prt_printf(err, "incorrect value size (%zu < %u)",
-                      bkey_val_u64s(k.k), stripe_val_u64s(s));
-               return -BCH_ERR_invalid_bkey;
-       }
+       bkey_fsck_err_on(bkey_val_u64s(k.k) < stripe_val_u64s(s), c, err,
+                        stripe_val_size_bad,
+                        "incorrect value size (%zu < %u)",
+                        bkey_val_u64s(k.k), stripe_val_u64s(s));
 
-       return bch2_bkey_ptrs_invalid(c, k, flags, err);
+       ret = bch2_bkey_ptrs_invalid(c, k, flags, err);
+fsck_err:
+       return ret;
 }
 
 void bch2_stripe_to_text(struct printbuf *out, struct bch_fs *c,
@@ -153,6 +150,7 @@ void bch2_stripe_to_text(struct printbuf *out, struct bch_fs *c,
                prt_printf(out, " %u:%llu:%u", ptr->dev, b, offset);
                if (i < nr_data)
                        prt_printf(out, "#%u", stripe_blockcount_get(s, i));
+               prt_printf(out, " gen %u", ptr->gen);
                if (ptr_stale(ca, ptr))
                        prt_printf(out, " stale");
        }
@@ -306,16 +304,21 @@ static void ec_validate_checksums(struct bch_fs *c, struct ec_stripe_buf *buf)
                        struct bch_csum got = ec_block_checksum(buf, i, offset);
 
                        if (bch2_crc_cmp(want, got)) {
-                               struct printbuf buf2 = PRINTBUF;
-
-                               bch2_bkey_val_to_text(&buf2, c, bkey_i_to_s_c(&buf->key));
+                               struct printbuf err = PRINTBUF;
+                               struct bch_dev *ca = bch_dev_bkey_exists(c, v->ptrs[i].dev);
+
+                               prt_printf(&err, "stripe checksum error: expected %0llx:%0llx got %0llx:%0llx (type %s)\n",
+                                          want.hi, want.lo,
+                                          got.hi, got.lo,
+                                          bch2_csum_types[v->csum_type]);
+                               prt_printf(&err, "  for %ps at %u of\n  ", (void *) _RET_IP_, i);
+                               bch2_bkey_val_to_text(&err, c, bkey_i_to_s_c(&buf->key));
+                               bch_err_ratelimited(ca, "%s", err.buf);
+                               printbuf_exit(&err);
 
-                               bch_err_ratelimited(c,
-                                       "stripe checksum error for %ps at %u:%u: csum type %u, expected %llx got %llx\n%s",
-                                       (void *) _RET_IP_, i, j, v->csum_type,
-                                       want.lo, got.lo, buf2.buf);
-                               printbuf_exit(&buf2);
                                clear_bit(i, buf->valid);
+
+                               bch2_io_error(ca, BCH_MEMBER_ERROR_checksum);
                                break;
                        }
 
@@ -373,7 +376,11 @@ static void ec_block_endio(struct bio *bio)
        struct bch_dev *ca = ec_bio->ca;
        struct closure *cl = bio->bi_private;
 
-       if (bch2_dev_io_err_on(bio->bi_status, ca, "erasure coding %s error: %s",
+       if (bch2_dev_io_err_on(bio->bi_status, ca,
+                              bio_data_dir(bio)
+                              ? BCH_MEMBER_ERROR_write
+                              : BCH_MEMBER_ERROR_read,
+                              "erasure coding %s error: %s",
                               bio_data_dir(bio) ? "write" : "read",
                               bch2_blk_status_to_str(bio->bi_status)))
                clear_bit(ec_bio->idx, ec_bio->buf->valid);
@@ -474,14 +481,10 @@ err:
        return ret;
 }
 
-static int get_stripe_key(struct bch_fs *c, u64 idx, struct ec_stripe_buf *stripe)
-{
-       return bch2_trans_run(c, get_stripe_key_trans(trans, idx, stripe));
-}
-
 /* recovery read path: */
-int bch2_ec_read_extent(struct bch_fs *c, struct bch_read_bio *rbio)
+int bch2_ec_read_extent(struct btree_trans *trans, struct bch_read_bio *rbio)
 {
+       struct bch_fs *c = trans->c;
        struct ec_stripe_buf *buf;
        struct closure cl;
        struct bch_stripe *v;
@@ -496,7 +499,7 @@ int bch2_ec_read_extent(struct bch_fs *c, struct bch_read_bio *rbio)
        if (!buf)
                return -BCH_ERR_ENOMEM_ec_read_extent;
 
-       ret = get_stripe_key(c, rbio->pick.ec.idx, buf);
+       ret = lockrestart_do(trans, get_stripe_key_trans(trans, rbio->pick.ec.idx, buf));
        if (ret) {
                bch_err_ratelimited(c,
                        "error doing reconstruct read: error %i looking up stripe", ret);
@@ -800,7 +803,7 @@ static void ec_stripe_delete_work(struct work_struct *work)
                if (!idx)
                        break;
 
-               ret = commit_do(trans, NULL, NULL, BTREE_INSERT_NOFAIL,
+               ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
                                ec_stripe_delete(trans, idx));
                if (ret) {
                        bch_err_fn(c, ret);
@@ -980,8 +983,8 @@ static int ec_stripe_update_bucket(struct btree_trans *trans, struct ec_stripe_b
 
        while (1) {
                ret = commit_do(trans, NULL, NULL,
-                               BTREE_INSERT_NOCHECK_RW|
-                               BTREE_INSERT_NOFAIL,
+                               BCH_TRANS_COMMIT_no_check_rw|
+                               BCH_TRANS_COMMIT_no_enospc,
                        ec_stripe_update_extent(trans, bucket_pos, bucket.gen,
                                                s, &bp_pos));
                if (ret)
@@ -1002,7 +1005,7 @@ static int ec_stripe_update_extents(struct bch_fs *c, struct ec_stripe_buf *s)
        unsigned i, nr_data = v->nr_blocks - v->nr_redundant;
        int ret = 0;
 
-       ret = bch2_btree_write_buffer_flush(trans);
+       ret = bch2_btree_write_buffer_flush_nocheck_rw(trans);
        if (ret)
                goto err;
 
@@ -1118,8 +1121,8 @@ static void ec_stripe_create(struct ec_stripe_new *s)
        }
 
        ret = bch2_trans_do(c, &s->res, NULL,
-                           BTREE_INSERT_NOCHECK_RW|
-                           BTREE_INSERT_NOFAIL,
+                           BCH_TRANS_COMMIT_no_check_rw|
+                           BCH_TRANS_COMMIT_no_enospc,
                            ec_stripe_key_update(trans,
                                        bkey_i_to_stripe(&s->new_stripe.key),
                                        !s->have_existing_stripe));
@@ -1370,6 +1373,15 @@ ec_new_stripe_head_alloc(struct bch_fs *c, unsigned target,
                        h->nr_active_devs++;
 
        rcu_read_unlock();
+
+       /*
+        * If we only have redundancy + 1 devices, we're better off with just
+        * replication:
+        */
+       if (h->nr_active_devs < h->redundancy + 2)
+               bch_err(c, "insufficient devices available to create stripe (have %u, need %u) - mismatched bucket sizes?",
+                       h->nr_active_devs, h->redundancy + 2);
+
        list_add(&h->list, &c->ec_stripe_head_list);
        return h;
 }
@@ -1403,7 +1415,7 @@ __bch2_ec_stripe_head_get(struct btree_trans *trans,
        if (ret)
                return ERR_PTR(ret);
 
-       if (test_bit(BCH_FS_GOING_RO, &c->flags)) {
+       if (test_bit(BCH_FS_going_ro, &c->flags)) {
                h = ERR_PTR(-BCH_ERR_erofs_no_writes);
                goto found;
        }
@@ -1421,6 +1433,11 @@ __bch2_ec_stripe_head_get(struct btree_trans *trans,
 
        h = ec_new_stripe_head_alloc(c, target, algo, redundancy, watermark);
 found:
+       if (!IS_ERR_OR_NULL(h) &&
+           h->nr_active_devs < h->redundancy + 2) {
+               mutex_unlock(&h->lock);
+               h = NULL;
+       }
        mutex_unlock(&c->ec_stripe_head_lock);
        return h;
 }
@@ -1678,8 +1695,6 @@ struct ec_stripe_head *bch2_ec_stripe_head_get(struct btree_trans *trans,
        int ret;
 
        h = __bch2_ec_stripe_head_get(trans, target, algo, redundancy, watermark);
-       if (!h)
-               bch_err(c, "no stripe head");
        if (IS_ERR_OR_NULL(h))
                return h;