futex: get_futex_key, get_key_refs and drop_key_refs

lguest uses the convenient futex infrastructure for inter-domain I/O, so
expose get_futex_key, get_key_refs (renamed get_futex_key_refs) and
drop_key_refs (renamed drop_futex_key_refs).  Also means we need to expose the
union that these use.

No code changes.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Rusty Russell 2007-05-08 00:26:42 -07:00 committed by Linus Torvalds
parent aa5bd7e929
commit 9adef58b1d
2 changed files with 43 additions and 36 deletions

View File

@ -100,6 +100,35 @@ long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout,
extern int extern int
handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi); handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi);
/*
* Futexes are matched on equal values of this key.
* The key type depends on whether it's a shared or private mapping.
* Don't rearrange members without looking at hash_futex().
*
* offset is aligned to a multiple of sizeof(u32) (== 4) by definition.
* We set bit 0 to indicate if it's an inode-based key.
*/
union futex_key {
struct {
unsigned long pgoff;
struct inode *inode;
int offset;
} shared;
struct {
unsigned long address;
struct mm_struct *mm;
int offset;
} private;
struct {
unsigned long word;
void *ptr;
int offset;
} both;
};
int get_futex_key(u32 __user *uaddr, union futex_key *key);
void get_futex_key_refs(union futex_key *key);
void drop_futex_key_refs(union futex_key *key);
#ifdef CONFIG_FUTEX #ifdef CONFIG_FUTEX
extern void exit_robust_list(struct task_struct *curr); extern void exit_robust_list(struct task_struct *curr);
extern void exit_pi_state_list(struct task_struct *curr); extern void exit_pi_state_list(struct task_struct *curr);

View File

@ -48,38 +48,13 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/module.h>
#include <asm/futex.h> #include <asm/futex.h>
#include "rtmutex_common.h" #include "rtmutex_common.h"
#define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8) #define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
/*
* Futexes are matched on equal values of this key.
* The key type depends on whether it's a shared or private mapping.
* Don't rearrange members without looking at hash_futex().
*
* offset is aligned to a multiple of sizeof(u32) (== 4) by definition.
* We set bit 0 to indicate if it's an inode-based key.
*/
union futex_key {
struct {
unsigned long pgoff;
struct inode *inode;
int offset;
} shared;
struct {
unsigned long address;
struct mm_struct *mm;
int offset;
} private;
struct {
unsigned long word;
void *ptr;
int offset;
} both;
};
/* /*
* Priority Inheritance state: * Priority Inheritance state:
*/ */
@ -175,7 +150,7 @@ static inline int match_futex(union futex_key *key1, union futex_key *key2)
* *
* Should be called with &current->mm->mmap_sem but NOT any spinlocks. * Should be called with &current->mm->mmap_sem but NOT any spinlocks.
*/ */
static int get_futex_key(u32 __user *uaddr, union futex_key *key) int get_futex_key(u32 __user *uaddr, union futex_key *key)
{ {
unsigned long address = (unsigned long)uaddr; unsigned long address = (unsigned long)uaddr;
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
@ -246,6 +221,7 @@ static int get_futex_key(u32 __user *uaddr, union futex_key *key)
} }
return err; return err;
} }
EXPORT_SYMBOL_GPL(get_futex_key);
/* /*
* Take a reference to the resource addressed by a key. * Take a reference to the resource addressed by a key.
@ -254,7 +230,7 @@ static int get_futex_key(u32 __user *uaddr, union futex_key *key)
* NOTE: mmap_sem MUST be held between get_futex_key() and calling this * NOTE: mmap_sem MUST be held between get_futex_key() and calling this
* function, if it is called at all. mmap_sem keeps key->shared.inode valid. * function, if it is called at all. mmap_sem keeps key->shared.inode valid.
*/ */
static inline void get_key_refs(union futex_key *key) inline void get_futex_key_refs(union futex_key *key)
{ {
if (key->both.ptr != 0) { if (key->both.ptr != 0) {
if (key->both.offset & 1) if (key->both.offset & 1)
@ -263,12 +239,13 @@ static inline void get_key_refs(union futex_key *key)
atomic_inc(&key->private.mm->mm_count); atomic_inc(&key->private.mm->mm_count);
} }
} }
EXPORT_SYMBOL_GPL(get_futex_key_refs);
/* /*
* Drop a reference to the resource addressed by a key. * Drop a reference to the resource addressed by a key.
* The hash bucket spinlock must not be held. * The hash bucket spinlock must not be held.
*/ */
static void drop_key_refs(union futex_key *key) void drop_futex_key_refs(union futex_key *key)
{ {
if (key->both.ptr != 0) { if (key->both.ptr != 0) {
if (key->both.offset & 1) if (key->both.offset & 1)
@ -277,6 +254,7 @@ static void drop_key_refs(union futex_key *key)
mmdrop(key->private.mm); mmdrop(key->private.mm);
} }
} }
EXPORT_SYMBOL_GPL(drop_futex_key_refs);
static inline int get_futex_value_locked(u32 *dest, u32 __user *from) static inline int get_futex_value_locked(u32 *dest, u32 __user *from)
{ {
@ -873,7 +851,7 @@ static int futex_requeue(u32 __user *uaddr1, u32 __user *uaddr2,
this->lock_ptr = &hb2->lock; this->lock_ptr = &hb2->lock;
} }
this->key = key2; this->key = key2;
get_key_refs(&key2); get_futex_key_refs(&key2);
drop_count++; drop_count++;
if (ret - nr_wake >= nr_requeue) if (ret - nr_wake >= nr_requeue)
@ -886,9 +864,9 @@ out_unlock:
if (hb1 != hb2) if (hb1 != hb2)
spin_unlock(&hb2->lock); spin_unlock(&hb2->lock);
/* drop_key_refs() must be called outside the spinlocks. */ /* drop_futex_key_refs() must be called outside the spinlocks. */
while (--drop_count >= 0) while (--drop_count >= 0)
drop_key_refs(&key1); drop_futex_key_refs(&key1);
out: out:
up_read(&current->mm->mmap_sem); up_read(&current->mm->mmap_sem);
@ -906,7 +884,7 @@ queue_lock(struct futex_q *q, int fd, struct file *filp)
init_waitqueue_head(&q->waiters); init_waitqueue_head(&q->waiters);
get_key_refs(&q->key); get_futex_key_refs(&q->key);
hb = hash_futex(&q->key); hb = hash_futex(&q->key);
q->lock_ptr = &hb->lock; q->lock_ptr = &hb->lock;
@ -925,7 +903,7 @@ static inline void
queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb) queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb)
{ {
spin_unlock(&hb->lock); spin_unlock(&hb->lock);
drop_key_refs(&q->key); drop_futex_key_refs(&q->key);
} }
/* /*
@ -980,7 +958,7 @@ static int unqueue_me(struct futex_q *q)
ret = 1; ret = 1;
} }
drop_key_refs(&q->key); drop_futex_key_refs(&q->key);
return ret; return ret;
} }
@ -999,7 +977,7 @@ static void unqueue_me_pi(struct futex_q *q, struct futex_hash_bucket *hb)
spin_unlock(&hb->lock); spin_unlock(&hb->lock);
drop_key_refs(&q->key); drop_futex_key_refs(&q->key);
} }
static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time) static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)