diff options
| author | Ingo Molnar <mingo@elte.hu> | 2006-07-29 05:17:57 +0200 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-28 21:02:00 -0700 | 
| commit | e3f2ddeac718c768fdac4b7fe69d465172f788a8 (patch) | |
| tree | 5428532dc6c87710c35a71858425f6d726f0e44c /kernel/futex_compat.c | |
| parent | 627371d73cdd04ed23fe098755b4f855138ad9e0 (diff) | |
| download | olio-linux-3.10-e3f2ddeac718c768fdac4b7fe69d465172f788a8.tar.xz olio-linux-3.10-e3f2ddeac718c768fdac4b7fe69d465172f788a8.zip  | |
[PATCH] pi-futex: robust-futex exit
Fix robust PI-futexes to be properly unlocked on unexpected exit.
For this to work the kernel has to know whether a futex is a PI or a
non-PI one, because the semantics are different.  Since the space in
relevant glibc data structures is extremely scarce, the best solution is
to encode the 'PI' information in bit 0 of the robust list pointer.
Existing (non-PI) glibc robust futexes have this bit always zero, so the
ABI is kept.  New glibc with PI-robust-futexes will set this bit.
Further fixes from Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Ulrich Drepper <drepper@redhat.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/futex_compat.c')
| -rw-r--r-- | kernel/futex_compat.c | 34 | 
1 files changed, 25 insertions, 9 deletions
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c index d1d92b441fb..d1aab1a452c 100644 --- a/kernel/futex_compat.c +++ b/kernel/futex_compat.c @@ -12,6 +12,23 @@  #include <asm/uaccess.h> + +/* + * Fetch a robust-list pointer. Bit 0 signals PI futexes: + */ +static inline int +fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry, +		   compat_uptr_t *head, int *pi) +{ +	if (get_user(*uentry, head)) +		return -EFAULT; + +	*entry = compat_ptr((*uentry) & ~1); +	*pi = (unsigned int)(*uentry) & 1; + +	return 0; +} +  /*   * Walk curr->robust_list (very carefully, it's a userspace list!)   * and mark any locks found there dead, and notify any waiters. @@ -22,17 +39,16 @@ void compat_exit_robust_list(struct task_struct *curr)  {  	struct compat_robust_list_head __user *head = curr->compat_robust_list;  	struct robust_list __user *entry, *pending; +	unsigned int limit = ROBUST_LIST_LIMIT, pi;  	compat_uptr_t uentry, upending; -	unsigned int limit = ROBUST_LIST_LIMIT;  	compat_long_t futex_offset;  	/*  	 * Fetch the list head (which was registered earlier, via  	 * sys_set_robust_list()):  	 */ -	if (get_user(uentry, &head->list.next)) +	if (fetch_robust_entry(&uentry, &entry, &head->list.next, &pi))  		return; -	entry = compat_ptr(uentry);  	/*  	 * Fetch the relative futex offset:  	 */ @@ -42,11 +58,11 @@ void compat_exit_robust_list(struct task_struct *curr)  	 * Fetch any possibly pending lock-add first, and handle it  	 * if it exists:  	 */ -	if (get_user(upending, &head->list_op_pending)) +	if (fetch_robust_entry(&upending, &pending, +			       &head->list_op_pending, &pi))  		return; -	pending = compat_ptr(upending);  	if (upending) -		handle_futex_death((void *)pending + futex_offset, curr); +		handle_futex_death((void *)pending + futex_offset, curr, pi);  	while (compat_ptr(uentry) != &head->list) {  		/* @@ -55,15 +71,15 @@ void compat_exit_robust_list(struct task_struct *curr)  		 */  		if (entry != pending)  			if (handle_futex_death((void *)entry + futex_offset, -						curr)) +						curr, pi))  				return;  		/*  		 * Fetch the next entry in the list:  		 */ -		if (get_user(uentry, (compat_uptr_t *)&entry->next)) +		if (fetch_robust_entry(&uentry, &entry, +				       (compat_uptr_t *)&entry->next, &pi))  			return; -		entry = compat_ptr(uentry);  		/*  		 * Avoid excessively long or circular lists:  		 */  |