#include <linux/rculist.h>
#include <linux/rcupdate.h>
-const char * const bch2_alloc_reserves[] = {
+static void bch2_trans_mutex_lock_norelock(struct btree_trans *trans,
+ struct mutex *lock)
+{
+ if (!mutex_trylock(lock)) {
+ bch2_trans_unlock(trans);
+ mutex_lock(lock);
+ }
+}
+
+const char * const bch2_watermarks[] = {
#define x(t) #t,
- BCH_ALLOC_RESERVES()
+ BCH_WATERMARKS()
#undef x
NULL
};
return ob;
}
-static void open_bucket_free_unused(struct bch_fs *c,
- struct write_point *wp,
- struct open_bucket *ob)
+static void open_bucket_free_unused(struct bch_fs *c, struct open_bucket *ob)
{
BUG_ON(c->open_buckets_partial_nr >=
ARRAY_SIZE(c->open_buckets_partial));
return -1;
}
-static inline unsigned open_buckets_reserved(enum alloc_reserve reserve)
+static inline unsigned open_buckets_reserved(enum bch_watermark watermark)
{
- switch (reserve) {
- case RESERVE_btree:
- case RESERVE_btree_movinggc:
+ switch (watermark) {
+ case BCH_WATERMARK_reclaim:
return 0;
- case RESERVE_movinggc:
+ case BCH_WATERMARK_btree:
+ case BCH_WATERMARK_btree_copygc:
return OPEN_BUCKETS_COUNT / 4;
+ case BCH_WATERMARK_copygc:
+ return OPEN_BUCKETS_COUNT / 3;
default:
return OPEN_BUCKETS_COUNT / 2;
}
static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *ca,
u64 bucket,
- enum alloc_reserve reserve,
+ enum bch_watermark watermark,
const struct bch_alloc_v4 *a,
struct bucket_alloc_state *s,
struct closure *cl)
spin_lock(&c->freelist_lock);
- if (unlikely(c->open_buckets_nr_free <= open_buckets_reserved(reserve))) {
+ if (unlikely(c->open_buckets_nr_free <= open_buckets_reserved(watermark))) {
if (cl)
closure_wait(&c->open_buckets_wait, cl);
}
static struct open_bucket *try_alloc_bucket(struct btree_trans *trans, struct bch_dev *ca,
- enum alloc_reserve reserve, u64 free_entry,
+ enum bch_watermark watermark, u64 free_entry,
struct bucket_alloc_state *s,
struct bkey_s_c freespace_k,
struct closure *cl)
a = bch2_alloc_to_v4(k, &a_convert);
if (a->data_type != BCH_DATA_free) {
- if (!test_bit(BCH_FS_CHECK_ALLOC_DONE, &c->flags)) {
+ if (c->curr_recovery_pass <= BCH_RECOVERY_PASS_check_alloc_info) {
ob = NULL;
goto err;
}
}
if (genbits != (alloc_freespace_genbits(*a) >> 56) &&
- test_bit(BCH_FS_CHECK_ALLOC_DONE, &c->flags)) {
+ c->curr_recovery_pass > BCH_RECOVERY_PASS_check_alloc_info) {
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_trans_inconsistent(trans, "%s", buf.buf);
ob = ERR_PTR(-EIO);
goto err;
-
}
- if (!test_bit(BCH_FS_CHECK_BACKPOINTERS_DONE, &c->flags)) {
+ if (c->curr_recovery_pass <= BCH_RECOVERY_PASS_check_extents_to_backpointers) {
struct bch_backpointer bp;
struct bpos bp_pos = POS_MIN;
}
}
- ob = __try_alloc_bucket(c, ca, b, reserve, a, s, cl);
+ ob = __try_alloc_bucket(c, ca, b, watermark, a, s, cl);
if (!ob)
iter.path->preserve = false;
err:
- set_btree_iter_dontneed(&iter);
+ if (iter.trans && iter.path)
+ set_btree_iter_dontneed(&iter);
bch2_trans_iter_exit(trans, &iter);
printbuf_exit(&buf);
return ob;
static noinline struct open_bucket *
bch2_bucket_alloc_early(struct btree_trans *trans,
struct bch_dev *ca,
- enum alloc_reserve reserve,
+ enum bch_watermark watermark,
struct bucket_alloc_state *s,
struct closure *cl)
{
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, watermark, a, s, cl);
if (ob)
break;
}
static struct open_bucket *bch2_bucket_alloc_freelist(struct btree_trans *trans,
struct bch_dev *ca,
- enum alloc_reserve reserve,
+ enum bch_watermark watermark,
struct bucket_alloc_state *s,
struct closure *cl)
{
s->buckets_seen++;
- ob = try_alloc_bucket(trans, ca, reserve,
+ ob = try_alloc_bucket(trans, ca, watermark,
alloc_cursor, s, k, cl);
if (ob) {
iter.path->preserve = false;
*/
static struct open_bucket *bch2_bucket_alloc_trans(struct btree_trans *trans,
struct bch_dev *ca,
- enum alloc_reserve reserve,
+ enum bch_watermark watermark,
struct closure *cl,
struct bch_dev_usage *usage)
{
bool waiting = false;
again:
bch2_dev_usage_read_fast(ca, usage);
- avail = dev_buckets_free(ca, *usage, reserve);
+ avail = dev_buckets_free(ca, *usage, watermark);
if (usage->d[BCH_DATA_need_discard].buckets > avail)
bch2_do_discards(c);
closure_wake_up(&c->freelist_wait);
alloc:
ob = likely(freespace)
- ? bch2_bucket_alloc_freelist(trans, ca, reserve, &s, cl)
- : bch2_bucket_alloc_early(trans, ca, reserve, &s, cl);
+ ? bch2_bucket_alloc_freelist(trans, ca, watermark, &s, cl)
+ : bch2_bucket_alloc_early(trans, ca, watermark, &s, cl);
if (s.skipped_need_journal_commit * 2 > avail)
bch2_journal_flush_async(&c->journal, NULL);
- if (!ob && freespace && !test_bit(BCH_FS_CHECK_ALLOC_DONE, &c->flags)) {
+ if (!ob && freespace && c->curr_recovery_pass <= BCH_RECOVERY_PASS_check_alloc_info) {
freespace = false;
goto alloc;
}
if (!IS_ERR(ob))
trace_and_count(c, bucket_alloc, ca,
- bch2_alloc_reserves[reserve],
+ bch2_watermarks[watermark],
ob->bucket,
usage->d[BCH_DATA_free].buckets,
avail,
"");
else if (!bch2_err_matches(PTR_ERR(ob), BCH_ERR_transaction_restart))
trace_and_count(c, bucket_alloc_fail, ca,
- bch2_alloc_reserves[reserve],
+ bch2_watermarks[watermark],
0,
usage->d[BCH_DATA_free].buckets,
avail,
}
struct open_bucket *bch2_bucket_alloc(struct bch_fs *c, struct bch_dev *ca,
- enum alloc_reserve reserve,
+ enum bch_watermark watermark,
struct closure *cl)
{
struct bch_dev_usage usage;
struct open_bucket *ob;
bch2_trans_do(c, NULL, NULL, 0,
- PTR_ERR_OR_ZERO(ob = bch2_bucket_alloc_trans(&trans, ca, reserve,
+ PTR_ERR_OR_ZERO(ob = bch2_bucket_alloc_trans(&trans, ca, watermark,
cl, &usage)));
return ob;
}
struct bch_dev_usage *usage)
{
u64 *v = stripe->next_alloc + ca->dev_idx;
- u64 free_space = dev_buckets_available(ca, RESERVE_none);
+ u64 free_space = dev_buckets_available(ca, BCH_WATERMARK_normal);
u64 free_space_inv = free_space
? div64_u64(1ULL << 48, free_space)
: 1ULL << 48;
bool *have_cache,
unsigned flags,
enum bch_data_type data_type,
- enum alloc_reserve reserve,
+ enum bch_watermark watermark,
struct closure *cl)
{
struct bch_fs *c = trans->c;
continue;
}
- ob = bch2_bucket_alloc_trans(trans, ca, reserve, cl, &usage);
+ ob = bch2_bucket_alloc_trans(trans, ca, watermark, cl, &usage);
if (!IS_ERR(ob))
bch2_dev_stripe_increment_inlined(ca, stripe, &usage);
percpu_ref_put(&ca->ref);
unsigned nr_replicas,
unsigned *nr_effective,
bool *have_cache,
- enum alloc_reserve reserve,
+ enum bch_watermark watermark,
unsigned flags,
struct closure *cl)
{
if (ec_open_bucket(c, ptrs))
return 0;
- h = bch2_ec_stripe_head_get(trans, target, 0, nr_replicas - 1, reserve, cl);
+ h = bch2_ec_stripe_head_get(trans, target, 0, nr_replicas - 1, watermark, cl);
if (IS_ERR(h))
return PTR_ERR(h);
if (!h)
unsigned nr_replicas,
unsigned *nr_effective,
bool *have_cache, bool ec,
- enum alloc_reserve reserve,
+ enum bch_watermark watermark,
unsigned flags)
{
int i, ret = 0;
u64 avail;
bch2_dev_usage_read_fast(ca, &usage);
- avail = dev_buckets_free(ca, usage, reserve);
+ avail = dev_buckets_free(ca, usage, watermark);
if (!avail)
continue;
unsigned nr_replicas,
unsigned *nr_effective,
bool *have_cache,
- enum alloc_reserve reserve,
+ enum bch_watermark watermark,
unsigned flags,
struct closure *_cl)
{
unsigned i;
int ret;
- rcu_read_lock();
devs = target_rw_devs(c, wp->data_type, target);
- rcu_read_unlock();
/* Don't allocate from devices we already have pointers to: */
for (i = 0; i < devs_have->nr; i++)
ret = bucket_alloc_set_partial(c, ptrs, wp, &devs,
nr_replicas, nr_effective,
- have_cache, erasure_code, reserve, flags);
+ have_cache, erasure_code, watermark, flags);
if (ret)
return ret;
target,
nr_replicas, nr_effective,
have_cache,
- reserve, flags, _cl);
+ watermark, flags, _cl);
} else {
retry_blocking:
/*
*/
ret = bch2_bucket_alloc_set_trans(trans, ptrs, &wp->stripe, &devs,
nr_replicas, nr_effective, have_cache,
- flags, wp->data_type, reserve, cl);
+ flags, wp->data_type, watermark, cl);
if (ret &&
!bch2_err_matches(ret, BCH_ERR_transaction_restart) &&
!bch2_err_matches(ret, BCH_ERR_insufficient_devices) &&
unsigned nr_replicas,
unsigned *nr_effective,
bool *have_cache,
- enum alloc_reserve reserve,
+ enum bch_watermark watermark,
unsigned flags,
struct closure *cl)
{
ret = __open_bucket_add_buckets(trans, ptrs, wp,
devs_have, target, erasure_code,
nr_replicas, nr_effective, have_cache,
- reserve, flags, cl);
+ watermark, flags, cl);
if (bch2_err_matches(ret, BCH_ERR_transaction_restart) ||
bch2_err_matches(ret, BCH_ERR_operation_blocked) ||
bch2_err_matches(ret, BCH_ERR_freelist_empty) ||
ret = __open_bucket_add_buckets(trans, ptrs, wp,
devs_have, target, false,
nr_replicas, nr_effective, have_cache,
- reserve, flags, cl);
+ watermark, flags, cl);
return ret < 0 ? ret : 0;
}
return true;
}
-static bool try_decrease_writepoints(struct bch_fs *c, unsigned old_nr)
+static bool try_decrease_writepoints(struct btree_trans *trans, unsigned old_nr)
{
+ struct bch_fs *c = trans->c;
struct write_point *wp;
+ struct open_bucket *ob;
+ unsigned i;
mutex_lock(&c->write_points_hash_lock);
if (c->write_points_nr < old_nr) {
hlist_del_rcu(&wp->node);
mutex_unlock(&c->write_points_hash_lock);
- bch2_writepoint_stop(c, NULL, false, wp);
+ bch2_trans_mutex_lock_norelock(trans, &wp->lock);
+ open_bucket_for_each(c, &wp->ptrs, ob, i)
+ open_bucket_free_unused(c, ob);
+ wp->ptrs.nr = 0;
+ mutex_unlock(&wp->lock);
return true;
}
-static void bch2_trans_mutex_lock_norelock(struct btree_trans *trans,
- struct mutex *lock)
-{
- if (!mutex_trylock(lock)) {
- bch2_trans_unlock(trans);
- mutex_lock(lock);
- }
-}
-
static struct write_point *writepoint_find(struct btree_trans *trans,
unsigned long write_point)
{
struct bch_devs_list *devs_have,
unsigned nr_replicas,
unsigned nr_replicas_required,
- enum alloc_reserve reserve,
+ enum bch_watermark watermark,
unsigned flags,
struct closure *cl,
struct write_point **wp_ret)
ret = open_bucket_add_buckets(trans, &ptrs, wp, devs_have,
target, erasure_code,
nr_replicas, &nr_effective,
- &have_cache, reserve,
+ &have_cache, watermark,
flags, NULL);
if (!ret ||
bch2_err_matches(ret, BCH_ERR_transaction_restart))
ret = open_bucket_add_buckets(trans, &ptrs, wp, devs_have,
0, erasure_code,
nr_replicas, &nr_effective,
- &have_cache, reserve,
+ &have_cache, watermark,
flags, cl);
} else {
allocate_blocking:
ret = open_bucket_add_buckets(trans, &ptrs, wp, devs_have,
target, erasure_code,
nr_replicas, &nr_effective,
- &have_cache, reserve,
+ &have_cache, watermark,
flags, cl);
}
alloc_done:
/* Free buckets we didn't use: */
open_bucket_for_each(c, &wp->ptrs, ob, i)
- open_bucket_free_unused(c, wp, ob);
+ open_bucket_free_unused(c, ob);
wp->ptrs = ptrs;
if (ptrs.nr < ARRAY_SIZE(ptrs.v))
ob_push(c, &ptrs, ob);
else
- open_bucket_free_unused(c, wp, ob);
+ open_bucket_free_unused(c, ob);
wp->ptrs = ptrs;
mutex_unlock(&wp->lock);
if (bch2_err_matches(ret, BCH_ERR_freelist_empty) &&
- try_decrease_writepoints(c, write_points_nr))
+ try_decrease_writepoints(trans, write_points_nr))
goto retry;
if (bch2_err_matches(ret, BCH_ERR_open_buckets_empty) ||