#include "btree_write_buffer.h"
#include "buckets.h"
#include "clock.h"
-#include "disk_groups.h"
#include "errcode.h"
#include "error.h"
-#include "extents.h"
-#include "eytzinger.h"
-#include "io.h"
-#include "keylist.h"
#include "lru.h"
#include "move.h"
#include "movinggc.h"
-#include "super-io.h"
+#include "trace.h"
-#include <trace/events/bcachefs.h>
-#include <linux/bsearch.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/math64.h>
#include <linux/sched/task.h>
-#include <linux/sort.h>
#include <linux/wait.h>
struct buckets_in_flight {
b->k.bucket.offset))
return 0;
- bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc,
- b->k.bucket, BTREE_ITER_CACHED);
- k = bch2_btree_iter_peek_slot(&iter);
+ k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_alloc,
+ b->k.bucket, BTREE_ITER_CACHED);
ret = bkey_err(k);
- bch2_trans_iter_exit(trans, &iter);
-
if (ret)
return ret;
a->fragmentation_lru &&
a->fragmentation_lru <= time;
- if (!ret) {
- struct printbuf buf = PRINTBUF;
-
- bch2_bkey_val_to_text(&buf, trans->c, k);
- pr_debug("%s", buf.buf);
- printbuf_exit(&buf);
- }
-
+ bch2_trans_iter_exit(trans, &iter);
return ret;
}
if (atomic_read(&i->count))
break;
- /*
- * moving_ctxt_exit calls bch2_write as it flushes pending
- * reads, which inits another btree_trans; this one must be
- * unlocked:
- */
- bch2_verify_bucket_evacuated(trans, i->bucket.k.bucket, i->bucket.k.gen);
-
list->first = i->next;
if (!list->first)
list->last = NULL;
struct bch_fs *c = trans->c;
struct btree_iter iter;
struct bkey_s_c k;
- size_t nr_to_get = max(16UL, buckets_in_flight->nr / 4);
+ size_t nr_to_get = max_t(size_t, 16U, buckets_in_flight->nr / 4);
size_t saw = 0, in_flight = 0, not_movable = 0, sectors = 0;
int ret;
lru_pos(BCH_LRU_FRAGMENTATION_START, U64_MAX, LRU_TIME_MAX),
0, k, ({
struct move_bucket b = { .k.bucket = u64_to_bucket(k.k->p.offset) };
- int ret = 0;
+ int ret2 = 0;
saw++;
else if (bucket_in_flight(buckets_in_flight, b.k))
in_flight++;
else {
- ret = darray_push(buckets, b) ?: buckets->nr >= nr_to_get;
- if (ret >= 0)
+ ret2 = darray_push(buckets, b) ?: buckets->nr >= nr_to_get;
+ if (ret2 >= 0)
sectors += b.sectors;
}
- ret;
+ ret2;
}));
pr_debug("have: %zu (%zu) saw %zu in flight %zu not movable %zu got %zu (%zu)/%zu buckets ret %i",
return ret < 0 ? ret : 0;
}
+noinline
static int bch2_copygc(struct btree_trans *trans,
struct moving_context *ctxt,
struct buckets_in_flight *buckets_in_flight)
{
struct bch_fs *c = trans->c;
struct data_update_opts data_opts = {
- .btree_insert_flags = BTREE_INSERT_USE_RESERVE|JOURNAL_WATERMARK_copygc,
+ .btree_insert_flags = BCH_WATERMARK_copygc,
};
move_buckets buckets = { 0 };
struct move_bucket_in_flight *f;
f = move_bucket_in_flight_add(buckets_in_flight, *i);
ret = PTR_ERR_OR_ZERO(f);
- if (ret == -EEXIST) /* rare race: copygc_get_buckets returned same bucket more than once */
+ if (ret == -EEXIST) { /* rare race: copygc_get_buckets returned same bucket more than once */
+ ret = 0;
continue;
+ }
if (ret == -ENOMEM) { /* flush IO, continue later */
ret = 0;
break;
darray_exit(&buckets);
/* no entries in LRU btree found, or got to end: */
- if (ret == -ENOENT)
+ if (bch2_err_matches(ret, ENOENT))
ret = 0;
if (ret < 0 && !bch2_err_matches(ret, EROFS))
- bch_err(c, "error from bch2_move_data() in copygc: %s", bch2_err_str(ret));
+ bch_err_msg(c, ret, "from bch2_move_data()");
moved = atomic64_read(&ctxt->stats->sectors_moved) - moved;
trace_and_count(c, copygc, c, moved, 0, 0, 0);
for_each_rw_member(ca, c, dev_idx) {
struct bch_dev_usage usage = bch2_dev_usage_read(ca);
- fragmented_allowed = ((__dev_buckets_available(ca, usage, RESERVE_stripe) *
+ fragmented_allowed = ((__dev_buckets_available(ca, usage, BCH_WATERMARK_stripe) *
ca->mi.bucket_size) >> 1);
fragmented = 0;
static int bch2_copygc_thread(void *arg)
{
struct bch_fs *c = arg;
- struct btree_trans trans;
+ struct btree_trans *trans;
struct moving_context ctxt;
struct bch_move_stats move_stats;
struct io_clock *clock = &c->io_clock[WRITE];
- struct buckets_in_flight move_buckets;
+ struct buckets_in_flight buckets;
u64 last, wait;
int ret = 0;
- memset(&move_buckets, 0, sizeof(move_buckets));
+ memset(&buckets, 0, sizeof(buckets));
- ret = rhashtable_init(&move_buckets.table, &bch_move_bucket_params);
+ ret = rhashtable_init(&buckets.table, &bch_move_bucket_params);
if (ret) {
- bch_err(c, "error allocating copygc buckets in flight: %s",
- bch2_err_str(ret));
+ bch_err_msg(c, ret, "allocating copygc buckets in flight");
return ret;
}
set_freezable();
- bch2_trans_init(&trans, c, 0, 0);
+ trans = bch2_trans_get(c);
bch2_move_stats_init(&move_stats, "copygc");
bch2_moving_ctxt_init(&ctxt, c, NULL, &move_stats,
false);
while (!ret && !kthread_should_stop()) {
- bch2_trans_unlock(&trans);
+ bch2_trans_unlock(trans);
cond_resched();
if (!c->copy_gc_enabled) {
- move_buckets_wait(&trans, &ctxt, &move_buckets, true);
+ move_buckets_wait(trans, &ctxt, &buckets, true);
kthread_wait_freezable(c->copy_gc_enabled);
}
if (unlikely(freezing(current))) {
- move_buckets_wait(&trans, &ctxt, &move_buckets, true);
+ move_buckets_wait(trans, &ctxt, &buckets, true);
__refrigerator(false);
continue;
}
if (wait > clock->max_slop) {
c->copygc_wait_at = last;
c->copygc_wait = last + wait;
- move_buckets_wait(&trans, &ctxt, &move_buckets, true);
+ move_buckets_wait(trans, &ctxt, &buckets, true);
trace_and_count(c, copygc_wait, c, wait, last + wait);
bch2_kthread_io_clock_wait(clock, last + wait,
MAX_SCHEDULE_TIMEOUT);
c->copygc_wait = 0;
c->copygc_running = true;
- ret = bch2_copygc(&trans, &ctxt, &move_buckets);
+ ret = bch2_copygc(trans, &ctxt, &buckets);
c->copygc_running = false;
wake_up(&c->copygc_running_wq);
}
- move_buckets_wait(&trans, &ctxt, &move_buckets, true);
- bch2_trans_exit(&trans);
+ move_buckets_wait(trans, &ctxt, &buckets, true);
+ rhashtable_destroy(&buckets.table);
+ bch2_trans_put(trans);
bch2_moving_ctxt_exit(&ctxt);
return 0;
t = kthread_create(bch2_copygc_thread, c, "bch-copygc/%s", c->name);
ret = PTR_ERR_OR_ZERO(t);
if (ret) {
- bch_err(c, "error creating copygc thread: %s", bch2_err_str(ret));
+ bch_err_msg(c, ret, "creating copygc thread");
return ret;
}