hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/ID8IIO ----------------------------------------- xsched_vsm_add_tail() previously relied on its caller (vstream_kick()) to hold vstream->stream_lock. In this call path, vstream_kick() acquired the spinlock and then invoked xsched_vsm_add_tail(), which performed a kmalloc(GFP_KERNEL) inside the spinlock region. This triggers the following warning: BUG: sleeping function called from invalid context __might_sleep+0x54/0xb0 kmem_cache_alloc_node(GFP_KERNEL) xsched_vsm_add_tail() vstream_kick() The root cause is that GFP_KERNEL allocations may sleep, but vstream->stream_lock is a spinlock and therefore an atomic context. Thus kmalloc() must not be executed while holding this lock. Fix this by: - moving spin_lock(&vs->stream_lock) into xsched_vsm_add_tail() - ensuring kmalloc(GFP_KERNEL) is done outside of the spinlock - keeping all list and kicks_count updates protected by stream_lock - removing stream_lock operations from vstream_kick() Fixes: 76c15076abcb ("xsched: Add basic scheduler core support") Signed-off-by: Zicheng Qu <quzicheng@huawei.com> --- kernel/xsched/core.c | 7 ++++++- kernel/xsched/vstream.c | 3 --- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/kernel/xsched/core.c b/kernel/xsched/core.c index f4a843acd5cd..69f1a442f985 100644 --- a/kernel/xsched/core.c +++ b/kernel/xsched/core.c @@ -315,7 +315,10 @@ int xsched_vsm_add_tail(struct vstream_info *vs, vstream_args_t *arg) return -ENOMEM; } + spin_lock(&vs->stream_lock); + if (vs->kicks_count > MAX_VSTREAM_SIZE) { + spin_unlock(&vs->stream_lock); kfree(new_vsm); return -EBUSY; } @@ -323,7 +326,9 @@ int xsched_vsm_add_tail(struct vstream_info *vs, vstream_args_t *arg) xsched_init_vsm(new_vsm, vs, arg); list_add_tail(&new_vsm->node, &vs->metadata_list); new_vsm->add_time = ktime_get(); - vs->kicks_count += 1; + vs->kicks_count++; + + spin_unlock(&vs->stream_lock); /* Increasing a total amount of kicks on an CU to which this * context is attached to based on sched_class. diff --git a/kernel/xsched/vstream.c b/kernel/xsched/vstream.c index 128a869738be..d0815e33e081 100644 --- a/kernel/xsched/vstream.c +++ b/kernel/xsched/vstream.c @@ -589,12 +589,10 @@ int vstream_kick(struct vstream_args *arg) do { mutex_lock(&xcu->xcu_lock); - spin_lock(&vstream->stream_lock); /* Adding kick metadata. */ err = xsched_vsm_add_tail(vstream, arg); if (err == -EBUSY) { - spin_unlock(&vstream->stream_lock); mutex_unlock(&xcu->xcu_lock); /* Retry after a while */ @@ -612,7 +610,6 @@ int vstream_kick(struct vstream_args *arg) enqueue_ctx(xse, xcu); } while (err == -EBUSY); - spin_unlock(&vstream->stream_lock); mutex_unlock(&xcu->xcu_lock); if (!err) wake_up_interruptible(&xcu->wq_xcu_idle); -- 2.34.1