Update bcachefs sources to c887148ebf99 thread_with_file: add f_ops.flush

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2024-02-20 16:28:18 -05:00
parent 6ff5313cbe
commit e5b2870d05
17 changed files with 370 additions and 71 deletions

View File

@ -1 +1 @@
9a555a741e807275c320807babd3f42efb8fee90 c887148ebf9989ce8bdf6f814d4342ba5bf465fa

View File

@ -29,6 +29,8 @@
#include <linux/sched/task.h> #include <linux/sched/task.h>
#include <linux/sort.h> #include <linux/sort.h>
static void bch2_discard_one_bucket_fast(struct bch_fs *c, struct bpos bucket);
/* Persistent alloc info: */ /* Persistent alloc info: */
static const unsigned BCH_ALLOC_V1_FIELD_BYTES[] = { static const unsigned BCH_ALLOC_V1_FIELD_BYTES[] = {
@ -866,14 +868,14 @@ int bch2_trigger_alloc(struct btree_trans *trans,
#define statechange(expr) !eval_state(old_a, expr) && eval_state(new_a, expr) #define statechange(expr) !eval_state(old_a, expr) && eval_state(new_a, expr)
#define bucket_flushed(a) (!a->journal_seq || a->journal_seq <= c->journal.flushed_seq_ondisk) #define bucket_flushed(a) (!a->journal_seq || a->journal_seq <= c->journal.flushed_seq_ondisk)
if (statechange(a->data_type == BCH_DATA_free && if (statechange(a->data_type == BCH_DATA_free) &&
bucket_flushed(a))) bucket_flushed(new_a))
closure_wake_up(&c->freelist_wait); closure_wake_up(&c->freelist_wait);
if (statechange(a->data_type == BCH_DATA_need_discard && if (statechange(a->data_type == BCH_DATA_need_discard) &&
bucket_flushed(a)) && !bch2_bucket_is_open(c, new.k->p.inode, new.k->p.offset) &&
!bch2_bucket_is_open(c, new.k->p.inode, new.k->p.offset)) bucket_flushed(new_a))
bch2_do_discards(c); bch2_discard_one_bucket_fast(c, new.k->p);
if (statechange(a->data_type == BCH_DATA_cached) && if (statechange(a->data_type == BCH_DATA_cached) &&
!bch2_bucket_is_open(c, new.k->p.inode, new.k->p.offset) && !bch2_bucket_is_open(c, new.k->p.inode, new.k->p.offset) &&
@ -1609,6 +1611,36 @@ int bch2_check_alloc_to_lru_refs(struct bch_fs *c)
return ret; return ret;
} }
static int discard_in_flight_add(struct bch_fs *c, struct bpos bucket)
{
int ret;
mutex_lock(&c->discard_buckets_in_flight_lock);
darray_for_each(c->discard_buckets_in_flight, i)
if (bkey_eq(*i, bucket)) {
ret = -EEXIST;
goto out;
}
ret = darray_push(&c->discard_buckets_in_flight, bucket);
out:
mutex_unlock(&c->discard_buckets_in_flight_lock);
return ret;
}
static void discard_in_flight_remove(struct bch_fs *c, struct bpos bucket)
{
mutex_lock(&c->discard_buckets_in_flight_lock);
darray_for_each(c->discard_buckets_in_flight, i)
if (bkey_eq(*i, bucket)) {
darray_remove_item(&c->discard_buckets_in_flight, i);
goto found;
}
BUG();
found:
mutex_unlock(&c->discard_buckets_in_flight_lock);
}
struct discard_buckets_state { struct discard_buckets_state {
u64 seen; u64 seen;
u64 open; u64 open;
@ -1647,6 +1679,7 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
struct bch_dev *ca; struct bch_dev *ca;
struct bkey_i_alloc_v4 *a; struct bkey_i_alloc_v4 *a;
struct printbuf buf = PRINTBUF; struct printbuf buf = PRINTBUF;
bool discard_locked = false;
int ret = 0; int ret = 0;
ca = bch_dev_bkey_exists(c, pos.inode); ca = bch_dev_bkey_exists(c, pos.inode);
@ -1714,6 +1747,11 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
goto out; goto out;
} }
if (discard_in_flight_add(c, SPOS(iter.pos.inode, iter.pos.offset, true)))
goto out;
discard_locked = true;
if (!bkey_eq(*discard_pos_done, iter.pos) && if (!bkey_eq(*discard_pos_done, iter.pos) &&
ca->mi.discard && !c->opts.nochanges) { ca->mi.discard && !c->opts.nochanges) {
/* /*
@ -1745,6 +1783,8 @@ write:
count_event(c, bucket_discard); count_event(c, bucket_discard);
s->discarded++; s->discarded++;
out: out:
if (discard_locked)
discard_in_flight_remove(c, iter.pos);
s->seen++; s->seen++;
bch2_trans_iter_exit(trans, &iter); bch2_trans_iter_exit(trans, &iter);
percpu_ref_put(&ca->io_ref); percpu_ref_put(&ca->io_ref);
@ -1784,6 +1824,92 @@ void bch2_do_discards(struct bch_fs *c)
bch2_write_ref_put(c, BCH_WRITE_REF_discard); bch2_write_ref_put(c, BCH_WRITE_REF_discard);
} }
static int bch2_clear_bucket_needs_discard(struct btree_trans *trans, struct bpos bucket)
{
struct btree_iter iter;
bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc, bucket, BTREE_ITER_INTENT);
struct bkey_s_c k = bch2_btree_iter_peek_slot(&iter);
int ret = bkey_err(k);
if (ret)
goto err;
struct bkey_i_alloc_v4 *a = bch2_alloc_to_v4_mut(trans, k);
ret = PTR_ERR_OR_ZERO(a);
if (ret)
goto err;
SET_BCH_ALLOC_V4_NEED_DISCARD(&a->v, false);
a->v.data_type = alloc_data_type(a->v, a->v.data_type);
ret = bch2_trans_update(trans, &iter, &a->k_i, 0);
err:
bch2_trans_iter_exit(trans, &iter);
return ret;
}
static void bch2_do_discards_fast_work(struct work_struct *work)
{
struct bch_fs *c = container_of(work, struct bch_fs, discard_fast_work);
while (1) {
bool got_bucket = false;
struct bpos bucket;
struct bch_dev *ca;
mutex_lock(&c->discard_buckets_in_flight_lock);
darray_for_each(c->discard_buckets_in_flight, i) {
if (i->snapshot)
continue;
ca = bch_dev_bkey_exists(c, i->inode);
if (!percpu_ref_tryget(&ca->io_ref)) {
darray_remove_item(&c->discard_buckets_in_flight, i);
continue;
}
got_bucket = true;
bucket = *i;
i->snapshot = true;
break;
}
mutex_unlock(&c->discard_buckets_in_flight_lock);
if (!got_bucket)
break;
blkdev_issue_discard(ca->disk_sb.bdev,
bucket.offset * ca->mi.bucket_size,
ca->mi.bucket_size,
GFP_KERNEL);
int ret = bch2_trans_do(c, NULL, NULL,
BCH_WATERMARK_btree|
BCH_TRANS_COMMIT_no_enospc,
bch2_clear_bucket_needs_discard(trans, bucket));
bch_err_fn(c, ret);
percpu_ref_put(&ca->io_ref);
discard_in_flight_remove(c, bucket);
if (ret)
break;
}
bch2_write_ref_put(c, BCH_WRITE_REF_discard_fast);
}
static void bch2_discard_one_bucket_fast(struct bch_fs *c, struct bpos bucket)
{
struct bch_dev *ca = bch_dev_bkey_exists(c, bucket.inode);
if (!percpu_ref_is_dying(&ca->io_ref) &&
!discard_in_flight_add(c, bucket) &&
bch2_write_ref_tryget(c, BCH_WRITE_REF_discard_fast) &&
!queue_work(c->write_ref_wq, &c->discard_fast_work))
bch2_write_ref_put(c, BCH_WRITE_REF_discard_fast);
}
static int invalidate_one_bucket(struct btree_trans *trans, static int invalidate_one_bucket(struct btree_trans *trans,
struct btree_iter *lru_iter, struct btree_iter *lru_iter,
struct bkey_s_c lru_k, struct bkey_s_c lru_k,
@ -2215,9 +2341,16 @@ void bch2_dev_allocator_add(struct bch_fs *c, struct bch_dev *ca)
set_bit(ca->dev_idx, c->rw_devs[i].d); set_bit(ca->dev_idx, c->rw_devs[i].d);
} }
void bch2_fs_allocator_background_exit(struct bch_fs *c)
{
darray_exit(&c->discard_buckets_in_flight);
}
void bch2_fs_allocator_background_init(struct bch_fs *c) void bch2_fs_allocator_background_init(struct bch_fs *c)
{ {
spin_lock_init(&c->freelist_lock); spin_lock_init(&c->freelist_lock);
mutex_init(&c->discard_buckets_in_flight_lock);
INIT_WORK(&c->discard_work, bch2_do_discards_work); INIT_WORK(&c->discard_work, bch2_do_discards_work);
INIT_WORK(&c->discard_fast_work, bch2_do_discards_fast_work);
INIT_WORK(&c->invalidate_work, bch2_do_invalidates_work); INIT_WORK(&c->invalidate_work, bch2_do_invalidates_work);
} }

View File

@ -269,6 +269,7 @@ u64 bch2_min_rw_member_capacity(struct bch_fs *);
void bch2_dev_allocator_remove(struct bch_fs *, struct bch_dev *); void bch2_dev_allocator_remove(struct bch_fs *, struct bch_dev *);
void bch2_dev_allocator_add(struct bch_fs *, struct bch_dev *); void bch2_dev_allocator_add(struct bch_fs *, struct bch_dev *);
void bch2_fs_allocator_background_exit(struct bch_fs *);
void bch2_fs_allocator_background_init(struct bch_fs *); void bch2_fs_allocator_background_init(struct bch_fs *);
#endif /* _BCACHEFS_ALLOC_BACKGROUND_H */ #endif /* _BCACHEFS_ALLOC_BACKGROUND_H */

View File

@ -708,6 +708,7 @@ struct btree_trans_buf {
x(reflink) \ x(reflink) \
x(fallocate) \ x(fallocate) \
x(discard) \ x(discard) \
x(discard_fast) \
x(invalidate) \ x(invalidate) \
x(delete_dead_snapshots) \ x(delete_dead_snapshots) \
x(snapshot_delete_pagecache) \ x(snapshot_delete_pagecache) \
@ -943,8 +944,11 @@ struct bch_fs {
unsigned write_points_nr; unsigned write_points_nr;
struct buckets_waiting_for_journal buckets_waiting_for_journal; struct buckets_waiting_for_journal buckets_waiting_for_journal;
struct work_struct discard_work;
struct work_struct invalidate_work; struct work_struct invalidate_work;
struct work_struct discard_work;
struct mutex discard_buckets_in_flight_lock;
DARRAY(struct bpos) discard_buckets_in_flight;
struct work_struct discard_fast_work;
/* GARBAGE COLLECTION */ /* GARBAGE COLLECTION */
struct task_struct *gc_thread; struct task_struct *gc_thread;

View File

@ -189,7 +189,11 @@ struct bversion {
__u32 hi; __u32 hi;
__u64 lo; __u64 lo;
#endif #endif
} __packed __aligned(4); } __packed
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
__aligned(4)
#endif
;
struct bkey { struct bkey {
/* Size of combined key and value, in u64s */ /* Size of combined key and value, in u64s */

View File

@ -747,7 +747,8 @@ void bch2_trans_downgrade(struct btree_trans *trans)
return; return;
trans_for_each_path(trans, path, i) trans_for_each_path(trans, path, i)
bch2_btree_path_downgrade(trans, path); if (path->ref)
bch2_btree_path_downgrade(trans, path);
} }
int bch2_trans_relock(struct btree_trans *trans) int bch2_trans_relock(struct btree_trans *trans)

View File

@ -590,7 +590,9 @@ static int bch2_journal_keys_to_write_buffer(struct bch_fs *c, struct journal_bu
entry->type = BCH_JSET_ENTRY_btree_keys; entry->type = BCH_JSET_ENTRY_btree_keys;
} }
spin_lock(&c->journal.lock);
buf->need_flush_to_write_buffer = false; buf->need_flush_to_write_buffer = false;
spin_unlock(&c->journal.lock);
out: out:
bch2_journal_keys_to_write_buffer_end(c, &dst); bch2_journal_keys_to_write_buffer_end(c, &dst);
return ret; return ret;

View File

@ -155,14 +155,28 @@ static void bch2_fsck_thread_exit(struct thread_with_stdio *_thr)
kfree(thr); kfree(thr);
} }
static void bch2_fsck_offline_thread_fn(struct thread_with_stdio *stdio) static int bch2_fsck_offline_thread_fn(struct thread_with_stdio *stdio)
{ {
struct fsck_thread *thr = container_of(stdio, struct fsck_thread, thr); struct fsck_thread *thr = container_of(stdio, struct fsck_thread, thr);
struct bch_fs *c = bch2_fs_open(thr->devs, thr->nr_devs, thr->opts); struct bch_fs *c = bch2_fs_open(thr->devs, thr->nr_devs, thr->opts);
thr->thr.thr.ret = PTR_ERR_OR_ZERO(c); if (IS_ERR(c))
if (!thr->thr.thr.ret) return PTR_ERR(c);
bch2_fs_stop(c);
int ret = 0;
if (test_bit(BCH_FS_errors_fixed, &c->flags))
ret |= 1;
if (test_bit(BCH_FS_error, &c->flags))
ret |= 4;
bch2_fs_stop(c);
if (ret & 1)
stdio_redirect_printf(&stdio->stdio, false, "%s: errors fixed\n", c->name);
if (ret & 4)
stdio_redirect_printf(&stdio->stdio, false, "%s: still has errors\n", c->name);
return ret;
} }
static const struct thread_with_stdio_ops bch2_offline_fsck_ops = { static const struct thread_with_stdio_ops bch2_offline_fsck_ops = {
@ -763,7 +777,7 @@ static long bch2_ioctl_disk_resize_journal(struct bch_fs *c,
return ret; return ret;
} }
static void bch2_fsck_online_thread_fn(struct thread_with_stdio *stdio) static int bch2_fsck_online_thread_fn(struct thread_with_stdio *stdio)
{ {
struct fsck_thread *thr = container_of(stdio, struct fsck_thread, thr); struct fsck_thread *thr = container_of(stdio, struct fsck_thread, thr);
struct bch_fs *c = thr->c; struct bch_fs *c = thr->c;
@ -795,6 +809,7 @@ static void bch2_fsck_online_thread_fn(struct thread_with_stdio *stdio)
up(&c->online_fsck_mutex); up(&c->online_fsck_mutex);
bch2_ro_ref_put(c); bch2_ro_ref_put(c);
return ret;
} }
static const struct thread_with_stdio_ops bch2_online_fsck_ops = { static const struct thread_with_stdio_ops bch2_online_fsck_ops = {

View File

@ -342,6 +342,27 @@ static int remove_backpointer(struct btree_trans *trans,
return ret; return ret;
} }
static int reattach_subvol(struct btree_trans *trans, struct bkey_s_c_subvolume s)
{
struct bch_fs *c = trans->c;
struct bch_inode_unpacked inode;
int ret = bch2_inode_find_by_inum_trans(trans,
(subvol_inum) { s.k->p.offset, le64_to_cpu(s.v->inode) },
&inode);
if (ret)
return ret;
ret = remove_backpointer(trans, &inode);
bch_err_msg(c, ret, "removing dirent");
if (ret)
return ret;
ret = reattach_inode(trans, &inode, le32_to_cpu(s.v->snapshot));
bch_err_msg(c, ret, "reattaching inode %llu", inode.bi_inum);
return ret;
}
struct snapshots_seen_entry { struct snapshots_seen_entry {
u32 id; u32 id;
u32 equiv; u32 equiv;
@ -2111,6 +2132,107 @@ int bch2_check_root(struct bch_fs *c)
return ret; return ret;
} }
typedef DARRAY(u32) darray_u32;
static bool darray_u32_has(darray_u32 *d, u32 v)
{
darray_for_each(*d, i)
if (*i == v)
return true;
return false;
}
/*
* We've checked that inode backpointers point to valid dirents; here, it's
* sufficient to check that the subvolume root has a dirent:
*/
static int subvol_has_dirent(struct btree_trans *trans, struct bkey_s_c_subvolume s)
{
struct bch_inode_unpacked inode;
int ret = bch2_inode_find_by_inum_trans(trans,
(subvol_inum) { s.k->p.offset, le64_to_cpu(s.v->inode) },
&inode);
if (ret)
return ret;
return inode.bi_dir != 0;
}
static int check_subvol_path(struct btree_trans *trans, struct btree_iter *iter, struct bkey_s_c k)
{
struct bch_fs *c = trans->c;
struct btree_iter parent_iter = {};
darray_u32 subvol_path = {};
struct printbuf buf = PRINTBUF;
int ret = 0;
if (k.k->type != KEY_TYPE_subvolume)
return 0;
while (k.k->p.offset != BCACHEFS_ROOT_SUBVOL) {
ret = darray_push(&subvol_path, k.k->p.offset);
if (ret)
goto err;
struct bkey_s_c_subvolume s = bkey_s_c_to_subvolume(k);
ret = subvol_has_dirent(trans, s);
if (ret < 0)
break;
if (fsck_err_on(!ret,
c, subvol_unreachable,
"unreachable subvolume %s",
(bch2_bkey_val_to_text(&buf, c, s.s_c),
buf.buf))) {
ret = reattach_subvol(trans, s);
break;
}
u32 parent = le32_to_cpu(s.v->fs_path_parent);
if (darray_u32_has(&subvol_path, parent)) {
if (fsck_err(c, subvol_loop, "subvolume loop"))
ret = reattach_subvol(trans, s);
break;
}
bch2_trans_iter_exit(trans, &parent_iter);
bch2_trans_iter_init(trans, &parent_iter,
BTREE_ID_subvolumes, POS(0, parent), 0);
k = bch2_btree_iter_peek_slot(&parent_iter);
ret = bkey_err(k);
if (ret)
goto err;
if (fsck_err_on(k.k->type != KEY_TYPE_subvolume,
c, subvol_unreachable,
"unreachable subvolume %s",
(bch2_bkey_val_to_text(&buf, c, s.s_c),
buf.buf))) {
ret = reattach_subvol(trans, s);
break;
}
}
fsck_err:
err:
printbuf_exit(&buf);
darray_exit(&subvol_path);
bch2_trans_iter_exit(trans, &parent_iter);
return ret;
}
int bch2_check_subvolume_structure(struct bch_fs *c)
{
int ret = bch2_trans_run(c,
for_each_btree_key_commit(trans, iter,
BTREE_ID_subvolumes, POS_MIN, BTREE_ITER_PREFETCH, k,
NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
check_subvol_path(trans, &iter, k)));
bch_err_fn(c, ret);
return ret;
}
struct pathbuf_entry { struct pathbuf_entry {
u64 inum; u64 inum;
u32 snapshot; u32 snapshot;
@ -2127,22 +2249,9 @@ static bool path_is_dup(pathbuf *p, u64 inum, u32 snapshot)
return false; return false;
} }
static int path_down(struct bch_fs *c, pathbuf *p,
u64 inum, u32 snapshot)
{
int ret = darray_push(p, ((struct pathbuf_entry) {
.inum = inum,
.snapshot = snapshot,
}));
if (ret)
bch_err(c, "fsck: error allocating memory for pathbuf, size %zu",
p->size);
return ret;
}
/* /*
* Check that a given inode is reachable from the root: * Check that a given inode is reachable from its subvolume root - we already
* verified subvolume connectivity:
* *
* XXX: we should also be verifying that inodes are in the right subvolumes * XXX: we should also be verifying that inodes are in the right subvolumes
*/ */
@ -2159,8 +2268,7 @@ static int check_path(struct btree_trans *trans, pathbuf *p, struct bkey_s_c ino
BUG_ON(bch2_inode_unpack(inode_k, &inode)); BUG_ON(bch2_inode_unpack(inode_k, &inode));
while (!(inode.bi_inum == BCACHEFS_ROOT_INO && while (!inode.bi_subvol) {
inode.bi_subvol == BCACHEFS_ROOT_SUBVOL)) {
struct btree_iter dirent_iter; struct btree_iter dirent_iter;
struct bkey_s_c_dirent d; struct bkey_s_c_dirent d;
u32 parent_snapshot = snapshot; u32 parent_snapshot = snapshot;
@ -2191,11 +2299,12 @@ static int check_path(struct btree_trans *trans, pathbuf *p, struct bkey_s_c ino
if (!S_ISDIR(inode.bi_mode)) if (!S_ISDIR(inode.bi_mode))
break; break;
ret = path_down(c, p, inode.bi_inum, snapshot); ret = darray_push(p, ((struct pathbuf_entry) {
if (ret) { .inum = inode.bi_inum,
bch_err(c, "memory allocation failure"); .snapshot = snapshot,
}));
if (ret)
return ret; return ret;
}
snapshot = parent_snapshot; snapshot = parent_snapshot;
@ -2222,18 +2331,15 @@ static int check_path(struct btree_trans *trans, pathbuf *p, struct bkey_s_c ino
pr_err("%llu:%u", i->inum, i->snapshot); pr_err("%llu:%u", i->inum, i->snapshot);
pr_err("%llu:%u", inode.bi_inum, snapshot); pr_err("%llu:%u", inode.bi_inum, snapshot);
if (!fsck_err(c, dir_loop, "directory structure loop")) if (fsck_err(c, dir_loop, "directory structure loop")) {
return 0; ret = remove_backpointer(trans, &inode);
ret = remove_backpointer(trans, &inode);
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
bch_err_msg(c, ret, "removing dirent"); bch_err_msg(c, ret, "removing dirent");
if (ret) if (ret)
break; break;
ret = reattach_inode(trans, &inode, snapshot); ret = reattach_inode(trans, &inode, snapshot);
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
bch_err_msg(c, ret, "reattaching inode %llu", inode.bi_inum); bch_err_msg(c, ret, "reattaching inode %llu", inode.bi_inum);
}
break; break;
} }
} }

View File

@ -8,6 +8,7 @@ int bch2_check_indirect_extents(struct bch_fs *);
int bch2_check_dirents(struct bch_fs *); int bch2_check_dirents(struct bch_fs *);
int bch2_check_xattrs(struct bch_fs *); int bch2_check_xattrs(struct bch_fs *);
int bch2_check_root(struct bch_fs *); int bch2_check_root(struct bch_fs *);
int bch2_check_subvolume_structure(struct bch_fs *);
int bch2_check_directory_structure(struct bch_fs *); int bch2_check_directory_structure(struct bch_fs *);
int bch2_check_nlinks(struct bch_fs *); int bch2_check_nlinks(struct bch_fs *);
int bch2_fix_reflink_p(struct bch_fs *); int bch2_fix_reflink_p(struct bch_fs *);

View File

@ -530,7 +530,8 @@ static void __bch2_write_index(struct bch_write_op *op)
bch_err_inum_offset_ratelimited(c, bch_err_inum_offset_ratelimited(c,
insert->k.p.inode, insert->k.p.offset << 9, insert->k.p.inode, insert->k.p.offset << 9,
"write error while doing btree update: %s", "%s write error while doing btree update: %s",
op->flags & BCH_WRITE_MOVE ? "move" : "user",
bch2_err_str(ret)); bch2_err_str(ret));
} }
@ -1067,7 +1068,8 @@ do_write:
*_dst = dst; *_dst = dst;
return more; return more;
csum_err: csum_err:
bch_err(c, "error verifying existing checksum while rewriting existing data (memory corruption?)"); bch_err(c, "%s writ error: error verifying existing checksum while rewriting existing data (memory corruption?)",
op->flags & BCH_WRITE_MOVE ? "move" : "user");
ret = -EIO; ret = -EIO;
err: err:
if (to_wbio(dst)->bounce) if (to_wbio(dst)->bounce)
@ -1169,7 +1171,8 @@ static void bch2_nocow_write_convert_unwritten(struct bch_write_op *op)
bch_err_inum_offset_ratelimited(c, bch_err_inum_offset_ratelimited(c,
insert->k.p.inode, insert->k.p.offset << 9, insert->k.p.inode, insert->k.p.offset << 9,
"write error while doing btree update: %s", "%s write error while doing btree update: %s",
op->flags & BCH_WRITE_MOVE ? "move" : "user",
bch2_err_str(ret)); bch2_err_str(ret));
} }
@ -1449,7 +1452,9 @@ err:
bch_err_inum_offset_ratelimited(c, bch_err_inum_offset_ratelimited(c,
op->pos.inode, op->pos.inode,
op->pos.offset << 9, op->pos.offset << 9,
"%s(): error: %s", __func__, bch2_err_str(ret)); "%s(): %s error: %s", __func__,
op->flags & BCH_WRITE_MOVE ? "move" : "user",
bch2_err_str(ret));
op->error = ret; op->error = ret;
break; break;
} }
@ -1573,7 +1578,8 @@ CLOSURE_CALLBACK(bch2_write)
bch_err_inum_offset_ratelimited(c, bch_err_inum_offset_ratelimited(c,
op->pos.inode, op->pos.inode,
op->pos.offset << 9, op->pos.offset << 9,
"misaligned write"); "%s write error: misaligned write",
op->flags & BCH_WRITE_MOVE ? "move" : "user");
op->error = -EIO; op->error = -EIO;
goto err; goto err;
} }

View File

@ -53,33 +53,48 @@ static void bch2_journal_buf_to_text(struct printbuf *out, struct journal *j, u6
unsigned i = seq & JOURNAL_BUF_MASK; unsigned i = seq & JOURNAL_BUF_MASK;
struct journal_buf *buf = j->buf + i; struct journal_buf *buf = j->buf + i;
prt_printf(out, "seq:"); prt_str(out, "seq:");
prt_tab(out); prt_tab(out);
prt_printf(out, "%llu", seq); prt_printf(out, "%llu", seq);
prt_newline(out); prt_newline(out);
printbuf_indent_add(out, 2); printbuf_indent_add(out, 2);
prt_printf(out, "refcount:"); prt_str(out, "refcount:");
prt_tab(out); prt_tab(out);
prt_printf(out, "%u", journal_state_count(s, i)); prt_printf(out, "%u", journal_state_count(s, i));
prt_newline(out); prt_newline(out);
prt_printf(out, "size:"); prt_str(out, "size:");
prt_tab(out); prt_tab(out);
prt_human_readable_u64(out, vstruct_bytes(buf->data)); prt_human_readable_u64(out, vstruct_bytes(buf->data));
prt_newline(out); prt_newline(out);
prt_printf(out, "expires"); prt_str(out, "expires:");
prt_tab(out); prt_tab(out);
prt_printf(out, "%li jiffies", buf->expires - jiffies); prt_printf(out, "%li jiffies", buf->expires - jiffies);
prt_newline(out); prt_newline(out);
prt_str(out, "flags:");
prt_tab(out);
if (buf->noflush)
prt_str(out, "noflush ");
if (buf->must_flush)
prt_str(out, "must_flush ");
if (buf->separate_flush)
prt_str(out, "separate_flush ");
if (buf->need_flush_to_write_buffer)
prt_str(out, "need_flush_to_write_buffer ");
if (buf->need_flush_to_write_buffer)
prt_str(out, "need_flush_to_write_buffer ");
if (buf->write_done) if (buf->write_done)
prt_printf(out, "write done\n"); prt_str(out, "write done ");
else if (buf->write_allocated) if (buf->write_started)
prt_printf(out, "write allocated\n"); prt_str(out, "write started ");
else if (buf->write_started) if (buf->write_allocated)
prt_printf(out, "write started\n"); prt_str(out, "write allocated ");
if (buf->write_done)
prt_str(out, "write done");
prt_newline(out);
printbuf_indent_sub(out, 2); printbuf_indent_sub(out, 2);
} }
@ -1420,6 +1435,7 @@ void __bch2_journal_debug_to_text(struct printbuf *out, struct journal *j)
prt_printf(out, "reclaim kicked:\t\t%u\n", j->reclaim_kicked); prt_printf(out, "reclaim kicked:\t\t%u\n", j->reclaim_kicked);
prt_printf(out, "reclaim runs in:\t%u ms\n", time_after(j->next_reclaim, now) prt_printf(out, "reclaim runs in:\t%u ms\n", time_after(j->next_reclaim, now)
? jiffies_to_msecs(j->next_reclaim - jiffies) : 0); ? jiffies_to_msecs(j->next_reclaim - jiffies) : 0);
prt_printf(out, "blocked:\t\t%u\n", j->blocked);
prt_printf(out, "current entry sectors:\t%u\n", j->cur_entry_sectors); prt_printf(out, "current entry sectors:\t%u\n", j->cur_entry_sectors);
prt_printf(out, "current entry error:\t%s\n", bch2_journal_errors[j->cur_entry_error]); prt_printf(out, "current entry error:\t%s\n", bch2_journal_errors[j->cur_entry_error]);
prt_printf(out, "current entry:\t\t"); prt_printf(out, "current entry:\t\t");

View File

@ -1830,7 +1830,10 @@ static int bch2_journal_write_prep(struct journal *j, struct journal_buf *w)
if (wb.wb) if (wb.wb)
bch2_journal_keys_to_write_buffer_end(c, &wb); bch2_journal_keys_to_write_buffer_end(c, &wb);
spin_lock(&c->journal.lock);
w->need_flush_to_write_buffer = false; w->need_flush_to_write_buffer = false;
spin_unlock(&c->journal.lock);
start = end = vstruct_last(jset); start = end = vstruct_last(jset);
@ -1948,12 +1951,20 @@ CLOSURE_CALLBACK(bch2_journal_write)
unsigned nr_rw_members = 0; unsigned nr_rw_members = 0;
int ret; int ret;
for_each_rw_member(c, ca)
nr_rw_members++;
BUG_ON(BCH_SB_CLEAN(c->disk_sb.sb)); BUG_ON(BCH_SB_CLEAN(c->disk_sb.sb));
BUG_ON(!w->write_started);
BUG_ON(w->write_allocated); BUG_ON(w->write_allocated);
BUG_ON(w->write_done);
j->write_start_time = local_clock(); j->write_start_time = local_clock();
spin_lock(&j->lock); spin_lock(&j->lock);
if (nr_rw_members > 1)
w->separate_flush = true;
ret = bch2_journal_write_pick_flush(j, w); ret = bch2_journal_write_pick_flush(j, w);
spin_unlock(&j->lock); spin_unlock(&j->lock);
if (ret) if (ret)
@ -2008,12 +2019,6 @@ CLOSURE_CALLBACK(bch2_journal_write)
if (c->opts.nochanges) if (c->opts.nochanges)
goto no_io; goto no_io;
for_each_rw_member(c, ca)
nr_rw_members++;
if (nr_rw_members > 1)
w->separate_flush = true;
/* /*
* Mark journal replicas before we submit the write to guarantee * Mark journal replicas before we submit the write to guarantee
* recovery will find the journal entries after a crash. * recovery will find the journal entries after a crash.

View File

@ -887,9 +887,11 @@ int bch2_journal_flush_device_pins(struct journal *j, int dev_idx)
journal_seq_pin(j, seq)->devs); journal_seq_pin(j, seq)->devs);
seq++; seq++;
spin_unlock(&j->lock); if (replicas.e.nr_devs) {
ret = bch2_mark_replicas(c, &replicas.e); spin_unlock(&j->lock);
spin_lock(&j->lock); ret = bch2_mark_replicas(c, &replicas.e);
spin_lock(&j->lock);
}
} }
spin_unlock(&j->lock); spin_unlock(&j->lock);
err: err:

View File

@ -412,11 +412,11 @@ void bch2_rebalance_status_to_text(struct printbuf *out, struct bch_fs *c)
u64 now = atomic64_read(&c->io_clock[WRITE].now); u64 now = atomic64_read(&c->io_clock[WRITE].now);
prt_str(out, "io wait duration: "); prt_str(out, "io wait duration: ");
bch2_prt_human_readable_s64(out, r->wait_iotime_end - r->wait_iotime_start); bch2_prt_human_readable_s64(out, (r->wait_iotime_end - r->wait_iotime_start) << 9);
prt_newline(out); prt_newline(out);
prt_str(out, "io wait remaining: "); prt_str(out, "io wait remaining: ");
bch2_prt_human_readable_s64(out, r->wait_iotime_end - now); bch2_prt_human_readable_s64(out, (r->wait_iotime_end - now) << 9);
prt_newline(out); prt_newline(out);
prt_str(out, "duration waited: "); prt_str(out, "duration waited: ");

View File

@ -44,6 +44,7 @@
x(check_dirents, 27, PASS_FSCK) \ x(check_dirents, 27, PASS_FSCK) \
x(check_xattrs, 28, PASS_FSCK) \ x(check_xattrs, 28, PASS_FSCK) \
x(check_root, 29, PASS_ONLINE|PASS_FSCK) \ x(check_root, 29, PASS_ONLINE|PASS_FSCK) \
x(check_subvolume_structure, 36, PASS_ONLINE|PASS_FSCK) \
x(check_directory_structure, 30, PASS_ONLINE|PASS_FSCK) \ x(check_directory_structure, 30, PASS_ONLINE|PASS_FSCK) \
x(check_nlinks, 31, PASS_FSCK) \ x(check_nlinks, 31, PASS_FSCK) \
x(delete_dead_inodes, 32, PASS_FSCK|PASS_UNCLEAN) \ x(delete_dead_inodes, 32, PASS_FSCK|PASS_UNCLEAN) \

View File

@ -262,7 +262,9 @@
x(subvol_fs_path_parent_wrong, 254) \ x(subvol_fs_path_parent_wrong, 254) \
x(subvol_root_fs_path_parent_nonzero, 255) \ x(subvol_root_fs_path_parent_nonzero, 255) \
x(subvol_children_not_set, 256) \ x(subvol_children_not_set, 256) \
x(subvol_children_bad, 257) x(subvol_children_bad, 257) \
x(subvol_loop, 258) \
x(subvol_unreachable, 259)
enum bch_sb_error_id { enum bch_sb_error_id {
#define x(t, n) BCH_FSCK_ERR_##t = n, #define x(t, n) BCH_FSCK_ERR_##t = n,