diff options
-rw-r--r-- | fs/bcachefs/fsck.c | 36 | ||||
-rw-r--r-- | fs/bcachefs/io_misc.c | 27 | ||||
-rw-r--r-- | fs/bcachefs/io_misc.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/journal_io.c | 55 | ||||
-rw-r--r-- | fs/bcachefs/journal_io.h | 7 | ||||
-rw-r--r-- | fs/bcachefs/journal_seq_blacklist.c | 46 | ||||
-rw-r--r-- | fs/bcachefs/journal_seq_blacklist.h | 3 | ||||
-rw-r--r-- | fs/bcachefs/util.c | 5 |
8 files changed, 127 insertions, 54 deletions
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c index 00afe0a3593f..471e93a3f00c 100644 --- a/fs/bcachefs/fsck.c +++ b/fs/bcachefs/fsck.c @@ -12,6 +12,7 @@ #include "fs.h" #include "fsck.h" #include "inode.h" +#include "io_misc.h" #include "keylist.h" #include "namei.h" #include "recovery_passes.h" @@ -1637,7 +1638,8 @@ static int check_i_sectors_notnested(struct btree_trans *trans, struct inode_wal i->count = count2; } - if (fsck_err_on(!(i->inode.bi_flags & BCH_INODE_i_sectors_dirty), + if (fsck_err_on(!(i->inode.bi_flags & BCH_INODE_i_sectors_dirty) && + i->inode.bi_sectors != i->count, trans, inode_i_sectors_wrong, "inode %llu:%u has incorrect i_sectors: got %llu, should be %llu", w->last_pos.inode, i->inode.bi_snapshot, @@ -1963,33 +1965,11 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, "extent type past end of inode %llu:%u, i_size %llu\n%s", i->inode.bi_inum, i->inode.bi_snapshot, i->inode.bi_size, (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { - struct bkey_i *whiteout = bch2_trans_kmalloc(trans, sizeof(*whiteout)); - ret = PTR_ERR_OR_ZERO(whiteout); - if (ret) - goto err; - - bkey_init(&whiteout->k); - whiteout->k.p = SPOS(k.k->p.inode, - last_block, - i->inode.bi_snapshot); - bch2_key_resize(&whiteout->k, - min(KEY_SIZE_MAX & (~0 << c->block_bits), - U64_MAX - whiteout->k.p.offset)); - - - /* - * Need a normal (not BTREE_ITER_all_snapshots) - * iterator, if we're deleting in a different - * snapshot and need to emit a whiteout - */ - struct btree_iter iter2; - bch2_trans_iter_init(trans, &iter2, BTREE_ID_extents, - bkey_start_pos(&whiteout->k), - BTREE_ITER_intent); - ret = bch2_btree_iter_traverse(trans, &iter2) ?: - bch2_trans_update(trans, &iter2, whiteout, - BTREE_UPDATE_internal_snapshot_node); - bch2_trans_iter_exit(trans, &iter2); + ret = bch2_fpunch_snapshot(trans, + SPOS(i->inode.bi_inum, + last_block, + i->inode.bi_snapshot), + POS(i->inode.bi_inum, U64_MAX)); if (ret) goto err; diff --git a/fs/bcachefs/io_misc.c b/fs/bcachefs/io_misc.c index bf72b1d2e2cb..07023667a475 100644 --- a/fs/bcachefs/io_misc.c +++ b/fs/bcachefs/io_misc.c @@ -135,6 +135,33 @@ err_noprint: return ret; } +/* For fsck */ +int bch2_fpunch_snapshot(struct btree_trans *trans, struct bpos start, struct bpos end) +{ + u32 restart_count = trans->restart_count; + struct bch_fs *c = trans->c; + struct disk_reservation disk_res = bch2_disk_reservation_init(c, 0); + unsigned max_sectors = KEY_SIZE_MAX & (~0 << c->block_bits); + struct bkey_i delete; + + int ret = for_each_btree_key_max_commit(trans, iter, BTREE_ID_extents, + start, end, 0, k, + &disk_res, NULL, BCH_TRANS_COMMIT_no_enospc, ({ + bkey_init(&delete.k); + delete.k.p = iter.pos; + + /* create the biggest key we can */ + bch2_key_resize(&delete.k, max_sectors); + bch2_cut_back(end, &delete); + + bch2_extent_trim_atomic(trans, &iter, &delete) ?: + bch2_trans_update(trans, &iter, &delete, 0); + })); + + bch2_disk_reservation_put(c, &disk_res); + return ret ?: trans_was_restarted(trans, restart_count); +} + /* * Returns -BCH_ERR_transacton_restart if we had to drop locks: */ diff --git a/fs/bcachefs/io_misc.h b/fs/bcachefs/io_misc.h index 9cb44a7c43c1..b93e4d4b3c0c 100644 --- a/fs/bcachefs/io_misc.h +++ b/fs/bcachefs/io_misc.h @@ -5,6 +5,8 @@ int bch2_extent_fallocate(struct btree_trans *, subvol_inum, struct btree_iter *, u64, struct bch_io_opts, s64 *, struct write_point_specifier); + +int bch2_fpunch_snapshot(struct btree_trans *, struct bpos, struct bpos); int bch2_fpunch_at(struct btree_trans *, struct btree_iter *, subvol_inum, u64, s64 *); int bch2_fpunch(struct bch_fs *c, subvol_inum, u64, u64, s64 *); diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c index dd3f3434c1b0..2d6ce4348a22 100644 --- a/fs/bcachefs/journal_io.c +++ b/fs/bcachefs/journal_io.c @@ -1245,6 +1245,8 @@ noinline_for_stack static void bch2_journal_print_checksum_error(struct bch_fs *c, struct journal_replay *j) { struct printbuf buf = PRINTBUF; + bch2_log_msg_start(c, &buf); + enum bch_csum_type csum_type = JSET_CSUM_TYPE(&j->j); bool have_good = false; @@ -1272,6 +1274,28 @@ static void bch2_journal_print_checksum_error(struct bch_fs *c, struct journal_r printbuf_exit(&buf); } +struct u64_range bch2_journal_entry_missing_range(struct bch_fs *c, u64 start, u64 end) +{ + BUG_ON(start > end); + + if (start == end) + return (struct u64_range) {}; + + start = bch2_journal_seq_next_nonblacklisted(c, start); + if (start >= end) + return (struct u64_range) {}; + + struct u64_range missing = { + .start = start, + .end = min(end, bch2_journal_seq_next_blacklisted(c, start)), + }; + + if (missing.start == missing.end) + return (struct u64_range) {}; + + return missing; +} + noinline_for_stack static int bch2_journal_check_for_missing(struct bch_fs *c, u64 start_seq, u64 end_seq) { @@ -1280,6 +1304,7 @@ static int bch2_journal_check_for_missing(struct bch_fs *c, u64 start_seq, u64 e struct genradix_iter radix_iter; struct journal_replay *i, **_i, *prev = NULL; + /* Sequence number we expect to find next, to check for missing entries */ u64 seq = start_seq; genradix_for_each(&c->journal_entries, radix_iter, _i) { @@ -1290,43 +1315,31 @@ static int bch2_journal_check_for_missing(struct bch_fs *c, u64 start_seq, u64 e BUG_ON(seq > le64_to_cpu(i->j.seq)); - while (seq < le64_to_cpu(i->j.seq)) { - while (seq < le64_to_cpu(i->j.seq) && - bch2_journal_seq_is_blacklisted(c, seq, false)) - seq++; - - if (seq == le64_to_cpu(i->j.seq)) - break; - - u64 missing_start = seq; - - while (seq < le64_to_cpu(i->j.seq) && - !bch2_journal_seq_is_blacklisted(c, seq, false)) - seq++; - - u64 missing_end = seq - 1; + struct u64_range missing; + while ((missing = bch2_journal_entry_missing_range(c, seq, le64_to_cpu(i->j.seq))).start) { printbuf_reset(&buf); prt_printf(&buf, "journal entries %llu-%llu missing! (replaying %llu-%llu)", - missing_start, missing_end, + missing.start, missing.end - 1, start_seq, end_seq); - prt_printf(&buf, "\nprev at "); if (prev) { + prt_printf(&buf, "\n%llu at ", le64_to_cpu(prev->j.seq)); bch2_journal_ptrs_to_text(&buf, c, prev); prt_printf(&buf, " size %zu", vstruct_sectors(&prev->j, c->block_bits)); - } else - prt_printf(&buf, "(none)"); + } - prt_printf(&buf, "\nnext at "); + prt_printf(&buf, "\n%llu at ", le64_to_cpu(i->j.seq)); bch2_journal_ptrs_to_text(&buf, c, i); prt_printf(&buf, ", continue?"); fsck_err(c, journal_entries_missing, "%s", buf.buf); + + seq = missing.end; } prev = i; - seq++; + seq = le64_to_cpu(i->j.seq) + 1; } fsck_err: printbuf_exit(&buf); diff --git a/fs/bcachefs/journal_io.h b/fs/bcachefs/journal_io.h index 6fa82c4050fe..f53c5c81d137 100644 --- a/fs/bcachefs/journal_io.h +++ b/fs/bcachefs/journal_io.h @@ -71,6 +71,13 @@ void bch2_journal_entry_to_text(struct printbuf *, struct bch_fs *, void bch2_journal_ptrs_to_text(struct printbuf *, struct bch_fs *, struct journal_replay *); +struct u64_range { + u64 start; + u64 end; +}; + +struct u64_range bch2_journal_entry_missing_range(struct bch_fs *, u64, u64); + int bch2_journal_read(struct bch_fs *, u64 *, u64 *, u64 *); CLOSURE_CALLBACK(bch2_journal_write); diff --git a/fs/bcachefs/journal_seq_blacklist.c b/fs/bcachefs/journal_seq_blacklist.c index af4fe416d9ec..6361809b5e2e 100644 --- a/fs/bcachefs/journal_seq_blacklist.c +++ b/fs/bcachefs/journal_seq_blacklist.c @@ -103,6 +103,52 @@ static int journal_seq_blacklist_table_cmp(const void *_l, const void *_r) return cmp_int(l->start, r->start); } +static int journal_seq_blacklist_table_end_cmp(const void *_l, const void *_r) +{ + const struct journal_seq_blacklist_table_entry *l = _l; + const struct journal_seq_blacklist_table_entry *r = _r; + + return cmp_int(l->end, r->end); +} + +u64 bch2_journal_seq_next_blacklisted(struct bch_fs *c, u64 seq) +{ + struct journal_seq_blacklist_table *t = c->journal_seq_blacklist_table; + + if (!t) + return U64_MAX; + + struct journal_seq_blacklist_table_entry search = { .end = seq }; + int idx = eytzinger0_find_gt(t->entries, t->nr, + sizeof(t->entries[0]), + journal_seq_blacklist_table_end_cmp, + &search); + if (idx < 0) + return U64_MAX; + + return max(seq, t->entries[idx].start); +} + +u64 bch2_journal_seq_next_nonblacklisted(struct bch_fs *c, u64 seq) +{ + struct journal_seq_blacklist_table *t = c->journal_seq_blacklist_table; + + if (!t) + return seq; + + while (true) { + struct journal_seq_blacklist_table_entry search = { .start = seq }; + int idx = eytzinger0_find_le(t->entries, t->nr, + sizeof(t->entries[0]), + journal_seq_blacklist_table_cmp, + &search); + if (idx < 0 || t->entries[idx].end <= seq) + return seq; + + seq = t->entries[idx].end; + } +} + bool bch2_journal_seq_is_blacklisted(struct bch_fs *c, u64 seq, bool dirty) { diff --git a/fs/bcachefs/journal_seq_blacklist.h b/fs/bcachefs/journal_seq_blacklist.h index f06942ccfcdd..389b789b26f4 100644 --- a/fs/bcachefs/journal_seq_blacklist.h +++ b/fs/bcachefs/journal_seq_blacklist.h @@ -11,6 +11,9 @@ blacklist_nr_entries(struct bch_sb_field_journal_seq_blacklist *bl) : 0; } +u64 bch2_journal_seq_next_blacklisted(struct bch_fs *, u64); +u64 bch2_journal_seq_next_nonblacklisted(struct bch_fs *, u64); + bool bch2_journal_seq_is_blacklisted(struct bch_fs *, u64, bool); u64 bch2_journal_last_blacklisted_seq(struct bch_fs *); int bch2_journal_seq_blacklist_add(struct bch_fs *c, u64, u64); diff --git a/fs/bcachefs/util.c b/fs/bcachefs/util.c index 05b40debf211..7a4436fd4441 100644 --- a/fs/bcachefs/util.c +++ b/fs/bcachefs/util.c @@ -299,17 +299,12 @@ int bch2_save_backtrace(bch_stacktrace *stack, struct task_struct *task, unsigne if (ret) return ret; - if (!down_read_trylock(&task->signal->exec_update_lock)) - return -1; - do { nr_entries = stack_trace_save_tsk(task, stack->data, stack->size, skipnr + 1); } while (nr_entries == stack->size && !(ret = darray_make_room_gfp(stack, stack->size * 2, gfp))); stack->nr = nr_entries; - up_read(&task->signal->exec_update_lock); - return ret; #else return 0; |