Commit 405a41d7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'locking-urgent-2025-02-28' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull locking fix from Ingo Molnar:
 "Fix an rcuref_put() slowpath race"

* tag 'locking-urgent-2025-02-28' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  rcuref: Plug slowpath race in rcuref_put()
parents 5c44ddaf b9a49520
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -71,27 +71,30 @@ static inline __must_check bool rcuref_get(rcuref_t *ref)
	return rcuref_get_slowpath(ref);
}

extern __must_check bool rcuref_put_slowpath(rcuref_t *ref);
extern __must_check bool rcuref_put_slowpath(rcuref_t *ref, unsigned int cnt);

/*
 * Internal helper. Do not invoke directly.
 */
static __always_inline __must_check bool __rcuref_put(rcuref_t *ref)
{
	int cnt;

	RCU_LOCKDEP_WARN(!rcu_read_lock_held() && preemptible(),
			 "suspicious rcuref_put_rcusafe() usage");
	/*
	 * Unconditionally decrease the reference count. The saturation and
	 * dead zones provide enough tolerance for this.
	 */
	if (likely(!atomic_add_negative_release(-1, &ref->refcnt)))
	cnt = atomic_sub_return_release(1, &ref->refcnt);
	if (likely(cnt >= 0))
		return false;

	/*
	 * Handle the last reference drop and cases inside the saturation
	 * and dead zones.
	 */
	return rcuref_put_slowpath(ref);
	return rcuref_put_slowpath(ref, cnt);
}

/**
+2 −3
Original line number Diff line number Diff line
@@ -220,6 +220,7 @@ EXPORT_SYMBOL_GPL(rcuref_get_slowpath);
/**
 * rcuref_put_slowpath - Slowpath of __rcuref_put()
 * @ref:	Pointer to the reference count
 * @cnt:	The resulting value of the fastpath decrement
 *
 * Invoked when the reference count is outside of the valid zone.
 *
@@ -233,10 +234,8 @@ EXPORT_SYMBOL_GPL(rcuref_get_slowpath);
 *	with a concurrent get()/put() pair. Caller is not allowed to
 *	deconstruct the protected object.
 */
bool rcuref_put_slowpath(rcuref_t *ref)
bool rcuref_put_slowpath(rcuref_t *ref, unsigned int cnt)
{
	unsigned int cnt = atomic_read(&ref->refcnt);

	/* Did this drop the last reference? */
	if (likely(cnt == RCUREF_NOREF)) {
		/*