#include "io.h"
#include "journal.h"
#include "movinggc.h"
+#include "nocow_locking.h"
#include <linux/math64.h>
#include <linux/rculist.h>
static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *ca,
u64 bucket,
enum alloc_reserve reserve,
- struct bch_alloc_v4 *a,
+ const struct bch_alloc_v4 *a,
struct bucket_alloc_state *s,
struct closure *cl)
{
struct btree_iter iter = { NULL };
struct bkey_s_c k;
struct open_bucket *ob;
- struct bch_alloc_v4 a;
+ struct bch_alloc_v4 a_convert;
+ const struct bch_alloc_v4 *a;
u64 b = free_entry & ~(~0ULL << 56);
unsigned genbits = free_entry >> 56;
struct printbuf buf = PRINTBUF;
goto err;
}
- bch2_alloc_to_v4(k, &a);
+ a = bch2_alloc_to_v4(k, &a_convert);
- if (genbits != (alloc_freespace_genbits(a) >> 56)) {
- prt_printf(&buf, "bucket in freespace btree with wrong genbits (got %u should be %llu)\n"
- " freespace key ",
- genbits, alloc_freespace_genbits(a) >> 56);
+ if (a->data_type != BCH_DATA_free) {
+ if (!test_bit(BCH_FS_CHECK_ALLOC_DONE, &c->flags)) {
+ ob = NULL;
+ goto err;
+ }
+
+ prt_printf(&buf, "non free bucket in freespace btree\n"
+ " freespace key ");
bch2_bkey_val_to_text(&buf, c, freespace_k);
prt_printf(&buf, "\n ");
bch2_bkey_val_to_text(&buf, c, k);
bch2_trans_inconsistent(trans, "%s", buf.buf);
ob = ERR_PTR(-EIO);
goto err;
-
}
- if (a.data_type != BCH_DATA_free) {
- prt_printf(&buf, "non free bucket in freespace btree\n"
- " freespace key ");
+ if (genbits != (alloc_freespace_genbits(*a) >> 56) &&
+ test_bit(BCH_FS_CHECK_ALLOC_DONE, &c->flags)) {
+ prt_printf(&buf, "bucket in freespace btree with wrong genbits (got %u should be %llu)\n"
+ " freespace key ",
+ genbits, alloc_freespace_genbits(*a) >> 56);
bch2_bkey_val_to_text(&buf, c, freespace_k);
prt_printf(&buf, "\n ");
bch2_bkey_val_to_text(&buf, c, k);
bch2_trans_inconsistent(trans, "%s", buf.buf);
ob = ERR_PTR(-EIO);
goto err;
+
}
if (!test_bit(BCH_FS_CHECK_BACKPOINTERS_DONE, &c->flags)) {
}
}
- ob = __try_alloc_bucket(c, ca, b, reserve, &a, s, cl);
+ ob = __try_alloc_bucket(c, ca, b, reserve, a, s, cl);
if (!ob)
iter.path->preserve = false;
err:
for_each_btree_key_norestart(trans, iter, BTREE_ID_alloc, POS(ca->dev_idx, s->cur_bucket),
BTREE_ITER_SLOTS, k, ret) {
- struct bch_alloc_v4 a;
+ struct bch_alloc_v4 a_convert;
+ const struct bch_alloc_v4 *a;
- if (bkey_cmp(k.k->p, POS(ca->dev_idx, ca->mi.nbuckets)) >= 0)
+ if (bkey_ge(k.k->p, POS(ca->dev_idx, ca->mi.nbuckets)))
break;
if (ca->new_fs_bucket_idx &&
is_superblock_bucket(ca, k.k->p.offset))
continue;
- bch2_alloc_to_v4(k, &a);
+ a = bch2_alloc_to_v4(k, &a_convert);
- if (a.data_type != BCH_DATA_free)
+ if (a->data_type != BCH_DATA_free)
continue;
s->buckets_seen++;
- ob = __try_alloc_bucket(trans->c, ca, k.k->p.offset, reserve, &a, s, cl);
+ ob = __try_alloc_bucket(trans->c, ca, k.k->p.offset, reserve, a, s, cl);
if (ob)
break;
}
{
struct bch_fs *c = trans->c;
struct open_bucket *ob = NULL;
- bool freespace_initialized = READ_ONCE(ca->mi.freespace_initialized);
- u64 start = freespace_initialized ? 0 : ca->bucket_alloc_trans_early_cursor;
+ bool freespace = READ_ONCE(ca->mi.freespace_initialized);
+ u64 start = freespace ? 0 : ca->bucket_alloc_trans_early_cursor;
u64 avail;
struct bucket_alloc_state s = { .cur_bucket = start };
bool waiting = false;
if (ob)
return ob;
}
-
- ob = likely(ca->mi.freespace_initialized)
+alloc:
+ ob = likely(freespace)
? bch2_bucket_alloc_freelist(trans, ca, reserve, &s, cl)
: bch2_bucket_alloc_early(trans, ca, reserve, &s, cl);
if (s.skipped_need_journal_commit * 2 > avail)
bch2_journal_flush_async(&c->journal, NULL);
- if (!ob && !freespace_initialized && start) {
+ if (!ob && !freespace && start) {
start = s.cur_bucket = 0;
- goto again;
+ goto alloc;
}
- if (!freespace_initialized)
+ if (!ob && freespace && !test_bit(BCH_FS_CHECK_ALLOC_DONE, &c->flags)) {
+ freespace = false;
+ goto alloc;
+ }
+
+ if (!freespace)
ca->bucket_alloc_trans_early_cursor = s.cur_bucket;
err:
if (!ob)
if (bch2_err_matches(ret, BCH_ERR_open_buckets_empty) ||
bch2_err_matches(ret, BCH_ERR_freelist_empty))
return cl
- ? -EAGAIN
+ ? -BCH_ERR_bucket_alloc_blocked
: -BCH_ERR_ENOSPC_bucket_alloc;
- if (bch2_err_matches(ret, BCH_ERR_insufficient_devices))
- return -EROFS;
-
return ret;
}
};
}
-/*
- * Append pointers to the space we just allocated to @k, and mark @sectors space
- * as allocated out of @ob
- */
void bch2_alloc_sectors_append_ptrs(struct bch_fs *c, struct write_point *wp,
struct bkey_i *k, unsigned sectors,
bool cached)
-
{
- struct open_bucket *ob;
- unsigned i;
-
- BUG_ON(sectors > wp->sectors_free);
- wp->sectors_free -= sectors;
-
- open_bucket_for_each(c, &wp->ptrs, ob, i) {
- struct bch_dev *ca = bch_dev_bkey_exists(c, ob->dev);
- struct bch_extent_ptr ptr = bch2_ob_ptr(c, ob);
-
- ptr.cached = cached ||
- (!ca->mi.durability &&
- wp->data_type == BCH_DATA_user);
-
- bch2_bkey_append_ptr(k, ptr);
-
- BUG_ON(sectors > ob->sectors_free);
- ob->sectors_free -= sectors;
- }
+ bch2_alloc_sectors_append_ptrs_inlined(c, wp, k, sectors, cached);
}
/*
*/
void bch2_alloc_sectors_done(struct bch_fs *c, struct write_point *wp)
{
- struct open_buckets ptrs = { .nr = 0 }, keep = { .nr = 0 };
- struct open_bucket *ob;
- unsigned i;
-
- open_bucket_for_each(c, &wp->ptrs, ob, i)
- ob_push(c, !ob->sectors_free ? &ptrs : &keep, ob);
- wp->ptrs = keep;
-
- mutex_unlock(&wp->lock);
-
- bch2_open_buckets_put(c, &ptrs);
+ bch2_alloc_sectors_done_inlined(c, wp);
}
static inline void writepoint_init(struct write_point *wp,