mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2026-01-06 03:53:44 +00:00
bcachefs fixes for 6.11-rc8
- 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 -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEKnAFLkS8Qha+jvQrE6szbY3KbnYFAmbe/BoACgkQE6szbY3K bnbGuRAApGK3NNIlvMQkldLmDgHgeN/vuYHT4dx7XBquwS/R1T84WffIJklVOahD KdrXhGsLH63kjqck3ngCe3DFDD7Fhirmx9syVHhLAkzGFkDEYGQuIzeDXIn+XOMe kUTMhNgtSJL/eEc8zGmvyPIjtTrwoih2V0EeC1aW7h4tWtIsMk3q45aMX3yTlyqI FnMmKFjzqnOIVjT8nBLuzDP97FG4w2foSuNiZWTYo7FLi8IhPrp95tr58NqM4jvd 99U5I3aOFHe9WcCDT1vgr0P5dmmSEwIKBCfvIlA8fbVlnZzjJqEjSKh+C4878KFv FP51FOY/ZQVRE/+p8AQ82N1Zc3OTZ2488X6ajDt0Ir5EHMMmqiEXz5Zx9/7mmdta egmiVX5OAVHgWR61xzTa6LKnGIjT0XE/lYJT9kc8iox9BBduQEx+iZ8OeRDAeObW 048K3jBhXST+hK91lbgj7/lvj3IWabPSyfPyzpe46aejS3N7b79bEvKanD7dH5Dy KhdGuCKv2PXvlYbxI3rLPGUeL3InIe8TjvYa2ryl5qICSKhHjk7+8tvLeGWIXI55 rDglrYqw3s1IiGeg4QpKAB4YIeQfZn3g1WbfEs/H5GnoA7UDnQw9IkJb0/S39bEw 8OVYh52+USafMceqhwxbI4dfX7RcI00JBcVCZO5hcVu77MQA8G4= =6PAk -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
bc83b4d1f0
@ -1968,8 +1968,8 @@ static void bch2_do_discards_fast_work(struct work_struct *work)
|
||||
break;
|
||||
}
|
||||
|
||||
bch2_write_ref_put(c, BCH_WRITE_REF_discard_fast);
|
||||
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)
|
||||
@ -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))
|
||||
return;
|
||||
|
||||
if (!bch2_dev_get_ioref(c, ca->dev_idx, WRITE))
|
||||
if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_discard_fast))
|
||||
return;
|
||||
|
||||
if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_discard_fast))
|
||||
goto put_ioref;
|
||||
if (!bch2_dev_get_ioref(c, ca->dev_idx, WRITE))
|
||||
goto put_ref;
|
||||
|
||||
if (queue_work(c->write_ref_wq, &ca->discard_fast_work))
|
||||
return;
|
||||
|
||||
bch2_write_ref_put(c, BCH_WRITE_REF_discard_fast);
|
||||
put_ioref:
|
||||
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,
|
||||
@ -2132,26 +2132,26 @@ static void bch2_do_invalidates_work(struct work_struct *work)
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
err:
|
||||
bch2_trans_put(trans);
|
||||
bch2_write_ref_put(c, BCH_WRITE_REF_invalidate);
|
||||
percpu_ref_put(&ca->io_ref);
|
||||
bch2_write_ref_put(c, BCH_WRITE_REF_invalidate);
|
||||
}
|
||||
|
||||
void bch2_dev_do_invalidates(struct bch_dev *ca)
|
||||
{
|
||||
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;
|
||||
|
||||
if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_invalidate))
|
||||
goto put_ioref;
|
||||
if (!bch2_dev_get_ioref(c, ca->dev_idx, WRITE))
|
||||
goto put_ref;
|
||||
|
||||
if (queue_work(c->write_ref_wq, &ca->invalidate_work))
|
||||
return;
|
||||
|
||||
bch2_write_ref_put(c, BCH_WRITE_REF_invalidate);
|
||||
put_ioref:
|
||||
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)
|
||||
|
||||
@ -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);
|
||||
|
||||
cond_resched();
|
||||
|
||||
struct journal_key *dst = keys->data;
|
||||
|
||||
darray_for_each(*keys, src) {
|
||||
|
||||
@ -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);
|
||||
if (!ca) {
|
||||
if (fsck_err(trans, ptr_to_invalid_device,
|
||||
"pointer to missing device %u\n"
|
||||
"while marking %s",
|
||||
p.ptr.dev,
|
||||
(printbuf_reset(&buf),
|
||||
bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
|
||||
if (fsck_err_on(p.ptr.dev != BCH_SB_MEMBER_INVALID,
|
||||
trans, ptr_to_invalid_device,
|
||||
"pointer to missing device %u\n"
|
||||
"while marking %s",
|
||||
p.ptr.dev,
|
||||
(printbuf_reset(&buf),
|
||||
bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
|
||||
*do_update = true;
|
||||
return 0;
|
||||
}
|
||||
@ -562,7 +563,7 @@ static int bch2_trigger_pointer(struct btree_trans *trans,
|
||||
struct bch_fs *c = trans->c;
|
||||
struct bch_dev *ca = bch2_dev_tryget(c, p.ptr.dev);
|
||||
if (unlikely(!ca)) {
|
||||
if (insert)
|
||||
if (insert && p.ptr.dev != BCH_SB_MEMBER_INVALID)
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -97,7 +97,9 @@ static inline bool __bch2_ptr_matches_stripe(const struct bch_extent_ptr *stripe
|
||||
const struct bch_extent_ptr *data_ptr,
|
||||
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->offset >= stripe_ptr->offset &&
|
||||
data_ptr->offset < stripe_ptr->offset + sectors;
|
||||
|
||||
@ -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:
|
||||
*/
|
||||
union bch_extent_entry *bch2_bkey_drop_ptr_noerror(struct bkey_s k,
|
||||
struct bch_extent_ptr *ptr)
|
||||
void bch2_bkey_drop_ptr_noerror(struct bkey_s k, struct bch_extent_ptr *ptr)
|
||||
{
|
||||
struct bkey_ptrs ptrs = bch2_bkey_ptrs(k);
|
||||
union bch_extent_entry *entry = to_entry(ptr), *next;
|
||||
union bch_extent_entry *ret = entry;
|
||||
bool drop_crc = true;
|
||||
|
||||
if (k.k->type == KEY_TYPE_stripe) {
|
||||
ptr->dev = BCH_SB_MEMBER_INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
EBUG_ON(ptr < &ptrs.start->ptr ||
|
||||
ptr >= &ptrs.end->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,
|
||||
break;
|
||||
|
||||
if ((extent_entry_is_crc(entry) && drop_crc) ||
|
||||
extent_entry_is_stripe_ptr(entry)) {
|
||||
ret = (void *) ret - extent_entry_bytes(entry);
|
||||
extent_entry_is_stripe_ptr(entry))
|
||||
extent_entry_drop(k, entry);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
union bch_extent_entry *bch2_bkey_drop_ptr(struct bkey_s k,
|
||||
struct bch_extent_ptr *ptr)
|
||||
void bch2_bkey_drop_ptr(struct bkey_s k, struct bch_extent_ptr *ptr)
|
||||
{
|
||||
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
|
||||
@ -837,14 +835,10 @@ union bch_extent_entry *bch2_bkey_drop_ptr(struct bkey_s k,
|
||||
!bch2_bkey_dirty_devs(k.s_c).nr) {
|
||||
k.k->type = KEY_TYPE_error;
|
||||
set_bkey_val_u64s(k.k, 0);
|
||||
ret = NULL;
|
||||
} else if (!bch2_bkey_nr_ptrs(k.s_c)) {
|
||||
k.k->type = KEY_TYPE_deleted;
|
||||
set_bkey_val_u64s(k.k, 0);
|
||||
ret = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
void bch2_extent_ptr_decoded_append(struct bkey_i *,
|
||||
struct extent_ptr_decoded *);
|
||||
union bch_extent_entry *bch2_bkey_drop_ptr_noerror(struct bkey_s,
|
||||
struct bch_extent_ptr *);
|
||||
union bch_extent_entry *bch2_bkey_drop_ptr(struct bkey_s,
|
||||
struct bch_extent_ptr *);
|
||||
void bch2_bkey_drop_ptr_noerror(struct bkey_s, struct bch_extent_ptr *);
|
||||
void bch2_bkey_drop_ptr(struct bkey_s, struct bch_extent_ptr *);
|
||||
|
||||
#define bch2_bkey_drop_ptrs(_k, _ptr, _cond) \
|
||||
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; \
|
||||
\
|
||||
while ((_ptr = bkey_ptr_next(_ptrs, _ptr))) { \
|
||||
bkey_for_each_ptr(_ptrs, _ptr) \
|
||||
if (_cond) { \
|
||||
_ptr = (void *) bch2_bkey_drop_ptr(_k, _ptr); \
|
||||
_ptrs = bch2_bkey_ptrs(_k); \
|
||||
continue; \
|
||||
bch2_bkey_drop_ptr(_k, _ptr); \
|
||||
goto _again; \
|
||||
} \
|
||||
\
|
||||
(_ptr)++; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
bool bch2_bkey_matches_ptr(struct bch_fs *, struct bkey_s_c,
|
||||
|
||||
@ -177,6 +177,14 @@ static unsigned bch2_inode_hash(subvol_inum inum)
|
||||
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)
|
||||
{
|
||||
subvol_inum inum = inode_inum(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
|
||||
* btree inode may be inconsistent:
|
||||
@ -194,6 +196,11 @@ int bch2_vfs_init(void);
|
||||
|
||||
#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,
|
||||
snapshot_id_list *s) {}
|
||||
static inline void bch2_vfs_exit(void) {}
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include "darray.h"
|
||||
#include "dirent.h"
|
||||
#include "error.h"
|
||||
#include "fs.h"
|
||||
#include "fs-common.h"
|
||||
#include "fsck.h"
|
||||
#include "inode.h"
|
||||
@ -962,6 +963,22 @@ fsck_err:
|
||||
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,
|
||||
struct btree_iter *iter,
|
||||
struct bkey_s_c k,
|
||||
@ -1040,6 +1057,7 @@ static int check_inode(struct btree_trans *trans,
|
||||
}
|
||||
|
||||
if (u.bi_flags & BCH_INODE_unlinked &&
|
||||
!bch2_inode_open(c, k.k->p) &&
|
||||
(!c->sb.clean ||
|
||||
fsck_err(trans, inode_unlinked_but_clean,
|
||||
"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,
|
||||
nr_online += test_bit(e->devs[i], devs.d);
|
||||
|
||||
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();
|
||||
|
||||
|
||||
@ -461,7 +461,7 @@ STORE(bch2_fs)
|
||||
|
||||
sc.gfp_mask = GFP_KERNEL;
|
||||
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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user