mirror of
https://github.com/torvalds/linux.git
synced 2025-11-02 09:40:27 +02:00
bcachefs: BCH_RECOVERY_PASS_NO_RATELIMIT
Add a superblock flag to temporarily disable ratelimiting for a recovery pass. This will be used to make check_key_has_snapshot safer: we don't want to delete a key for a missing snapshot unless we know that the snapshots and subvolumes btrees are consistent, i.e. check_snapshots and check_subvols have run recently. Changing those btrees - creating/deleting a subvolume or snapshot - will set the "disable ratelimit" flag, i.e. ensuring that those passes run if check_key_has_snapshot discovers an error. We're only disabling ratelimiting in the snapshot/subvol delete paths, we're not so concerned about the create paths. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
a2ffab0e65
commit
0942b852d4
5 changed files with 53 additions and 13 deletions
|
|
@ -103,20 +103,20 @@ static void bch2_sb_recovery_passes_to_text(struct printbuf *out,
|
||||||
prt_tab(out);
|
prt_tab(out);
|
||||||
|
|
||||||
bch2_pr_time_units(out, le32_to_cpu(i->last_runtime) * NSEC_PER_SEC);
|
bch2_pr_time_units(out, le32_to_cpu(i->last_runtime) * NSEC_PER_SEC);
|
||||||
|
|
||||||
|
if (BCH_RECOVERY_PASS_NO_RATELIMIT(i))
|
||||||
|
prt_str(out, " (no ratelimit)");
|
||||||
|
|
||||||
prt_newline(out);
|
prt_newline(out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bch2_sb_recovery_pass_complete(struct bch_fs *c,
|
static struct recovery_pass_entry *bch2_sb_recovery_pass_entry(struct bch_fs *c,
|
||||||
enum bch_recovery_pass pass,
|
enum bch_recovery_pass pass)
|
||||||
s64 start_time)
|
|
||||||
{
|
{
|
||||||
enum bch_recovery_pass_stable stable = bch2_recovery_pass_to_stable(pass);
|
enum bch_recovery_pass_stable stable = bch2_recovery_pass_to_stable(pass);
|
||||||
s64 end_time = ktime_get_real_seconds();
|
|
||||||
|
|
||||||
mutex_lock(&c->sb_lock);
|
lockdep_assert_held(&c->sb_lock);
|
||||||
struct bch_sb_field_ext *ext = bch2_sb_field_get(c->disk_sb.sb, ext);
|
|
||||||
__clear_bit_le64(stable, ext->recovery_passes_required);
|
|
||||||
|
|
||||||
struct bch_sb_field_recovery_passes *r =
|
struct bch_sb_field_recovery_passes *r =
|
||||||
bch2_sb_field_get(c->disk_sb.sb, recovery_passes);
|
bch2_sb_field_get(c->disk_sb.sb, recovery_passes);
|
||||||
|
|
@ -127,15 +127,43 @@ static void bch2_sb_recovery_pass_complete(struct bch_fs *c,
|
||||||
r = bch2_sb_field_resize(&c->disk_sb, recovery_passes, u64s);
|
r = bch2_sb_field_resize(&c->disk_sb, recovery_passes, u64s);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
bch_err(c, "error creating recovery_passes sb section");
|
bch_err(c, "error creating recovery_passes sb section");
|
||||||
goto out;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r->start[stable].last_run = cpu_to_le64(end_time);
|
return r->start + stable;
|
||||||
r->start[stable].last_runtime = cpu_to_le32(max(0, end_time - start_time));
|
}
|
||||||
out:
|
|
||||||
|
static void bch2_sb_recovery_pass_complete(struct bch_fs *c,
|
||||||
|
enum bch_recovery_pass pass,
|
||||||
|
s64 start_time)
|
||||||
|
{
|
||||||
|
guard(mutex)(&c->sb_lock);
|
||||||
|
struct bch_sb_field_ext *ext = bch2_sb_field_get(c->disk_sb.sb, ext);
|
||||||
|
__clear_bit_le64(bch2_recovery_pass_to_stable(pass),
|
||||||
|
ext->recovery_passes_required);
|
||||||
|
|
||||||
|
struct recovery_pass_entry *e = bch2_sb_recovery_pass_entry(c, pass);
|
||||||
|
if (e) {
|
||||||
|
s64 end_time = ktime_get_real_seconds();
|
||||||
|
e->last_run = cpu_to_le64(end_time);
|
||||||
|
e->last_runtime = cpu_to_le32(max(0, end_time - start_time));
|
||||||
|
SET_BCH_RECOVERY_PASS_NO_RATELIMIT(e, false);
|
||||||
|
}
|
||||||
|
|
||||||
bch2_write_super(c);
|
bch2_write_super(c);
|
||||||
mutex_unlock(&c->sb_lock);
|
}
|
||||||
|
|
||||||
|
void bch2_recovery_pass_set_no_ratelimit(struct bch_fs *c,
|
||||||
|
enum bch_recovery_pass pass)
|
||||||
|
{
|
||||||
|
guard(mutex)(&c->sb_lock);
|
||||||
|
|
||||||
|
struct recovery_pass_entry *e = bch2_sb_recovery_pass_entry(c, pass);
|
||||||
|
if (e && !BCH_RECOVERY_PASS_NO_RATELIMIT(e)) {
|
||||||
|
SET_BCH_RECOVERY_PASS_NO_RATELIMIT(e, false);
|
||||||
|
bch2_write_super(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bch2_recovery_pass_want_ratelimit(struct bch_fs *c, enum bch_recovery_pass pass)
|
static bool bch2_recovery_pass_want_ratelimit(struct bch_fs *c, enum bch_recovery_pass pass)
|
||||||
|
|
@ -157,6 +185,9 @@ static bool bch2_recovery_pass_want_ratelimit(struct bch_fs *c, enum bch_recover
|
||||||
*/
|
*/
|
||||||
ret = (u64) le32_to_cpu(i->last_runtime) * 100 >
|
ret = (u64) le32_to_cpu(i->last_runtime) * 100 >
|
||||||
ktime_get_real_seconds() - le64_to_cpu(i->last_run);
|
ktime_get_real_seconds() - le64_to_cpu(i->last_run);
|
||||||
|
|
||||||
|
if (BCH_RECOVERY_PASS_NO_RATELIMIT(i))
|
||||||
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ u64 bch2_recovery_passes_from_stable(u64 v);
|
||||||
|
|
||||||
u64 bch2_fsck_recovery_passes(void);
|
u64 bch2_fsck_recovery_passes(void);
|
||||||
|
|
||||||
|
void bch2_recovery_pass_set_no_ratelimit(struct bch_fs *, enum bch_recovery_pass);
|
||||||
|
|
||||||
enum bch_run_recovery_pass_flags {
|
enum bch_run_recovery_pass_flags {
|
||||||
RUN_RECOVERY_PASS_nopersistent = BIT(0),
|
RUN_RECOVERY_PASS_nopersistent = BIT(0),
|
||||||
RUN_RECOVERY_PASS_ratelimit = BIT(1),
|
RUN_RECOVERY_PASS_ratelimit = BIT(1),
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,8 @@ struct recovery_pass_entry {
|
||||||
__le32 flags;
|
__le32 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LE32_BITMASK(BCH_RECOVERY_PASS_NO_RATELIMIT, struct recovery_pass_entry, flags, 0, 1)
|
||||||
|
|
||||||
struct bch_sb_field_recovery_passes {
|
struct bch_sb_field_recovery_passes {
|
||||||
struct bch_sb_field field;
|
struct bch_sb_field field;
|
||||||
struct recovery_pass_entry start[];
|
struct recovery_pass_entry start[];
|
||||||
|
|
|
||||||
|
|
@ -1878,6 +1878,8 @@ int __bch2_delete_dead_snapshots(struct bch_fs *c)
|
||||||
d->running = false;
|
d->running = false;
|
||||||
mutex_unlock(&d->progress_lock);
|
mutex_unlock(&d->progress_lock);
|
||||||
bch2_trans_put(trans);
|
bch2_trans_put(trans);
|
||||||
|
|
||||||
|
bch2_recovery_pass_set_no_ratelimit(c, BCH_RECOVERY_PASS_check_snapshots);
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&d->lock);
|
mutex_unlock(&d->lock);
|
||||||
if (!bch2_err_matches(ret, EROFS))
|
if (!bch2_err_matches(ret, EROFS))
|
||||||
|
|
|
||||||
|
|
@ -482,9 +482,12 @@ static int __bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
|
||||||
|
|
||||||
static int bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
|
static int bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
|
||||||
{
|
{
|
||||||
return bch2_subvolumes_reparent(trans, subvolid) ?:
|
int ret = bch2_subvolumes_reparent(trans, subvolid) ?:
|
||||||
commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
|
commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
|
||||||
__bch2_subvolume_delete(trans, subvolid));
|
__bch2_subvolume_delete(trans, subvolid));
|
||||||
|
|
||||||
|
bch2_recovery_pass_set_no_ratelimit(trans->c, BCH_RECOVERY_PASS_check_subvols);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
|
static void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue