#include "debug.h"
#include "super.h"
-struct bkey_alloc_unpacked {
- u64 journal_seq;
- u64 bucket;
- u8 dev;
- u8 gen;
- u8 oldest_gen;
- u8 data_type;
- bool need_discard:1;
- bool need_inc_gen:1;
-#define x(_name, _bits) u##_bits _name;
- BCH_ALLOC_FIELDS_V2()
-#undef x
-};
-
/* How out of date a pointer gen is allowed to be: */
#define BUCKET_GC_GEN_MAX 96U
-static inline u8 alloc_gc_gen(struct bkey_alloc_unpacked a)
+static inline bool bch2_dev_bucket_exists(struct bch_fs *c, struct bpos pos)
{
- return a.gen - a.oldest_gen;
-}
+ struct bch_dev *ca;
-enum bucket_state {
- BUCKET_free,
- BUCKET_need_gc_gens,
- BUCKET_need_discard,
- BUCKET_cached,
- BUCKET_dirty,
-};
+ if (!bch2_dev_exists2(c, pos.inode))
+ return false;
-extern const char * const bch2_bucket_states[];
+ ca = bch_dev_bkey_exists(c, pos.inode);
+ return pos.offset >= ca->mi.first_bucket &&
+ pos.offset < ca->mi.nbuckets;
+}
-static inline enum bucket_state bucket_state(struct bkey_alloc_unpacked a)
+static inline u8 alloc_gc_gen(struct bch_alloc_v4 a)
{
- if (a.dirty_sectors || a.stripe)
- return BUCKET_dirty;
- if (a.cached_sectors)
- return BUCKET_cached;
- BUG_ON(a.data_type);
- if (a.need_discard)
- return BUCKET_need_discard;
- if (alloc_gc_gen(a) >= BUCKET_GC_GEN_MAX)
- return BUCKET_need_gc_gens;
- return BUCKET_free;
+ return a.gen - a.oldest_gen;
}
-static inline u64 alloc_lru_idx(struct bkey_alloc_unpacked a)
+static inline enum bch_data_type __alloc_data_type(u32 dirty_sectors,
+ u32 cached_sectors,
+ u32 stripe,
+ struct bch_alloc_v4 a,
+ enum bch_data_type data_type)
{
- return bucket_state(a) == BUCKET_cached ? a.read_time : 0;
+ if (dirty_sectors)
+ return data_type;
+ if (stripe)
+ return BCH_DATA_stripe;
+ if (cached_sectors)
+ return BCH_DATA_cached;
+ if (BCH_ALLOC_V4_NEED_DISCARD(&a))
+ return BCH_DATA_need_discard;
+ if (alloc_gc_gen(a) >= BUCKET_GC_GEN_MAX)
+ return BCH_DATA_need_gc_gens;
+ return BCH_DATA_free;
}
-static inline u64 alloc_freespace_genbits(struct bkey_alloc_unpacked a)
+static inline enum bch_data_type alloc_data_type(struct bch_alloc_v4 a,
+ enum bch_data_type data_type)
{
- return ((u64) alloc_gc_gen(a) >> 4) << 56;
+ return __alloc_data_type(a.dirty_sectors, a.cached_sectors,
+ a.stripe, a, data_type);
}
-static inline struct bpos alloc_freespace_pos(struct bkey_alloc_unpacked a)
+static inline u64 alloc_lru_idx(struct bch_alloc_v4 a)
{
- return POS(a.dev, a.bucket | alloc_freespace_genbits(a));
+ return a.data_type == BCH_DATA_cached ? a.io_time[READ] : 0;
}
-/* returns true if not equal */
-static inline bool bkey_alloc_unpacked_cmp(struct bkey_alloc_unpacked l,
- struct bkey_alloc_unpacked r)
+static inline u64 alloc_freespace_genbits(struct bch_alloc_v4 a)
{
- return l.gen != r.gen ||
- l.oldest_gen != r.oldest_gen ||
- l.data_type != r.data_type
-#define x(_name, ...) || l._name != r._name
- BCH_ALLOC_FIELDS_V2()
-#undef x
- ;
+ return ((u64) alloc_gc_gen(a) >> 4) << 56;
}
-struct bkey_alloc_buf {
- struct bkey_i k;
- struct bch_alloc_v3 v;
+static inline struct bpos alloc_freespace_pos(struct bpos pos, struct bch_alloc_v4 a)
+{
+ pos.offset |= alloc_freespace_genbits(a);
+ return pos;
+}
-#define x(_name, _bits) + _bits / 8
- u8 _pad[0 + BCH_ALLOC_FIELDS_V2()];
-#undef x
-} __attribute__((packed, aligned(8)));
+struct bkey_i_alloc_v4 *
+bch2_trans_start_alloc_update(struct btree_trans *, struct btree_iter *, struct bpos);
-struct bkey_alloc_unpacked bch2_alloc_unpack(struct bkey_s_c);
-struct bkey_alloc_buf *bch2_alloc_pack(struct btree_trans *,
- const struct bkey_alloc_unpacked);
-int bch2_alloc_write(struct btree_trans *, struct btree_iter *,
- struct bkey_alloc_unpacked *, unsigned);
+void bch2_alloc_to_v4(struct bkey_s_c, struct bch_alloc_v4 *);
+struct bkey_i_alloc_v4 *bch2_alloc_to_v4_mut(struct btree_trans *, struct bkey_s_c);
int bch2_bucket_io_time_reset(struct btree_trans *, unsigned, size_t, int);
#define ALLOC_SCAN_BATCH(ca) max_t(size_t, 1, (ca)->mi.nbuckets >> 9)
-const char *bch2_alloc_v1_invalid(const struct bch_fs *, struct bkey_s_c);
-const char *bch2_alloc_v2_invalid(const struct bch_fs *, struct bkey_s_c);
-const char *bch2_alloc_v3_invalid(const struct bch_fs *, struct bkey_s_c);
+int bch2_alloc_v1_invalid(const struct bch_fs *, struct bkey_s_c, int, struct printbuf *);
+int bch2_alloc_v2_invalid(const struct bch_fs *, struct bkey_s_c, int, struct printbuf *);
+int bch2_alloc_v3_invalid(const struct bch_fs *, struct bkey_s_c, int, struct printbuf *);
+int bch2_alloc_v4_invalid(const struct bch_fs *, struct bkey_s_c, int, struct printbuf *);
+void bch2_alloc_v4_swab(struct bkey_s);
void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
#define bch2_bkey_ops_alloc (struct bkey_ops) { \
.atomic_trigger = bch2_mark_alloc, \
}
+#define bch2_bkey_ops_alloc_v4 (struct bkey_ops) { \
+ .key_invalid = bch2_alloc_v4_invalid, \
+ .val_to_text = bch2_alloc_to_text, \
+ .swab = bch2_alloc_v4_swab, \
+ .trans_trigger = bch2_trans_mark_alloc, \
+ .atomic_trigger = bch2_mark_alloc, \
+}
+
static inline bool bkey_is_alloc(const struct bkey *k)
{
return k->type == KEY_TYPE_alloc ||
int bch2_alloc_read(struct bch_fs *);
-int bch2_trans_mark_alloc(struct btree_trans *, struct bkey_s_c,
- struct bkey_i *, unsigned);
-int bch2_check_alloc_info(struct bch_fs *, bool);
+int bch2_trans_mark_alloc(struct btree_trans *, enum btree_id, unsigned,
+ struct bkey_s_c, struct bkey_i *, unsigned);
+int bch2_check_alloc_info(struct bch_fs *);
+int bch2_check_alloc_to_lru_refs(struct bch_fs *);
void bch2_do_discards(struct bch_fs *);
-static inline bool should_invalidate_buckets(struct bch_dev *ca)
+static inline u64 should_invalidate_buckets(struct bch_dev *ca,
+ struct bch_dev_usage u)
{
- struct bch_dev_usage u = bch2_dev_usage_read(ca);
+ u64 free = u.d[BCH_DATA_free].buckets +
+ u.d[BCH_DATA_need_discard].buckets;
- return u.d[BCH_DATA_cached].buckets &&
- u.buckets_unavailable + u.d[BCH_DATA_cached].buckets <
- ca->mi.nbuckets >> 7;
+ return clamp_t(s64, (ca->mi.nbuckets >> 7) - free,
+ 0, u.d[BCH_DATA_cached].buckets);
}
void bch2_do_invalidates(struct bch_fs *);