Commit bc83b4d1 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'bcachefs-2024-09-09' of git://evilpiepirate.org/bcachefs

Pull bcachefs fixes from Kent Overstreet:

 - fix ca->io_ref usage; analagous to previous patch doing that for main
   discard path

 - cond_resched() in __journal_keys_sort(), cutting down on "hung task"
   warnings when journal is big

 - rest of basic BCH_SB_MEMBER_INVALID support

 - and the critical one: don't delete open files in online fsck, this
   was causing the "dirent points to inode that doesn't point back"
   inconsistencies some users were seeing

* tag 'bcachefs-2024-09-09' of git://evilpiepirate.org/bcachefs:
  bcachefs: Don't delete open files in online fsck
  bcachefs: fix btree_key_cache sysfs knob
  bcachefs: More BCH_SB_MEMBER_INVALID support
  bcachefs: Simplify bch2_bkey_drop_ptrs()
  bcachefs: Add a cond_resched() to __journal_keys_sort()
  bcachefs: Fix ca->io_ref usage
parents fb92a1ff 16005147
...@@ -1968,8 +1968,8 @@ static void bch2_do_discards_fast_work(struct work_struct *work) ...@@ -1968,8 +1968,8 @@ static void bch2_do_discards_fast_work(struct work_struct *work)
break; break;
} }
bch2_write_ref_put(c, BCH_WRITE_REF_discard_fast);
percpu_ref_put(&ca->io_ref); percpu_ref_put(&ca->io_ref);
bch2_write_ref_put(c, BCH_WRITE_REF_discard_fast);
} }
static void bch2_discard_one_bucket_fast(struct bch_dev *ca, u64 bucket) static void bch2_discard_one_bucket_fast(struct bch_dev *ca, u64 bucket)
...@@ -1979,18 +1979,18 @@ static void bch2_discard_one_bucket_fast(struct bch_dev *ca, u64 bucket) ...@@ -1979,18 +1979,18 @@ static void bch2_discard_one_bucket_fast(struct bch_dev *ca, u64 bucket)
if (discard_in_flight_add(ca, bucket, false)) if (discard_in_flight_add(ca, bucket, false))
return; return;
if (!bch2_dev_get_ioref(c, ca->dev_idx, WRITE)) if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_discard_fast))
return; return;
if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_discard_fast)) if (!bch2_dev_get_ioref(c, ca->dev_idx, WRITE))
goto put_ioref; goto put_ref;
if (queue_work(c->write_ref_wq, &ca->discard_fast_work)) if (queue_work(c->write_ref_wq, &ca->discard_fast_work))
return; return;
bch2_write_ref_put(c, BCH_WRITE_REF_discard_fast);
put_ioref:
percpu_ref_put(&ca->io_ref); percpu_ref_put(&ca->io_ref);
put_ref:
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,
...@@ -2132,26 +2132,26 @@ static void bch2_do_invalidates_work(struct work_struct *work) ...@@ -2132,26 +2132,26 @@ static void bch2_do_invalidates_work(struct work_struct *work)
bch2_trans_iter_exit(trans, &iter); bch2_trans_iter_exit(trans, &iter);
err: err:
bch2_trans_put(trans); bch2_trans_put(trans);
bch2_write_ref_put(c, BCH_WRITE_REF_invalidate);
percpu_ref_put(&ca->io_ref); percpu_ref_put(&ca->io_ref);
bch2_write_ref_put(c, BCH_WRITE_REF_invalidate);
} }
void bch2_dev_do_invalidates(struct bch_dev *ca) void bch2_dev_do_invalidates(struct bch_dev *ca)
{ {
struct bch_fs *c = ca->fs; struct bch_fs *c = ca->fs;
if (!bch2_dev_get_ioref(c, ca->dev_idx, WRITE)) if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_invalidate))
return; return;
if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_invalidate)) if (!bch2_dev_get_ioref(c, ca->dev_idx, WRITE))
goto put_ioref; goto put_ref;
if (queue_work(c->write_ref_wq, &ca->invalidate_work)) if (queue_work(c->write_ref_wq, &ca->invalidate_work))
return; return;
bch2_write_ref_put(c, BCH_WRITE_REF_invalidate);
put_ioref:
percpu_ref_put(&ca->io_ref); percpu_ref_put(&ca->io_ref);
put_ref:
bch2_write_ref_put(c, BCH_WRITE_REF_invalidate);
} }
void bch2_do_invalidates(struct bch_fs *c) void bch2_do_invalidates(struct bch_fs *c)
......
...@@ -530,6 +530,8 @@ static void __journal_keys_sort(struct journal_keys *keys) ...@@ -530,6 +530,8 @@ static void __journal_keys_sort(struct journal_keys *keys)
{ {
sort(keys->data, keys->nr, sizeof(keys->data[0]), journal_sort_key_cmp, NULL); sort(keys->data, keys->nr, sizeof(keys->data[0]), journal_sort_key_cmp, NULL);
cond_resched();
struct journal_key *dst = keys->data; struct journal_key *dst = keys->data;
darray_for_each(*keys, src) { darray_for_each(*keys, src) {
......
...@@ -100,12 +100,13 @@ static int bch2_check_fix_ptr(struct btree_trans *trans, ...@@ -100,12 +100,13 @@ static int bch2_check_fix_ptr(struct btree_trans *trans,
struct bch_dev *ca = bch2_dev_tryget(c, p.ptr.dev); struct bch_dev *ca = bch2_dev_tryget(c, p.ptr.dev);
if (!ca) { if (!ca) {
if (fsck_err(trans, ptr_to_invalid_device, if (fsck_err_on(p.ptr.dev != BCH_SB_MEMBER_INVALID,
"pointer to missing device %u\n" trans, ptr_to_invalid_device,
"while marking %s", "pointer to missing device %u\n"
p.ptr.dev, "while marking %s",
(printbuf_reset(&buf), p.ptr.dev,
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
*do_update = true; *do_update = true;
return 0; return 0;
} }
...@@ -562,7 +563,7 @@ static int bch2_trigger_pointer(struct btree_trans *trans, ...@@ -562,7 +563,7 @@ static int bch2_trigger_pointer(struct btree_trans *trans,
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
struct bch_dev *ca = bch2_dev_tryget(c, p.ptr.dev); struct bch_dev *ca = bch2_dev_tryget(c, p.ptr.dev);
if (unlikely(!ca)) { if (unlikely(!ca)) {
if (insert) if (insert && p.ptr.dev != BCH_SB_MEMBER_INVALID)
ret = -EIO; ret = -EIO;
goto err; goto err;
} }
......
...@@ -97,7 +97,9 @@ static inline bool __bch2_ptr_matches_stripe(const struct bch_extent_ptr *stripe ...@@ -97,7 +97,9 @@ static inline bool __bch2_ptr_matches_stripe(const struct bch_extent_ptr *stripe
const struct bch_extent_ptr *data_ptr, const struct bch_extent_ptr *data_ptr,
unsigned sectors) unsigned sectors)
{ {
return data_ptr->dev == stripe_ptr->dev && return (data_ptr->dev == stripe_ptr->dev ||
data_ptr->dev == BCH_SB_MEMBER_INVALID ||
stripe_ptr->dev == BCH_SB_MEMBER_INVALID) &&
data_ptr->gen == stripe_ptr->gen && data_ptr->gen == stripe_ptr->gen &&
data_ptr->offset >= stripe_ptr->offset && data_ptr->offset >= stripe_ptr->offset &&
data_ptr->offset < stripe_ptr->offset + sectors; data_ptr->offset < stripe_ptr->offset + sectors;
......
...@@ -781,14 +781,17 @@ static union bch_extent_entry *extent_entry_prev(struct bkey_ptrs ptrs, ...@@ -781,14 +781,17 @@ static union bch_extent_entry *extent_entry_prev(struct bkey_ptrs ptrs,
/* /*
* Returns pointer to the next entry after the one being dropped: * Returns pointer to the next entry after the one being dropped:
*/ */
union bch_extent_entry *bch2_bkey_drop_ptr_noerror(struct bkey_s k, void bch2_bkey_drop_ptr_noerror(struct bkey_s k, struct bch_extent_ptr *ptr)
struct bch_extent_ptr *ptr)
{ {
struct bkey_ptrs ptrs = bch2_bkey_ptrs(k); struct bkey_ptrs ptrs = bch2_bkey_ptrs(k);
union bch_extent_entry *entry = to_entry(ptr), *next; union bch_extent_entry *entry = to_entry(ptr), *next;
union bch_extent_entry *ret = entry;
bool drop_crc = true; bool drop_crc = true;
if (k.k->type == KEY_TYPE_stripe) {
ptr->dev = BCH_SB_MEMBER_INVALID;
return;
}
EBUG_ON(ptr < &ptrs.start->ptr || EBUG_ON(ptr < &ptrs.start->ptr ||
ptr >= &ptrs.end->ptr); ptr >= &ptrs.end->ptr);
EBUG_ON(ptr->type != 1 << BCH_EXTENT_ENTRY_ptr); EBUG_ON(ptr->type != 1 << BCH_EXTENT_ENTRY_ptr);
...@@ -811,21 +814,16 @@ union bch_extent_entry *bch2_bkey_drop_ptr_noerror(struct bkey_s k, ...@@ -811,21 +814,16 @@ union bch_extent_entry *bch2_bkey_drop_ptr_noerror(struct bkey_s k,
break; break;
if ((extent_entry_is_crc(entry) && drop_crc) || if ((extent_entry_is_crc(entry) && drop_crc) ||
extent_entry_is_stripe_ptr(entry)) { extent_entry_is_stripe_ptr(entry))
ret = (void *) ret - extent_entry_bytes(entry);
extent_entry_drop(k, entry); extent_entry_drop(k, entry);
}
} }
return ret;
} }
union bch_extent_entry *bch2_bkey_drop_ptr(struct bkey_s k, void bch2_bkey_drop_ptr(struct bkey_s k, struct bch_extent_ptr *ptr)
struct bch_extent_ptr *ptr)
{ {
bool have_dirty = bch2_bkey_dirty_devs(k.s_c).nr; bool have_dirty = bch2_bkey_dirty_devs(k.s_c).nr;
union bch_extent_entry *ret =
bch2_bkey_drop_ptr_noerror(k, ptr); bch2_bkey_drop_ptr_noerror(k, ptr);
/* /*
* If we deleted all the dirty pointers and there's still cached * If we deleted all the dirty pointers and there's still cached
...@@ -837,14 +835,10 @@ union bch_extent_entry *bch2_bkey_drop_ptr(struct bkey_s k, ...@@ -837,14 +835,10 @@ union bch_extent_entry *bch2_bkey_drop_ptr(struct bkey_s k,
!bch2_bkey_dirty_devs(k.s_c).nr) { !bch2_bkey_dirty_devs(k.s_c).nr) {
k.k->type = KEY_TYPE_error; k.k->type = KEY_TYPE_error;
set_bkey_val_u64s(k.k, 0); set_bkey_val_u64s(k.k, 0);
ret = NULL;
} else if (!bch2_bkey_nr_ptrs(k.s_c)) { } else if (!bch2_bkey_nr_ptrs(k.s_c)) {
k.k->type = KEY_TYPE_deleted; k.k->type = KEY_TYPE_deleted;
set_bkey_val_u64s(k.k, 0); set_bkey_val_u64s(k.k, 0);
ret = NULL;
} }
return ret;
} }
void bch2_bkey_drop_device(struct bkey_s k, unsigned dev) void bch2_bkey_drop_device(struct bkey_s k, unsigned dev)
......
...@@ -649,26 +649,21 @@ static inline void bch2_bkey_append_ptr(struct bkey_i *k, struct bch_extent_ptr ...@@ -649,26 +649,21 @@ static inline void bch2_bkey_append_ptr(struct bkey_i *k, struct bch_extent_ptr
void bch2_extent_ptr_decoded_append(struct bkey_i *, void bch2_extent_ptr_decoded_append(struct bkey_i *,
struct extent_ptr_decoded *); struct extent_ptr_decoded *);
union bch_extent_entry *bch2_bkey_drop_ptr_noerror(struct bkey_s, void bch2_bkey_drop_ptr_noerror(struct bkey_s, struct bch_extent_ptr *);
struct bch_extent_ptr *); void bch2_bkey_drop_ptr(struct bkey_s, struct bch_extent_ptr *);
union bch_extent_entry *bch2_bkey_drop_ptr(struct bkey_s,
struct bch_extent_ptr *);
#define bch2_bkey_drop_ptrs(_k, _ptr, _cond) \ #define bch2_bkey_drop_ptrs(_k, _ptr, _cond) \
do { \ do { \
struct bkey_ptrs _ptrs = bch2_bkey_ptrs(_k); \ __label__ _again; \
struct bkey_ptrs _ptrs; \
_again: \
_ptrs = bch2_bkey_ptrs(_k); \
\ \
struct bch_extent_ptr *_ptr = &_ptrs.start->ptr; \ bkey_for_each_ptr(_ptrs, _ptr) \
\
while ((_ptr = bkey_ptr_next(_ptrs, _ptr))) { \
if (_cond) { \ if (_cond) { \
_ptr = (void *) bch2_bkey_drop_ptr(_k, _ptr); \ bch2_bkey_drop_ptr(_k, _ptr); \
_ptrs = bch2_bkey_ptrs(_k); \ goto _again; \
continue; \
} \ } \
\
(_ptr)++; \
} \
} while (0) } while (0)
bool bch2_bkey_matches_ptr(struct bch_fs *, struct bkey_s_c, bool bch2_bkey_matches_ptr(struct bch_fs *, struct bkey_s_c,
......
...@@ -177,6 +177,14 @@ static unsigned bch2_inode_hash(subvol_inum inum) ...@@ -177,6 +177,14 @@ static unsigned bch2_inode_hash(subvol_inum inum)
return jhash_3words(inum.subvol, inum.inum >> 32, inum.inum, JHASH_INITVAL); return jhash_3words(inum.subvol, inum.inum >> 32, inum.inum, JHASH_INITVAL);
} }
struct bch_inode_info *__bch2_inode_hash_find(struct bch_fs *c, subvol_inum inum)
{
return to_bch_ei(ilookup5_nowait(c->vfs_sb,
bch2_inode_hash(inum),
bch2_iget5_test,
&inum));
}
static struct bch_inode_info *bch2_inode_insert(struct bch_fs *c, struct bch_inode_info *inode) static struct bch_inode_info *bch2_inode_insert(struct bch_fs *c, struct bch_inode_info *inode)
{ {
subvol_inum inum = inode_inum(inode); subvol_inum inum = inode_inum(inode);
......
...@@ -56,6 +56,8 @@ static inline subvol_inum inode_inum(struct bch_inode_info *inode) ...@@ -56,6 +56,8 @@ static inline subvol_inum inode_inum(struct bch_inode_info *inode)
}; };
} }
struct bch_inode_info *__bch2_inode_hash_find(struct bch_fs *, subvol_inum);
/* /*
* Set if we've gotten a btree error for this inode, and thus the vfs inode and * Set if we've gotten a btree error for this inode, and thus the vfs inode and
* btree inode may be inconsistent: * btree inode may be inconsistent:
...@@ -194,6 +196,11 @@ int bch2_vfs_init(void); ...@@ -194,6 +196,11 @@ int bch2_vfs_init(void);
#define bch2_inode_update_after_write(_trans, _inode, _inode_u, _fields) ({ do {} while (0); }) #define bch2_inode_update_after_write(_trans, _inode, _inode_u, _fields) ({ do {} while (0); })
static inline struct bch_inode_info *__bch2_inode_hash_find(struct bch_fs *c, subvol_inum inum)
{
return NULL;
}
static inline void bch2_evict_subvolume_inodes(struct bch_fs *c, static inline void bch2_evict_subvolume_inodes(struct bch_fs *c,
snapshot_id_list *s) {} snapshot_id_list *s) {}
static inline void bch2_vfs_exit(void) {} static inline void bch2_vfs_exit(void) {}
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "darray.h" #include "darray.h"
#include "dirent.h" #include "dirent.h"
#include "error.h" #include "error.h"
#include "fs.h"
#include "fs-common.h" #include "fs-common.h"
#include "fsck.h" #include "fsck.h"
#include "inode.h" #include "inode.h"
...@@ -962,6 +963,22 @@ static int check_inode_dirent_inode(struct btree_trans *trans, struct bkey_s_c i ...@@ -962,6 +963,22 @@ static int check_inode_dirent_inode(struct btree_trans *trans, struct bkey_s_c i
return ret; return ret;
} }
static bool bch2_inode_open(struct bch_fs *c, struct bpos p)
{
subvol_inum inum = {
.subvol = snapshot_t(c, p.snapshot)->subvol,
.inum = p.offset,
};
/* snapshot tree corruption, can't safely delete */
if (!inum.subvol) {
bch_err_ratelimited(c, "%s(): snapshot %u has no subvol", __func__, p.snapshot);
return true;
}
return __bch2_inode_hash_find(c, inum) != NULL;
}
static int check_inode(struct btree_trans *trans, static int check_inode(struct btree_trans *trans,
struct btree_iter *iter, struct btree_iter *iter,
struct bkey_s_c k, struct bkey_s_c k,
...@@ -1040,6 +1057,7 @@ static int check_inode(struct btree_trans *trans, ...@@ -1040,6 +1057,7 @@ static int check_inode(struct btree_trans *trans,
} }
if (u.bi_flags & BCH_INODE_unlinked && if (u.bi_flags & BCH_INODE_unlinked &&
!bch2_inode_open(c, k.k->p) &&
(!c->sb.clean || (!c->sb.clean ||
fsck_err(trans, inode_unlinked_but_clean, fsck_err(trans, inode_unlinked_but_clean,
"filesystem marked clean, but inode %llu unlinked", "filesystem marked clean, but inode %llu unlinked",
......
...@@ -796,7 +796,7 @@ bool bch2_have_enough_devs(struct bch_fs *c, struct bch_devs_mask devs, ...@@ -796,7 +796,7 @@ bool bch2_have_enough_devs(struct bch_fs *c, struct bch_devs_mask devs,
nr_online += test_bit(e->devs[i], devs.d); nr_online += test_bit(e->devs[i], devs.d);
struct bch_dev *ca = bch2_dev_rcu(c, e->devs[i]); struct bch_dev *ca = bch2_dev_rcu(c, e->devs[i]);
nr_failed += ca && ca->mi.state == BCH_MEMBER_STATE_failed; nr_failed += !ca || ca->mi.state == BCH_MEMBER_STATE_failed;
} }
rcu_read_unlock(); rcu_read_unlock();
......
...@@ -461,7 +461,7 @@ STORE(bch2_fs) ...@@ -461,7 +461,7 @@ STORE(bch2_fs)
sc.gfp_mask = GFP_KERNEL; sc.gfp_mask = GFP_KERNEL;
sc.nr_to_scan = strtoul_or_return(buf); sc.nr_to_scan = strtoul_or_return(buf);
c->btree_key_cache.shrink->scan_objects(c->btree_cache.shrink, &sc); c->btree_key_cache.shrink->scan_objects(c->btree_key_cache.shrink, &sc);
} }
if (attr == &sysfs_trigger_gc) if (attr == &sysfs_trigger_gc)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment