Commit 6b63a948 authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: Add missing wakeup to bch2_inode_hash_remove()

This fixes two different bugs:

- Looser locking with the rhashtable means we need to recheck if the
  inode is still hashed after prepare_to_wait(), and add a corresponding
  wakeup after removing from the hash table.

- da18ecbf ("fs: add i_state helpers") changed the bit waitqueues
  used for inodes, and bcachefs wasn't updated and thus broke; this
  updates bcachefs to the new helper.

Fixes: 112d21fd ("bcachefs: switch to rhashtable for vfs inodes hash")
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent d2878660
...@@ -174,20 +174,24 @@ static const struct rhashtable_params bch2_vfs_inodes_params = { ...@@ -174,20 +174,24 @@ static const struct rhashtable_params bch2_vfs_inodes_params = {
.automatic_shrinking = true, .automatic_shrinking = true,
}; };
static void __wait_on_freeing_inode(struct inode *inode) struct bch_inode_info *__bch2_inode_hash_find(struct bch_fs *c, subvol_inum inum)
{ {
wait_queue_head_t *wq; return rhashtable_lookup_fast(&c->vfs_inodes_table, &inum, bch2_vfs_inodes_params);
DEFINE_WAIT_BIT(wait, &inode->i_state, __I_NEW);
wq = bit_waitqueue(&inode->i_state, __I_NEW);
prepare_to_wait(wq, &wait.wq_entry, TASK_UNINTERRUPTIBLE);
spin_unlock(&inode->i_lock);
schedule();
finish_wait(wq, &wait.wq_entry);
} }
struct bch_inode_info *__bch2_inode_hash_find(struct bch_fs *c, subvol_inum inum) static void __wait_on_freeing_inode(struct bch_fs *c,
struct bch_inode_info *inode,
subvol_inum inum)
{ {
return rhashtable_lookup_fast(&c->vfs_inodes_table, &inum, bch2_vfs_inodes_params); wait_queue_head_t *wq;
DEFINE_WAIT_BIT(wait, &inode->v.i_state, __I_NEW);
wq = inode_bit_waitqueue(&wait, &inode->v, __I_NEW);
prepare_to_wait(wq, &wait.wq_entry, TASK_UNINTERRUPTIBLE);
spin_unlock(&inode->v.i_lock);
if (__bch2_inode_hash_find(c, inum) == inode)
schedule_timeout(HZ * 10);
finish_wait(wq, &wait.wq_entry);
} }
static struct bch_inode_info *bch2_inode_hash_find(struct bch_fs *c, struct btree_trans *trans, static struct bch_inode_info *bch2_inode_hash_find(struct bch_fs *c, struct btree_trans *trans,
...@@ -204,10 +208,10 @@ static struct bch_inode_info *bch2_inode_hash_find(struct bch_fs *c, struct btre ...@@ -204,10 +208,10 @@ static struct bch_inode_info *bch2_inode_hash_find(struct bch_fs *c, struct btre
} }
if ((inode->v.i_state & (I_FREEING|I_WILL_FREE))) { if ((inode->v.i_state & (I_FREEING|I_WILL_FREE))) {
if (!trans) { if (!trans) {
__wait_on_freeing_inode(&inode->v); __wait_on_freeing_inode(c, inode, inum);
} else { } else {
bch2_trans_unlock(trans); bch2_trans_unlock(trans);
__wait_on_freeing_inode(&inode->v); __wait_on_freeing_inode(c, inode, inum);
int ret = bch2_trans_relock(trans); int ret = bch2_trans_relock(trans);
if (ret) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -232,6 +236,11 @@ static void bch2_inode_hash_remove(struct bch_fs *c, struct bch_inode_info *inod ...@@ -232,6 +236,11 @@ static void bch2_inode_hash_remove(struct bch_fs *c, struct bch_inode_info *inod
&inode->hash, bch2_vfs_inodes_params); &inode->hash, bch2_vfs_inodes_params);
BUG_ON(ret); BUG_ON(ret);
inode->v.i_hash.pprev = NULL; inode->v.i_hash.pprev = NULL;
/*
* This pairs with the bch2_inode_hash_find() ->
* __wait_on_freeing_inode() path
*/
inode_wake_up_bit(&inode->v, __I_NEW);
} }
} }
......
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