bcachefs: reserve space in journal for fs usage entries
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
24547d097a
commit
2c5af169f7
@ -545,6 +545,8 @@ struct bch_fs {
|
|||||||
struct bch_replicas_cpu replicas_gc;
|
struct bch_replicas_cpu replicas_gc;
|
||||||
struct mutex replicas_gc_lock;
|
struct mutex replicas_gc_lock;
|
||||||
|
|
||||||
|
struct journal_entry_res replicas_journal_res;
|
||||||
|
|
||||||
struct bch_disk_groups_cpu __rcu *disk_groups;
|
struct bch_disk_groups_cpu __rcu *disk_groups;
|
||||||
|
|
||||||
struct bch_opts opts;
|
struct bch_opts opts;
|
||||||
|
@ -1362,7 +1362,8 @@ static inline __u64 __bset_magic(struct bch_sb *sb)
|
|||||||
x(btree_root, 1) \
|
x(btree_root, 1) \
|
||||||
x(prio_ptrs, 2) \
|
x(prio_ptrs, 2) \
|
||||||
x(blacklist, 3) \
|
x(blacklist, 3) \
|
||||||
x(blacklist_v2, 4)
|
x(blacklist_v2, 4) \
|
||||||
|
x(usage, 5)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
#define x(f, nr) BCH_JSET_ENTRY_##f = nr,
|
#define x(f, nr) BCH_JSET_ENTRY_##f = nr,
|
||||||
@ -1392,6 +1393,20 @@ struct jset_entry_blacklist_v2 {
|
|||||||
__le64 end;
|
__le64 end;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FS_USAGE_REPLICAS = 0,
|
||||||
|
FS_USAGE_INODES = 1,
|
||||||
|
FS_USAGE_KEY_VERSION = 2,
|
||||||
|
FS_USAGE_NR = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jset_entry_usage {
|
||||||
|
struct jset_entry entry;
|
||||||
|
__le64 sectors;
|
||||||
|
__u8 type;
|
||||||
|
struct bch_replicas_entry r;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On disk format for a journal entry:
|
* On disk format for a journal entry:
|
||||||
* seq is monotonically increasing; every journal entry has its own unique
|
* seq is monotonically increasing; every journal entry has its own unique
|
||||||
|
@ -284,6 +284,7 @@ static int journal_entry_validate_blacklist_v2(struct bch_fs *c,
|
|||||||
if (journal_entry_err_on(le16_to_cpu(entry->u64s) != 2, c,
|
if (journal_entry_err_on(le16_to_cpu(entry->u64s) != 2, c,
|
||||||
"invalid journal seq blacklist entry: bad size")) {
|
"invalid journal seq blacklist entry: bad size")) {
|
||||||
journal_entry_null_range(entry, vstruct_next(entry));
|
journal_entry_null_range(entry, vstruct_next(entry));
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bl_entry = container_of(entry, struct jset_entry_blacklist_v2, entry);
|
bl_entry = container_of(entry, struct jset_entry_blacklist_v2, entry);
|
||||||
@ -293,6 +294,28 @@ static int journal_entry_validate_blacklist_v2(struct bch_fs *c,
|
|||||||
"invalid journal seq blacklist entry: start > end")) {
|
"invalid journal seq blacklist entry: start > end")) {
|
||||||
journal_entry_null_range(entry, vstruct_next(entry));
|
journal_entry_null_range(entry, vstruct_next(entry));
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
|
fsck_err:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int journal_entry_validate_usage(struct bch_fs *c,
|
||||||
|
struct jset *jset,
|
||||||
|
struct jset_entry *entry,
|
||||||
|
int write)
|
||||||
|
{
|
||||||
|
struct jset_entry_usage *u =
|
||||||
|
container_of(entry, struct jset_entry_usage, entry);
|
||||||
|
unsigned bytes = jset_u64s(le16_to_cpu(entry->u64s)) * sizeof(u64);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (journal_entry_err_on(bytes < sizeof(*u) ||
|
||||||
|
bytes < sizeof(*u) + u->r.nr_devs,
|
||||||
|
c,
|
||||||
|
"invalid journal entry usage: bad size")) {
|
||||||
|
journal_entry_null_range(entry, vstruct_next(entry));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
@ -315,18 +338,10 @@ static const struct jset_entry_ops bch2_jset_entry_ops[] = {
|
|||||||
static int journal_entry_validate(struct bch_fs *c, struct jset *jset,
|
static int journal_entry_validate(struct bch_fs *c, struct jset *jset,
|
||||||
struct jset_entry *entry, int write)
|
struct jset_entry *entry, int write)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
return entry->type < BCH_JSET_ENTRY_NR
|
||||||
|
? bch2_jset_entry_ops[entry->type].validate(c, jset,
|
||||||
if (entry->type >= BCH_JSET_ENTRY_NR) {
|
entry, write)
|
||||||
journal_entry_err(c, "invalid journal entry type %u",
|
: 0;
|
||||||
entry->type);
|
|
||||||
journal_entry_null_range(entry, vstruct_next(entry));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = bch2_jset_entry_ops[entry->type].validate(c, jset, entry, write);
|
|
||||||
fsck_err:
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jset_validate_entries(struct bch_fs *c, struct jset *jset,
|
static int jset_validate_entries(struct bch_fs *c, struct jset *jset,
|
||||||
|
@ -108,7 +108,8 @@ static bool journal_empty(struct list_head *journal)
|
|||||||
|
|
||||||
list_for_each_entry(i, journal, list) {
|
list_for_each_entry(i, journal, list) {
|
||||||
vstruct_for_each(&i->j, entry) {
|
vstruct_for_each(&i->j, entry) {
|
||||||
if (entry->type == BCH_JSET_ENTRY_btree_root)
|
if (entry->type == BCH_JSET_ENTRY_btree_root ||
|
||||||
|
entry->type == BCH_JSET_ENTRY_usage)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (entry->type == BCH_JSET_ENTRY_btree_keys &&
|
if (entry->type == BCH_JSET_ENTRY_btree_keys &&
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
#include "bcachefs.h"
|
#include "bcachefs.h"
|
||||||
|
#include "journal.h"
|
||||||
#include "replicas.h"
|
#include "replicas.h"
|
||||||
#include "super-io.h"
|
#include "super-io.h"
|
||||||
|
|
||||||
@ -302,6 +303,27 @@ err:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned reserve_journal_replicas(struct bch_fs *c,
|
||||||
|
struct bch_replicas_cpu *r)
|
||||||
|
{
|
||||||
|
struct bch_replicas_entry *e;
|
||||||
|
unsigned journal_res_u64s = 0;
|
||||||
|
|
||||||
|
/* nr_inodes: */
|
||||||
|
journal_res_u64s +=
|
||||||
|
DIV_ROUND_UP(sizeof(struct jset_entry_usage), sizeof(u64));
|
||||||
|
|
||||||
|
/* key_version: */
|
||||||
|
journal_res_u64s +=
|
||||||
|
DIV_ROUND_UP(sizeof(struct jset_entry_usage), sizeof(u64));
|
||||||
|
|
||||||
|
for_each_cpu_replicas_entry(r, e)
|
||||||
|
journal_res_u64s +=
|
||||||
|
DIV_ROUND_UP(sizeof(struct jset_entry_usage) +
|
||||||
|
e->nr_devs, sizeof(u64));
|
||||||
|
return journal_res_u64s;
|
||||||
|
}
|
||||||
|
|
||||||
noinline
|
noinline
|
||||||
static int bch2_mark_replicas_slowpath(struct bch_fs *c,
|
static int bch2_mark_replicas_slowpath(struct bch_fs *c,
|
||||||
struct bch_replicas_entry *new_entry)
|
struct bch_replicas_entry *new_entry)
|
||||||
@ -329,6 +351,10 @@ static int bch2_mark_replicas_slowpath(struct bch_fs *c,
|
|||||||
ret = bch2_cpu_replicas_to_sb_replicas(c, &new_r);
|
ret = bch2_cpu_replicas_to_sb_replicas(c, &new_r);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
bch2_journal_entry_res_resize(&c->journal,
|
||||||
|
&c->replicas_journal_res,
|
||||||
|
reserve_journal_replicas(c, &new_r));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!new_r.entries &&
|
if (!new_r.entries &&
|
||||||
@ -595,6 +621,7 @@ int bch2_sb_replicas_to_cpu_replicas(struct bch_fs *c)
|
|||||||
bch2_cpu_replicas_sort(&new_r);
|
bch2_cpu_replicas_sort(&new_r);
|
||||||
|
|
||||||
percpu_down_write(&c->mark_lock);
|
percpu_down_write(&c->mark_lock);
|
||||||
|
|
||||||
ret = replicas_table_update(c, &new_r);
|
ret = replicas_table_update(c, &new_r);
|
||||||
percpu_up_write(&c->mark_lock);
|
percpu_up_write(&c->mark_lock);
|
||||||
|
|
||||||
@ -915,3 +942,10 @@ unsigned bch2_dev_has_data(struct bch_fs *c, struct bch_dev *ca)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bch2_fs_replicas_init(struct bch_fs *c)
|
||||||
|
{
|
||||||
|
c->journal.entry_u64s_reserved +=
|
||||||
|
reserve_journal_replicas(c, &c->replicas);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -80,4 +80,6 @@ int bch2_sb_replicas_to_cpu_replicas(struct bch_fs *);
|
|||||||
extern const struct bch_sb_field_ops bch_sb_field_ops_replicas;
|
extern const struct bch_sb_field_ops bch_sb_field_ops_replicas;
|
||||||
extern const struct bch_sb_field_ops bch_sb_field_ops_replicas_v0;
|
extern const struct bch_sb_field_ops bch_sb_field_ops_replicas_v0;
|
||||||
|
|
||||||
|
int bch2_fs_replicas_init(struct bch_fs *);
|
||||||
|
|
||||||
#endif /* _BCACHEFS_REPLICAS_H */
|
#endif /* _BCACHEFS_REPLICAS_H */
|
||||||
|
@ -658,6 +658,7 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
|
|||||||
bch2_io_clock_init(&c->io_clock[READ]) ||
|
bch2_io_clock_init(&c->io_clock[READ]) ||
|
||||||
bch2_io_clock_init(&c->io_clock[WRITE]) ||
|
bch2_io_clock_init(&c->io_clock[WRITE]) ||
|
||||||
bch2_fs_journal_init(&c->journal) ||
|
bch2_fs_journal_init(&c->journal) ||
|
||||||
|
bch2_fs_replicas_init(c) ||
|
||||||
bch2_fs_btree_cache_init(c) ||
|
bch2_fs_btree_cache_init(c) ||
|
||||||
bch2_fs_io_init(c) ||
|
bch2_fs_io_init(c) ||
|
||||||
bch2_fs_encryption_init(c) ||
|
bch2_fs_encryption_init(c) ||
|
||||||
|
Loading…
Reference in New Issue
Block a user