2159 lines · 53.7 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0#include "bcachefs.h"#include "alloc_background.h"#include "alloc_foreground.h"#include "backpointers.h"#include "btree_cache.h"#include "btree_io.h"#include "btree_key_cache.h"#include "btree_update.h"#include "btree_update_interior.h"#include "btree_gc.h"#include "btree_write_buffer.h"#include "buckets.h"#include "buckets_waiting_for_journal.h"#include "clock.h"#include "debug.h"#include "ec.h"#include "error.h"#include "lru.h"#include "recovery.h"#include "trace.h"#include "varint.h" #include <linux/kthread.h>#include <linux/math64.h>#include <linux/random.h>#include <linux/rculist.h>#include <linux/rcupdate.h>#include <linux/sched/task.h>#include <linux/sort.h> /* Persistent alloc info: */ static const unsigned BCH_ALLOC_V1_FIELD_BYTES[] = {#define x(name, bits) [BCH_ALLOC_FIELD_V1_##name] = bits / 8,	BCH_ALLOC_FIELDS_V1()#undef x}; struct bkey_alloc_unpacked {	u64		journal_seq;	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}; static inline u64 alloc_field_v1_get(const struct bch_alloc *a,				     const void **p, unsigned field){	unsigned bytes = BCH_ALLOC_V1_FIELD_BYTES[field];	u64 v; 	if (!(a->fields & (1 << field)))		return 0; 	switch (bytes) {	case 1:		v = *((const u8 *) *p);		break;	case 2:		v = le16_to_cpup(*p);		break;	case 4:		v = le32_to_cpup(*p);		break;	case 8:		v = le64_to_cpup(*p);		break;	default:		BUG();	} 	*p += bytes;	return v;} static void bch2_alloc_unpack_v1(struct bkey_alloc_unpacked *out,				 struct bkey_s_c k){	const struct bch_alloc *in = bkey_s_c_to_alloc(k).v;	const void *d = in->data;	unsigned idx = 0; 	out->gen = in->gen; #define x(_name, _bits) out->_name = alloc_field_v1_get(in, &d, idx++);	BCH_ALLOC_FIELDS_V1()#undef  x} static int bch2_alloc_unpack_v2(struct bkey_alloc_unpacked *out,				struct bkey_s_c k){	struct bkey_s_c_alloc_v2 a = bkey_s_c_to_alloc_v2(k);	const u8 *in = a.v->data;	const u8 *end = bkey_val_end(a);	unsigned fieldnr = 0;	int ret;	u64 v; 	out->gen	= a.v->gen;	out->oldest_gen	= a.v->oldest_gen;	out->data_type	= a.v->data_type; #define x(_name, _bits)							\	if (fieldnr < a.v->nr_fields) {					\		ret = bch2_varint_decode_fast(in, end, &v);		\		if (ret < 0)						\			return ret;					\		in += ret;						\	} else {							\		v = 0;							\	}								\	out->_name = v;							\	if (v != out->_name)						\		return -1;						\	fieldnr++; 	BCH_ALLOC_FIELDS_V2()#undef  x	return 0;} static int bch2_alloc_unpack_v3(struct bkey_alloc_unpacked *out,				struct bkey_s_c k){	struct bkey_s_c_alloc_v3 a = bkey_s_c_to_alloc_v3(k);	const u8 *in = a.v->data;	const u8 *end = bkey_val_end(a);	unsigned fieldnr = 0;	int ret;	u64 v; 	out->gen	= a.v->gen;	out->oldest_gen	= a.v->oldest_gen;	out->data_type	= a.v->data_type;	out->need_discard = BCH_ALLOC_V3_NEED_DISCARD(a.v);	out->need_inc_gen = BCH_ALLOC_V3_NEED_INC_GEN(a.v);	out->journal_seq = le64_to_cpu(a.v->journal_seq); #define x(_name, _bits)							\	if (fieldnr < a.v->nr_fields) {					\		ret = bch2_varint_decode_fast(in, end, &v);		\		if (ret < 0)						\			return ret;					\		in += ret;						\	} else {							\		v = 0;							\	}								\	out->_name = v;							\	if (v != out->_name)						\		return -1;						\	fieldnr++; 	BCH_ALLOC_FIELDS_V2()#undef  x	return 0;} static struct bkey_alloc_unpacked bch2_alloc_unpack(struct bkey_s_c k){	struct bkey_alloc_unpacked ret = { .gen	= 0 }; 	switch (k.k->type) {	case KEY_TYPE_alloc:		bch2_alloc_unpack_v1(&ret, k);		break;	case KEY_TYPE_alloc_v2:		bch2_alloc_unpack_v2(&ret, k);		break;	case KEY_TYPE_alloc_v3:		bch2_alloc_unpack_v3(&ret, k);		break;	} 	return ret;} static unsigned bch_alloc_v1_val_u64s(const struct bch_alloc *a){	unsigned i, bytes = offsetof(struct bch_alloc, data); 	for (i = 0; i < ARRAY_SIZE(BCH_ALLOC_V1_FIELD_BYTES); i++)		if (a->fields & (1 << i))			bytes += BCH_ALLOC_V1_FIELD_BYTES[i]; 	return DIV_ROUND_UP(bytes, sizeof(u64));} int bch2_alloc_v1_invalid(struct bch_fs *c, struct bkey_s_c k,			  enum bkey_invalid_flags flags,			  struct printbuf *err){	struct bkey_s_c_alloc a = bkey_s_c_to_alloc(k);	int ret = 0; 	/* allow for unknown fields */	bkey_fsck_err_on(bkey_val_u64s(a.k) < bch_alloc_v1_val_u64s(a.v), c, err,			 alloc_v1_val_size_bad,			 "incorrect value size (%zu < %u)",			 bkey_val_u64s(a.k), bch_alloc_v1_val_u64s(a.v));fsck_err:	return ret;} int bch2_alloc_v2_invalid(struct bch_fs *c, struct bkey_s_c k,			  enum bkey_invalid_flags flags,			  struct printbuf *err){	struct bkey_alloc_unpacked u;	int ret = 0; 	bkey_fsck_err_on(bch2_alloc_unpack_v2(&u, k), c, err,			 alloc_v2_unpack_error,			 "unpack error");fsck_err:	return ret;} int bch2_alloc_v3_invalid(struct bch_fs *c, struct bkey_s_c k,			  enum bkey_invalid_flags flags,			  struct printbuf *err){	struct bkey_alloc_unpacked u;	int ret = 0; 	bkey_fsck_err_on(bch2_alloc_unpack_v3(&u, k), c, err,			 alloc_v2_unpack_error,			 "unpack error");fsck_err:	return ret;} int bch2_alloc_v4_invalid(struct bch_fs *c, struct bkey_s_c k,			  enum bkey_invalid_flags flags, struct printbuf *err){	struct bkey_s_c_alloc_v4 a = bkey_s_c_to_alloc_v4(k);	int ret = 0; 	bkey_fsck_err_on(alloc_v4_u64s(a.v) > bkey_val_u64s(k.k), c, err,			 alloc_v4_val_size_bad,			 "bad val size (%u > %zu)",			 alloc_v4_u64s(a.v), bkey_val_u64s(k.k)); 	bkey_fsck_err_on(!BCH_ALLOC_V4_BACKPOINTERS_START(a.v) &&			 BCH_ALLOC_V4_NR_BACKPOINTERS(a.v), c, err,			 alloc_v4_backpointers_start_bad,			 "invalid backpointers_start"); 	bkey_fsck_err_on(alloc_data_type(*a.v, a.v->data_type) != a.v->data_type, c, err,			 alloc_key_data_type_bad,			 "invalid data type (got %u should be %u)",			 a.v->data_type, alloc_data_type(*a.v, a.v->data_type)); 	switch (a.v->data_type) {	case BCH_DATA_free:	case BCH_DATA_need_gc_gens:	case BCH_DATA_need_discard:		bkey_fsck_err_on(a.v->dirty_sectors ||				 a.v->cached_sectors ||				 a.v->stripe, c, err,				 alloc_key_empty_but_have_data,				 "empty data type free but have data");		break;	case BCH_DATA_sb:	case BCH_DATA_journal:	case BCH_DATA_btree:	case BCH_DATA_user:	case BCH_DATA_parity:		bkey_fsck_err_on(!a.v->dirty_sectors, c, err,				 alloc_key_dirty_sectors_0,				 "data_type %s but dirty_sectors==0",				 bch2_data_types[a.v->data_type]);		break;	case BCH_DATA_cached:		bkey_fsck_err_on(!a.v->cached_sectors ||				 a.v->dirty_sectors ||				 a.v->stripe, c, err,				 alloc_key_cached_inconsistency,				 "data type inconsistency"); 		bkey_fsck_err_on(!a.v->io_time[READ] &&				 c->curr_recovery_pass > BCH_RECOVERY_PASS_check_alloc_to_lru_refs,				 c, err,				 alloc_key_cached_but_read_time_zero,				 "cached bucket with read_time == 0");		break;	case BCH_DATA_stripe:		break;	}fsck_err:	return ret;} void bch2_alloc_v4_swab(struct bkey_s k){	struct bch_alloc_v4 *a = bkey_s_to_alloc_v4(k).v;	struct bch_backpointer *bp, *bps; 	a->journal_seq		= swab64(a->journal_seq);	a->flags		= swab32(a->flags);	a->dirty_sectors	= swab32(a->dirty_sectors);	a->cached_sectors	= swab32(a->cached_sectors);	a->io_time[0]		= swab64(a->io_time[0]);	a->io_time[1]		= swab64(a->io_time[1]);	a->stripe		= swab32(a->stripe);	a->nr_external_backpointers = swab32(a->nr_external_backpointers);	a->fragmentation_lru	= swab64(a->fragmentation_lru); 	bps = alloc_v4_backpointers(a);	for (bp = bps; bp < bps + BCH_ALLOC_V4_NR_BACKPOINTERS(a); bp++) {		bp->bucket_offset	= swab40(bp->bucket_offset);		bp->bucket_len		= swab32(bp->bucket_len);		bch2_bpos_swab(&bp->pos);	}} void bch2_alloc_to_text(struct printbuf *out, struct bch_fs *c, struct bkey_s_c k){	struct bch_alloc_v4 _a;	const struct bch_alloc_v4 *a = bch2_alloc_to_v4(k, &_a);	unsigned i; 	prt_newline(out);	printbuf_indent_add(out, 2); 	prt_printf(out, "gen %u oldest_gen %u data_type %s",	       a->gen, a->oldest_gen,	       a->data_type < BCH_DATA_NR	       ? bch2_data_types[a->data_type]	       : "(invalid data type)");	prt_newline(out);	prt_printf(out, "journal_seq       %llu",	a->journal_seq);	prt_newline(out);	prt_printf(out, "need_discard      %llu",	BCH_ALLOC_V4_NEED_DISCARD(a));	prt_newline(out);	prt_printf(out, "need_inc_gen      %llu",	BCH_ALLOC_V4_NEED_INC_GEN(a));	prt_newline(out);	prt_printf(out, "dirty_sectors     %u",	a->dirty_sectors);	prt_newline(out);	prt_printf(out, "cached_sectors    %u",	a->cached_sectors);	prt_newline(out);	prt_printf(out, "stripe            %u",	a->stripe);	prt_newline(out);	prt_printf(out, "stripe_redundancy %u",	a->stripe_redundancy);	prt_newline(out);	prt_printf(out, "io_time[READ]     %llu",	a->io_time[READ]);	prt_newline(out);	prt_printf(out, "io_time[WRITE]    %llu",	a->io_time[WRITE]);	prt_newline(out);	prt_printf(out, "fragmentation     %llu",	a->fragmentation_lru);	prt_newline(out);	prt_printf(out, "bp_start          %llu", BCH_ALLOC_V4_BACKPOINTERS_START(a));	prt_newline(out); 	if (BCH_ALLOC_V4_NR_BACKPOINTERS(a)) {		struct bkey_s_c_alloc_v4 a_raw = bkey_s_c_to_alloc_v4(k);		const struct bch_backpointer *bps = alloc_v4_backpointers_c(a_raw.v); 		prt_printf(out, "backpointers:     %llu", BCH_ALLOC_V4_NR_BACKPOINTERS(a_raw.v));		printbuf_indent_add(out, 2); 		for (i = 0; i < BCH_ALLOC_V4_NR_BACKPOINTERS(a_raw.v); i++) {			prt_newline(out);			bch2_backpointer_to_text(out, &bps[i]);		} 		printbuf_indent_sub(out, 2);	} 	printbuf_indent_sub(out, 2);} void __bch2_alloc_to_v4(struct bkey_s_c k, struct bch_alloc_v4 *out){	if (k.k->type == KEY_TYPE_alloc_v4) {		void *src, *dst; 		*out = *bkey_s_c_to_alloc_v4(k).v; 		src = alloc_v4_backpointers(out);		SET_BCH_ALLOC_V4_BACKPOINTERS_START(out, BCH_ALLOC_V4_U64s);		dst = alloc_v4_backpointers(out); 		if (src < dst)			memset(src, 0, dst - src); 		SET_BCH_ALLOC_V4_NR_BACKPOINTERS(out, 0);	} else {		struct bkey_alloc_unpacked u = bch2_alloc_unpack(k); 		*out = (struct bch_alloc_v4) {			.journal_seq		= u.journal_seq,			.flags			= u.need_discard,			.gen			= u.gen,			.oldest_gen		= u.oldest_gen,			.data_type		= u.data_type,			.stripe_redundancy	= u.stripe_redundancy,			.dirty_sectors		= u.dirty_sectors,			.cached_sectors		= u.cached_sectors,			.io_time[READ]		= u.read_time,			.io_time[WRITE]		= u.write_time,			.stripe			= u.stripe,		}; 		SET_BCH_ALLOC_V4_BACKPOINTERS_START(out, BCH_ALLOC_V4_U64s);	}} static noinline struct bkey_i_alloc_v4 *__bch2_alloc_to_v4_mut(struct btree_trans *trans, struct bkey_s_c k){	struct bkey_i_alloc_v4 *ret; 	ret = bch2_trans_kmalloc(trans, max(bkey_bytes(k.k), sizeof(struct bkey_i_alloc_v4)));	if (IS_ERR(ret))		return ret; 	if (k.k->type == KEY_TYPE_alloc_v4) {		void *src, *dst; 		bkey_reassemble(&ret->k_i, k); 		src = alloc_v4_backpointers(&ret->v);		SET_BCH_ALLOC_V4_BACKPOINTERS_START(&ret->v, BCH_ALLOC_V4_U64s);		dst = alloc_v4_backpointers(&ret->v); 		if (src < dst)			memset(src, 0, dst - src); 		SET_BCH_ALLOC_V4_NR_BACKPOINTERS(&ret->v, 0);		set_alloc_v4_u64s(ret);	} else {		bkey_alloc_v4_init(&ret->k_i);		ret->k.p = k.k->p;		bch2_alloc_to_v4(k, &ret->v);	}	return ret;} static inline struct bkey_i_alloc_v4 *bch2_alloc_to_v4_mut_inlined(struct btree_trans *trans, struct bkey_s_c k){	struct bkey_s_c_alloc_v4 a; 	if (likely(k.k->type == KEY_TYPE_alloc_v4) &&	    ((a = bkey_s_c_to_alloc_v4(k), true) &&	     BCH_ALLOC_V4_NR_BACKPOINTERS(a.v) == 0))		return bch2_bkey_make_mut_noupdate_typed(trans, k, alloc_v4); 	return __bch2_alloc_to_v4_mut(trans, k);} struct bkey_i_alloc_v4 *bch2_alloc_to_v4_mut(struct btree_trans *trans, struct bkey_s_c k){	return bch2_alloc_to_v4_mut_inlined(trans, k);} struct bkey_i_alloc_v4 *bch2_trans_start_alloc_update(struct btree_trans *trans, struct btree_iter *iter,			      struct bpos pos){	struct bkey_s_c k;	struct bkey_i_alloc_v4 *a;	int ret; 	k = bch2_bkey_get_iter(trans, iter, BTREE_ID_alloc, pos,			     BTREE_ITER_WITH_UPDATES|			     BTREE_ITER_CACHED|			     BTREE_ITER_INTENT);	ret = bkey_err(k);	if (unlikely(ret))		return ERR_PTR(ret); 	a = bch2_alloc_to_v4_mut_inlined(trans, k);	ret = PTR_ERR_OR_ZERO(a);	if (unlikely(ret))		goto err;	return a;err:	bch2_trans_iter_exit(trans, iter);	return ERR_PTR(ret);} static struct bpos alloc_gens_pos(struct bpos pos, unsigned *offset){	*offset = pos.offset & KEY_TYPE_BUCKET_GENS_MASK; 	pos.offset >>= KEY_TYPE_BUCKET_GENS_BITS;	return pos;} static struct bpos bucket_gens_pos_to_alloc(struct bpos pos, unsigned offset){	pos.offset <<= KEY_TYPE_BUCKET_GENS_BITS;	pos.offset += offset;

Lines 1–500 of 2159.