Commit e7213ad6 authored by Zizhi Wo's avatar Zizhi Wo Committed by Baokun Li
Browse files

fscache: add a memory barrier for FSCACHE_COOKIE_LOOKING_UP

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IB5UKT



--------------------------------

Both fscache_object_lookup_negative() and fscache_obtained_object() call
clear_bit_unlock() and then wake_up_bit(). Although there are memory
barriers in clear_bit_unlock() to ensure that the memory order before it
is normal, but not to guarantee the order after it. And wake_up_bit() has
no memory order guarantee.

This will probably trigger a problem. Execute wake_up_bit() first to wake
up the waiting thread, but the cookie flag is not cleared. After that, the
wait thread detects that the flag still exists and will continue to sleep
to be awakened again. The wake thread then clears the bit, but there is no
wake operation, leaving mount waiting to be woken that blocking other
process.

Fix this issue by using clear_and_wake_up_bit() to adding a memory barrier
between clearing the flag and waking. In addition, we also need to ensure
the memory order of the wait side, so use wait_on_bit_acquire().

Fixes: caaef690 ("FS-Cache: Fix object state machine to have separate work and wait states")
Signed-off-by: default avatarZizhi Wo <wozizhi@huawei.com>
Signed-off-by: default avatarBaokun Li <libaokun1@huawei.com>
parent e1e05a2a
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -518,7 +518,7 @@ static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie,
	/* we may be required to wait for lookup to complete at this point */
	if (!fscache_defer_lookup) {
		_debug("non-deferred lookup %p", &cookie->flags);
		wait_on_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP,
		wait_on_bit_acquire(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP,
				    TASK_UNINTERRUPTIBLE);
		_debug("complete");
		if (test_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags))
+2 −4
Original line number Diff line number Diff line
@@ -521,8 +521,7 @@ void fscache_object_lookup_negative(struct fscache_object *object)
		clear_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags);

		_debug("wake up lookup %p", &cookie->flags);
		clear_bit_unlock(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags);
		wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP);
		clear_and_wake_up_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags);
	}
	_leave("");
}
@@ -556,8 +555,7 @@ void fscache_obtained_object(struct fscache_object *object)
		/* Allow write requests to begin stacking up and read requests
		 * to begin shovelling data.
		 */
		clear_bit_unlock(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags);
		wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP);
		clear_and_wake_up_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags);
	} else {
		fscache_stat(&fscache_n_object_created);
	}
+2 −2
Original line number Diff line number Diff line
@@ -352,7 +352,7 @@ int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie)
	fscache_stat(&fscache_n_retrievals_wait);

	jif = jiffies;
	if (wait_on_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP,
	if (wait_on_bit_acquire(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP,
				TASK_INTERRUPTIBLE) != 0) {
		fscache_stat(&fscache_n_retrievals_intr);
		_leave(" = -ERESTARTSYS");