[PATCH] pi-futex: robust-futex exit crash fix

Fix pi_state->list handling bugs: list handling mishap, locking error.
Plus add more debug checks and fix a few style issues i noticed while
debugging this.

(reported by Ulrich Drepper and Jakub Jelinek.)

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Ingo Molnar and committed by Linus Torvalds 627371d7 c97d20a6

+24 -8
+24 -8
kernel/futex.c
··· 415 */ 416 void exit_pi_state_list(struct task_struct *curr) 417 { 418 - struct futex_hash_bucket *hb; 419 struct list_head *next, *head = &curr->pi_state_list; 420 struct futex_pi_state *pi_state; 421 union futex_key key; 422 423 /* 424 * We are a ZOMBIE and nobody can enqueue itself on 425 * pi_state_list anymore, but we have to be careful 426 - * versus waiters unqueueing themselfs 427 */ 428 spin_lock_irq(&curr->pi_lock); 429 while (!list_empty(head)) { ··· 431 next = head->next; 432 pi_state = list_entry(next, struct futex_pi_state, list); 433 key = pi_state->key; 434 spin_unlock_irq(&curr->pi_lock); 435 436 - hb = hash_futex(&key); 437 spin_lock(&hb->lock); 438 439 spin_lock_irq(&curr->pi_lock); 440 if (head->next != next) { 441 spin_unlock(&hb->lock); 442 continue; 443 } 444 445 - list_del_init(&pi_state->list); 446 - 447 WARN_ON(pi_state->owner != curr); 448 - 449 pi_state->owner = NULL; 450 spin_unlock_irq(&curr->pi_lock); 451 ··· 473 head = &hb->chain; 474 475 list_for_each_entry_safe(this, next, head, list) { 476 - if (match_futex (&this->key, &me->key)) { 477 /* 478 * Another waiter already exists - bump up 479 * the refcount and return its pi_state: ··· 484 */ 485 if (unlikely(!pi_state)) 486 return -EINVAL; 487 488 atomic_inc(&pi_state->refcount); 489 me->pi_state = pi_state; ··· 515 pi_state->key = me->key; 516 517 spin_lock_irq(&p->pi_lock); 518 list_add(&pi_state->list, &p->pi_state_list); 519 pi_state->owner = p; 520 spin_unlock_irq(&p->pi_lock); ··· 590 if (curval != uval) 591 return -EINVAL; 592 593 - list_del_init(&pi_state->owner->pi_state_list); 594 list_add(&pi_state->list, &new_owner->pi_state_list); 595 pi_state->owner = new_owner; 596 rt_mutex_unlock(&pi_state->pi_mutex); 597 598 return 0; ··· 1250 /* Owner died? */ 1251 if (q.pi_state->owner != NULL) { 1252 spin_lock_irq(&q.pi_state->owner->pi_lock); 1253 list_del_init(&q.pi_state->list); 1254 spin_unlock_irq(&q.pi_state->owner->pi_lock); 1255 } else ··· 1259 q.pi_state->owner = current; 1260 1261 spin_lock_irq(&current->pi_lock); 1262 list_add(&q.pi_state->list, &current->pi_state_list); 1263 spin_unlock_irq(&current->pi_lock); 1264
··· 415 */ 416 void exit_pi_state_list(struct task_struct *curr) 417 { 418 struct list_head *next, *head = &curr->pi_state_list; 419 struct futex_pi_state *pi_state; 420 + struct futex_hash_bucket *hb; 421 union futex_key key; 422 423 /* 424 * We are a ZOMBIE and nobody can enqueue itself on 425 * pi_state_list anymore, but we have to be careful 426 + * versus waiters unqueueing themselves: 427 */ 428 spin_lock_irq(&curr->pi_lock); 429 while (!list_empty(head)) { ··· 431 next = head->next; 432 pi_state = list_entry(next, struct futex_pi_state, list); 433 key = pi_state->key; 434 + hb = hash_futex(&key); 435 spin_unlock_irq(&curr->pi_lock); 436 437 spin_lock(&hb->lock); 438 439 spin_lock_irq(&curr->pi_lock); 440 + /* 441 + * We dropped the pi-lock, so re-check whether this 442 + * task still owns the PI-state: 443 + */ 444 if (head->next != next) { 445 spin_unlock(&hb->lock); 446 continue; 447 } 448 449 WARN_ON(pi_state->owner != curr); 450 + WARN_ON(list_empty(&pi_state->list)); 451 + list_del_init(&pi_state->list); 452 pi_state->owner = NULL; 453 spin_unlock_irq(&curr->pi_lock); 454 ··· 470 head = &hb->chain; 471 472 list_for_each_entry_safe(this, next, head, list) { 473 + if (match_futex(&this->key, &me->key)) { 474 /* 475 * Another waiter already exists - bump up 476 * the refcount and return its pi_state: ··· 481 */ 482 if (unlikely(!pi_state)) 483 return -EINVAL; 484 + 485 + WARN_ON(!atomic_read(&pi_state->refcount)); 486 487 atomic_inc(&pi_state->refcount); 488 me->pi_state = pi_state; ··· 510 pi_state->key = me->key; 511 512 spin_lock_irq(&p->pi_lock); 513 + WARN_ON(!list_empty(&pi_state->list)); 514 list_add(&pi_state->list, &p->pi_state_list); 515 pi_state->owner = p; 516 spin_unlock_irq(&p->pi_lock); ··· 584 if (curval != uval) 585 return -EINVAL; 586 587 + spin_lock_irq(&pi_state->owner->pi_lock); 588 + WARN_ON(list_empty(&pi_state->list)); 589 + list_del_init(&pi_state->list); 590 + spin_unlock_irq(&pi_state->owner->pi_lock); 591 + 592 + spin_lock_irq(&new_owner->pi_lock); 593 + WARN_ON(!list_empty(&pi_state->list)); 594 list_add(&pi_state->list, &new_owner->pi_state_list); 595 pi_state->owner = new_owner; 596 + spin_unlock_irq(&new_owner->pi_lock); 597 + 598 rt_mutex_unlock(&pi_state->pi_mutex); 599 600 return 0; ··· 1236 /* Owner died? */ 1237 if (q.pi_state->owner != NULL) { 1238 spin_lock_irq(&q.pi_state->owner->pi_lock); 1239 + WARN_ON(list_empty(&q.pi_state->list)); 1240 list_del_init(&q.pi_state->list); 1241 spin_unlock_irq(&q.pi_state->owner->pi_lock); 1242 } else ··· 1244 q.pi_state->owner = current; 1245 1246 spin_lock_irq(&current->pi_lock); 1247 + WARN_ON(!list_empty(&q.pi_state->list)); 1248 list_add(&q.pi_state->list, &current->pi_state_list); 1249 spin_unlock_irq(&current->pi_lock); 1250