From: Zizhi Wo wozizhi@huawei.com
Offering: HULK 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: caaef6900bef ("FS-Cache: Fix object state machine to have separate work and wait states") Signed-off-by: Zizhi Wo wozizhi@huawei.com Signed-off-by: Baokun Li libaokun1@huawei.com --- fs/fscache/cookie.c | 4 ++-- fs/fscache/object.c | 6 ++---- fs/fscache/page.c | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index c6e6d166cdb1..c2b1637eaa03 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c @@ -518,8 +518,8 @@ 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, - TASK_UNINTERRUPTIBLE); + wait_on_bit_acquire(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP, + TASK_UNINTERRUPTIBLE); _debug("complete"); if (test_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags)) goto unavailable; diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 11170f079d33..f05003bb743c 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c @@ -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); } diff --git a/fs/fscache/page.c b/fs/fscache/page.c index b08568743370..3ff3799e42ef 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -352,8 +352,8 @@ 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, - TASK_INTERRUPTIBLE) != 0) { + if (wait_on_bit_acquire(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP, + TASK_INTERRUPTIBLE) != 0) { fscache_stat(&fscache_n_retrievals_intr); _leave(" = -ERESTARTSYS"); return -ERESTARTSYS;