History

workqueue: fix possible stall on try_to_grab_pending() of a delayed work item

Currently, when try_to_grab_pending() grabs a delayed work item, it leaves its linked work items alone on the delayed_works. The linked work items are always NO_COLOR and will cause future cwq_activate_first_delayed() increase cwq->nr_active incorrectly, and may cause the whole cwq to stall. For example, state: cwq->max_active = 1, cwq->nr_active = 1 one work in cwq->pool, many in cwq->delayed_works. step1: try_to_grab_pending() removes a work item from delayed_works but leaves its NO_COLOR linked work items on it. step2: Later on, cwq_activate_first_delayed() activates the linked work item increasing ->nr_active. step3: cwq->nr_active = 1, but all activated work items of the cwq are NO_COLOR. When they finish, cwq->nr_active will not be decreased due to NO_COLOR, and no further work items will be activated from cwq->delayed_works. the cwq stalls. Fix it by ensuring the target work item is activated before stealing PENDING in try_to_grab_pending(). This ensures that all the linked work items are activated without incorrectly bumping cwq->nr_active. tj: Updated comment and description.

Lai Jiangshan committed 14 years ago

Commit 3aa62491 parent a5b4e571 file · +22 −3Browse files

Showing the changes to kernel/workqueue.c (1 of 1 file). Show all

Unified · Split

kernel/workqueue.c+22−3
@@ -977,10 +977,9 @@ static void move_linked_works(struct work_struct *work, struct list_head *head, · 976 unmodified lines
977 *nextp = n;977 *nextp = n;
978}978}
979 979
980static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq)980static void cwq_activate_delayed_work(struct work_struct *work)
981{981{
982 struct work_struct *work = list_first_entry(&cwq->delayed_works,982 struct cpu_workqueue_struct *cwq = get_work_cwq(work);
983 struct work_struct, entry);
984 983
985 trace_workqueue_activate_work(work);984 trace_workqueue_activate_work(work);
986 move_linked_works(work, &cwq->pool->worklist, NULL);985 move_linked_works(work, &cwq->pool->worklist, NULL);
@@ -988,6 +987,14 @@ static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq) · 1 unmodified line
988 cwq->nr_active++;987 cwq->nr_active++;
989}988}
990 989
990static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq)
991{
992 struct work_struct *work = list_first_entry(&cwq->delayed_works,
993 struct work_struct, entry);
994
995 cwq_activate_delayed_work(work);
996}
997
991/**998/**
992 * cwq_dec_nr_in_flight - decrement cwq's nr_in_flight999 * cwq_dec_nr_in_flight - decrement cwq's nr_in_flight
993 * @cwq: cwq of interest1000 * @cwq: cwq of interest
@@ -1106,6 +1113,18 @@ static int try_to_grab_pending(struct work_struct *work, bool is_dwork, · 112 unmodified lines
1106 smp_rmb();1113 smp_rmb();
1107 if (gcwq == get_work_gcwq(work)) {1114 if (gcwq == get_work_gcwq(work)) {
1108 debug_work_deactivate(work);1115 debug_work_deactivate(work);
1116
1117 /*
1118 * A delayed work item cannot be grabbed directly
1119 * because it might have linked NO_COLOR work items
1120 * which, if left on the delayed_list, will confuse
1121 * cwq->nr_active management later on and cause
1122 * stall. Make sure the work item is activated
1123 * before grabbing.
1124 */
1125 if (*work_data_bits(work) & WORK_STRUCT_DELAYED)
1126 cwq_activate_delayed_work(work);
1127
1109 list_del_init(&work->entry);1128 list_del_init(&work->entry);
1110 cwq_dec_nr_in_flight(get_work_cwq(work),1129 cwq_dec_nr_in_flight(get_work_cwq(work),
1111 get_work_color(work),1130 get_work_color(work),

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t