Commit 1edfe4ea authored by Tejun Heo's avatar Tejun Heo Committed by Greg Kroah-Hartman
Browse files

kernfs: Fix spurious lockdep warning in kernfs_find_and_get_node_by_id()

c2549174 ("kernfs: Add KERNFS_REMOVING flags") made
kernfs_find_and_get_node_by_id() test kernfs_active() instead of
KERNFS_ACTIVATED. kernfs_find_and_get_by_id() is called without holding the
kernfs_rwsem triggering the following lockdep warning.

  WARNING: CPU: 1 PID: 6191 at fs/kernfs/dir.c:36 kernfs_active+0xe8/0x120 fs/kernfs/dir.c:38
  Modules linked in:
  CPU: 1 PID: 6191 Comm: syz-executor.1 Not tainted 6.0.0-syzkaller-09413-g4899a36f91a9 #0
  Hardware name: linux,dummy-virt (DT)
  pstate: 10000005 (nzcV daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
  pc : kernfs_active+0xe8/0x120 fs/kernfs/dir.c:36
  lr : lock_is_held include/linux/lockdep.h:283 [inline]
  lr : kernfs_active+0x94/0x120 fs/kernfs/dir.c:36
  sp : ffff8000182c7a00
  x29: ffff8000182c7a00 x28: 0000000000000002 x27: 0000000000000001
  x26: ffff00000ee1f6a8 x25: 1fffe00001dc3ed5 x24: 0000000000000000
  x23: ffff80000ca1fba0 x22: ffff8000089efcb0 x21: 0000000000000...
parent 54de93cd
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -31,10 +31,15 @@ static DEFINE_SPINLOCK(kernfs_idr_lock); /* root->ino_idr */

#define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb)

static bool __kernfs_active(struct kernfs_node *kn)
{
	return atomic_read(&kn->active) >= 0;
}

static bool kernfs_active(struct kernfs_node *kn)
{
	lockdep_assert_held(&kernfs_root(kn)->kernfs_rwsem);
	return atomic_read(&kn->active) >= 0;
	return __kernfs_active(kn);
}

static bool kernfs_lockdep(struct kernfs_node *kn)
@@ -705,7 +710,12 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root,
			goto err_unlock;
	}

	if (unlikely(!kernfs_active(kn) || !atomic_inc_not_zero(&kn->count)))
	/*
	 * We should fail if @kn has never been activated and guarantee success
	 * if the caller knows that @kn is active. Both can be achieved by
	 * __kernfs_active() which tests @kn->active without kernfs_rwsem.
	 */
	if (unlikely(!__kernfs_active(kn) || !atomic_inc_not_zero(&kn->count)))
		goto err_unlock;

	spin_unlock(&kernfs_idr_lock);