use schedule_timeout_uninterruptible in nv_sleep_ms()

nv_sleep_ms() function sets current process to TASK_INTERRUPTIBLE and call
schedule_timeout() in a while loop until less than a jiffie remains. It retains
in the loop regardless of whether signal is received. What's worse, process in
TASK_INTERRUPTIBLE state with pending signal would be set back to TASK_RUNNING
in __schedule() function, thus it would be rescheduled again and again, never
get into sleep state.

For example, processes calling nv_pci_remove() to remove a device which is still
in use would stuck in the sleep-check loop until usage_count down do zero.
Once SIGKILL received, it would remain in TASK_RUNNING, leading to a CPU usage
at 100%.

Instead, use schedule_timeout_uninterruptible() to substitute the while loop in
nv_sleep_ms(). The process would not be woken up only when the requested timeout
has expired.

Signed-off-by: huteng.ht <huteng.ht@bytedance.com>
This commit is contained in:
huteng.ht 2022-11-25 13:58:43 +08:00
parent 758b4ee818
commit 1379f5c758

View File

@ -210,23 +210,18 @@ static inline NV_STATUS nv_sleep_ms(unsigned int ms)
{
//
// If we have at least one full jiffy to wait, give up
// up the CPU; since we may be rescheduled before
// the requested timeout has expired, loop until less
// the CPU until the requested timeout has expired and less
// than a jiffie of the desired delay remains.
//
set_current_state(TASK_INTERRUPTIBLE);
do
schedule_timeout_uninterruptible(jiffies);
ktime_get_real_ts64(&tm_aux);
if (nv_timer_less_than(&tm_aux, &tm_end))
{
schedule_timeout(jiffies);
ktime_get_raw_ts64(&tm_aux);
if (nv_timer_less_than(&tm_aux, &tm_end))
{
tm_aux = timespec64_sub(tm_end, tm_aux);
ns = (NvU64) timespec64_to_ns(&tm_aux);
}
else
ns = 0;
} while ((jiffies = NV_NSECS_TO_JIFFIES(ns)) != 0);
tm_aux = timespec64_sub(tm_end, tm_aux);
ns = (NvU64) timespec64_to_ns(&tm_aux);
}
else
ns = 0;
}
if (ns > (NvU64) NSEC_PER_MSEC)