hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IB5UKT
--------------------------------
If the parent is not ready when an object is initialized, it grabs a reference count of the object and adds it to the parent's dependents. When the parent is ready, it traverses the dependents to remove the object and reduce the reference count.
However, calling fscache_dequeue_object when ABORT_INIT only removes the object from the parent's dependents without decreasing the object's reference count, thus leading to reference count leakage. When releasing /dev/cachefiles, the following softlock up is triggered because it waits for the reference count to reach 0.
================================================================== INFO: task cachefilesd2:635 blocked for more than 122 seconds. Not tainted 5.10.0-xfstests-00004-g042dc94280ce-dirty #1321 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. task:cachefilesd2 state:D stack:0 pid:635 ppid:596 flags:0x00004006 Call Trace: __schedule+0x3cc/0x770 schedule+0x5b/0xd0 fscache_withdraw_cache+0x298/0x427 cachefiles_daemon_unbind.cold+0x18/0x69 [cachefiles] cachefiles_put_unbind_pincount+0x2a/0x60 [cachefiles] cachefiles_daemon_release+0x75/0x1e0 [cachefiles] __fput+0xe8/0x260 task_work_run+0x5f/0xb0 do_exit+0x381/0xbb0 [...] ==================================================================
So put the reference count of the object when removing it from the parent's dependents in fscache_dequeue_object() to fix the issue.
Signed-off-by: Baokun Li libaokun1@huawei.com --- fs/fscache/object.c | 1 + include/linux/fscache-cache.h | 1 + 2 files changed, 2 insertions(+)
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index cb2146e02cd5..9ce3041a5d71 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c @@ -904,6 +904,7 @@ static void fscache_dequeue_object(struct fscache_object *object) if (!list_empty(&object->dep_link)) { spin_lock(&object->parent->lock); list_del_init(&object->dep_link); + fscache_put_object(object, fscache_obj_put_dequeue); spin_unlock(&object->parent->lock); }
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index f3ae78d1e5f3..cb8be2d3143c 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h @@ -34,6 +34,7 @@ enum fscache_obj_ref_trace { fscache_obj_put_enq_dep, fscache_obj_put_queue, fscache_obj_put_work, + fscache_obj_put_dequeue, fscache_obj_ref__nr_traces };