BUG_ON(m.dirty_sectors);
- bch2_mark_alloc_bucket(c, ca, b, true, gc_pos_alloc(c, NULL), 0);
+ bch2_mark_alloc_bucket(c, ca, b, true);
spin_lock(&c->freelist_lock);
verify_not_on_freelist(c, ca, b);
percpu_down_read(&c->mark_lock);
spin_lock(&c->freelist_lock);
- bch2_mark_alloc_bucket(c, ca, b, false,
- gc_pos_alloc(c, NULL), 0);
+ bch2_mark_alloc_bucket(c, ca, b, false);
BUG_ON(!fifo_pop_back(&ca->free_inc, b2));
BUG_ON(b != b2);
percpu_down_read(&c->mark_lock);
spin_lock(&ob->lock);
- bch2_mark_alloc_bucket(c, ca, PTR_BUCKET_NR(ca, &ob->ptr),
- false, gc_pos_alloc(c, ob), 0);
+ bch2_mark_alloc_bucket(c, ca, PTR_BUCKET_NR(ca, &ob->ptr), false);
ob->valid = false;
ob->type = 0;
GC_PHASE_BTREE_reflink,
GC_PHASE_PENDING_DELETE,
- GC_PHASE_ALLOC,
};
struct gc_pos {
}
#endif
-static void bch2_mark_allocator_buckets(struct bch_fs *c)
-{
- struct bch_dev *ca;
- struct open_bucket *ob;
- size_t i, j, iter;
- unsigned ci;
-
- percpu_down_read(&c->mark_lock);
-
- spin_lock(&c->freelist_lock);
- gc_pos_set(c, gc_pos_alloc(c, NULL));
-
- for_each_member_device(ca, c, ci) {
- fifo_for_each_entry(i, &ca->free_inc, iter)
- bch2_mark_alloc_bucket(c, ca, i, true,
- gc_pos_alloc(c, NULL),
- BTREE_TRIGGER_GC);
-
-
-
- for (j = 0; j < RESERVE_NR; j++)
- fifo_for_each_entry(i, &ca->free[j], iter)
- bch2_mark_alloc_bucket(c, ca, i, true,
- gc_pos_alloc(c, NULL),
- BTREE_TRIGGER_GC);
- }
-
- spin_unlock(&c->freelist_lock);
-
- for (ob = c->open_buckets;
- ob < c->open_buckets + ARRAY_SIZE(c->open_buckets);
- ob++) {
- spin_lock(&ob->lock);
- if (ob->valid) {
- gc_pos_set(c, gc_pos_alloc(c, ob));
- ca = bch_dev_bkey_exists(c, ob->ptr.dev);
- bch2_mark_alloc_bucket(c, ca, PTR_BUCKET_NR(ca, &ob->ptr), true,
- gc_pos_alloc(c, ob),
- BTREE_TRIGGER_GC);
- }
- spin_unlock(&ob->lock);
- }
-
- percpu_up_read(&c->mark_lock);
-}
-
static void bch2_gc_free(struct bch_fs *c)
{
struct bch_dev *ca;
for (b = 0; b < src->nbuckets; b++) {
copy_bucket_field(gen);
copy_bucket_field(data_type);
- copy_bucket_field(owned_by_allocator);
copy_bucket_field(stripe);
copy_bucket_field(dirty_sectors);
copy_bucket_field(cached_sectors);
if (metadata_only &&
(s->mark.data_type == BCH_DATA_user ||
- s->mark.data_type == BCH_DATA_cached)) {
+ s->mark.data_type == BCH_DATA_cached))
d->_mark = s->mark;
- d->_mark.owned_by_allocator = 0;
- }
}
};
#if 0
bch2_mark_pending_btree_node_frees(c);
#endif
- bch2_mark_allocator_buckets(c);
-
c->gc_count++;
if (test_bit(BCH_FS_NEED_ANOTHER_GC, &c->flags) ||
return gc_pos_btree(id, POS_MAX, BTREE_MAX_DEPTH);
}
-static inline struct gc_pos gc_pos_alloc(struct bch_fs *c, struct open_bucket *ob)
-{
- return (struct gc_pos) {
- .phase = GC_PHASE_ALLOC,
- .pos = POS(ob ? ob - c->open_buckets : 0, 0),
- };
-}
-
static inline bool gc_visited(struct bch_fs *c, struct gc_pos pos)
{
unsigned seq;
* Code for manipulating bucket marks for garbage collection.
*
* Copyright 2014 Datera, Inc.
- *
- * Bucket states:
- * - free bucket: mark == 0
- * The bucket contains no data and will not be read
- *
- * - allocator bucket: owned_by_allocator == 1
- * The bucket is on a free list, or it is an open bucket
- *
- * - cached bucket: owned_by_allocator == 0 &&
- * dirty_sectors == 0 &&
- * cached_sectors > 0
- * The bucket contains data but may be safely discarded as there are
- * enough replicas of the data on other cache devices, or it has been
- * written back to the backing device
- *
- * - dirty bucket: owned_by_allocator == 0 &&
- * dirty_sectors > 0
- * The bucket contains data that we must not discard (either only copy,
- * or one of the 'main copies' for data requiring multiple replicas)
- *
- * - metadata bucket: owned_by_allocator == 0 && is_metadata == 1
- * This is a btree node, journal or gen/prio bucket
- *
- * Lifecycle:
- *
- * bucket invalidated => bucket on freelist => open bucket =>
- * [dirty bucket =>] cached bucket => bucket invalidated => ...
- *
- * Note that cache promotion can skip the dirty bucket step, as data
- * is copied from a deeper tier to a shallower tier, onto a cached
- * bucket.
- * Note also that a cached bucket can spontaneously become dirty --
- * see below.
- *
- * Only a traversal of the key space can determine whether a bucket is
- * truly dirty or cached.
- *
- * Transitions:
- *
- * - free => allocator: bucket was invalidated
- * - cached => allocator: bucket was invalidated
- *
- * - allocator => dirty: open bucket was filled up
- * - allocator => cached: open bucket was filled up
- * - allocator => metadata: metadata was allocated
- *
- * - dirty => cached: dirty sectors were copied to a deeper tier
- * - dirty => free: dirty sectors were overwritten or moved (copy gc)
- * - cached => free: cached sectors were overwritten
- *
- * - metadata => free: metadata was freed
- *
- * Oddities:
- * - cached => dirty: a device was removed so formerly replicated data
- * is no longer sufficiently replicated
- * - free => cached: cannot happen
- * - free => dirty: cannot happen
- * - free => metadata: cannot happen
*/
#include "bcachefs.h"
ret; \
})
-static int __bch2_mark_alloc_bucket(struct bch_fs *c, struct bch_dev *ca,
- size_t b, bool owned_by_allocator,
- bool gc)
+void bch2_mark_alloc_bucket(struct bch_fs *c, struct bch_dev *ca,
+ size_t b, bool owned_by_allocator)
{
- struct bucket *g = __bucket(ca, b, gc);
+ struct bucket *g = bucket(ca, b);
struct bucket_mark old, new;
old = bucket_cmpxchg(g, new, ({
new.owned_by_allocator = owned_by_allocator;
}));
- BUG_ON(!gc &&
- !owned_by_allocator && !old.owned_by_allocator);
-
- return 0;
-}
-
-void bch2_mark_alloc_bucket(struct bch_fs *c, struct bch_dev *ca,
- size_t b, bool owned_by_allocator,
- struct gc_pos pos, unsigned flags)
-{
- preempt_disable();
-
- do_mark_fn(__bch2_mark_alloc_bucket, c, pos, flags,
- ca, b, owned_by_allocator);
-
- preempt_enable();
+ BUG_ON(owned_by_allocator == old.owned_by_allocator);
}
static int bch2_mark_alloc(struct bch_fs *c,
void bch2_bucket_seq_cleanup(struct bch_fs *);
void bch2_fs_usage_initialize(struct bch_fs *);
-void bch2_mark_alloc_bucket(struct bch_fs *, struct bch_dev *,
- size_t, bool, struct gc_pos, unsigned);
+void bch2_mark_alloc_bucket(struct bch_fs *, struct bch_dev *, size_t, bool);
void bch2_mark_metadata_bucket(struct bch_fs *, struct bch_dev *,
size_t, enum bch_data_type, unsigned,
struct gc_pos, unsigned);