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

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
Loading
Loading
Loading
Loading
+21 −12
Original line number Diff line number Diff line
@@ -174,20 +174,24 @@ static const struct rhashtable_params bch2_vfs_inodes_params = {
	.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;
	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);
	return rhashtable_lookup_fast(&c->vfs_inodes_table, &inum, bch2_vfs_inodes_params);
}

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,
@@ -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 (!trans) {
				__wait_on_freeing_inode(&inode->v);
				__wait_on_freeing_inode(c, inode, inum);
			} else {
				bch2_trans_unlock(trans);
				__wait_on_freeing_inode(&inode->v);
				__wait_on_freeing_inode(c, inode, inum);
				int ret = bch2_trans_relock(trans);
				if (ret)
					return ERR_PTR(ret);
@@ -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);
		BUG_ON(ret);
		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);
	}
}