This fixes a livelock in the xprt->sending queue where we end up never making progress on lower priority tasks because sleep_on_priority() keeps adding new tasks with the same owner to the head of the queue, and priority bumps mean that we keep resetting the queue->owner to whatever task is at the head of the queue. Regression introduced by commit c05eecf636101dd4347b2d8fa457626bf0088e0a (SUNRPC: Don't allow low priority tasks to pre-empt higher priority ones).
Unified · Split
| @@ -98,9 +98,25 @@ __rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task) · 97 unmodified lines | ||
| 98 | 98 | list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list); |
| 99 | 99 | } |
| 100 | 100 | |
| 101 | +static void rpc_rotate_queue_owner(struct rpc_wait_queue *queue) | |
| 102 | +{ | |
| 103 | + struct list_head *q = &queue->tasks[queue->priority]; | |
| 104 | + struct rpc_task *task; | |
| 105 | + | |
| 106 | + if (!list_empty(q)) { | |
| 107 | + task = list_first_entry(q, struct rpc_task, u.tk_wait.list); | |
| 108 | + if (task->tk_owner == queue->owner) | |
| 109 | + list_move_tail(&task->u.tk_wait.list, q); | |
| 110 | + } | |
| 111 | +} | |
| 112 | + | |
| 101 | 113 | static void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority) |
| 102 | 114 | { |
| 103 | − queue->priority = priority; | |
| 115 | + if (queue->priority != priority) { | |
| 116 | + /* Fairness: rotate the list when changing priority */ | |
| 117 | + rpc_rotate_queue_owner(queue); | |
| 118 | + queue->priority = priority; | |
| 119 | + } | |
| 104 | 120 | } |
| 105 | 121 | |
| 106 | 122 | static void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid) |