summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorPatrick Mochel <mochel@osdl.org>2003-09-04 21:12:36 -0700
committerPatrick Mochel <mochel@osdl.org>2003-09-04 21:12:36 -0700
commit110291f2d1d589e042d172c1b57777679abefe6d (patch)
treef558a06a925fcfc2fbcfcab45c8cde0eb76d9614 /kernel
parentf1a6400876c588497a5477cd642ead33fcbc7e81 (diff)
parent863003968458edf00e2ebdad49f68040203d886d (diff)
Merge osdl.org:/home/mochel/src/kernel/linux-2.5-virgin
into osdl.org:/home/mochel/src/kernel/linux-2.5-power
Diffstat (limited to 'kernel')
-rw-r--r--kernel/configs.c133
-rw-r--r--kernel/futex.c427
-rw-r--r--kernel/sysctl.c1
3 files changed, 279 insertions, 282 deletions
diff --git a/kernel/configs.c b/kernel/configs.c
index dd7acd64b214..7faf6837bfb2 100644
--- a/kernel/configs.c
+++ b/kernel/configs.c
@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/compile.h>
#include <linux/version.h>
@@ -41,75 +42,59 @@
/**************************************************/
/* globals and useful constants */
-static char *IKCONFIG_NAME = "ikconfig";
-static char *IKCONFIG_VERSION = "0.5";
+static const char IKCONFIG_NAME[] = "ikconfig";
+static const char IKCONFIG_VERSION[] = "0.6";
-static int ikconfig_current_size = 0;
-static struct proc_dir_entry *ikconfig_dir, *current_config, *built_with;
-
-static int
-ikconfig_permission_current(struct inode *inode, int op, struct nameidata *nd)
-{
- /* anyone can read the device, no one can write to it */
- return (op == MAY_READ) ? 0 : -EACCES;
-}
+static int ikconfig_size;
+static struct proc_dir_entry *ikconfig_dir;
static ssize_t
-ikconfig_output_current(struct file *file, char *buf,
- size_t len, loff_t * offset)
-{
- int i, limit;
- int cnt;
-
- limit = (ikconfig_current_size > len) ? len : ikconfig_current_size;
- for (i = file->f_pos, cnt = 0;
- i < ikconfig_current_size && cnt < limit; i++, cnt++) {
- if (put_user(ikconfig_config[i], buf + cnt))
- return -EFAULT;
- }
- file->f_pos = i;
- return cnt;
-}
-
-static int
-ikconfig_open_current(struct inode *inode, struct file *file)
-{
- if (file->f_mode & FMODE_READ) {
- inode->i_size = ikconfig_current_size;
- file->f_pos = 0;
- }
- return 0;
-}
-
-static int
-ikconfig_close_current(struct inode *inode, struct file *file)
+ikconfig_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
{
- return 0;
+ loff_t pos = *offset;
+ ssize_t count;
+
+ if (pos >= ikconfig_size)
+ return 0;
+
+ count = min(len, (size_t)(ikconfig_size - pos));
+ if(copy_to_user(buf, ikconfig_config + pos, count))
+ return -EFAULT;
+
+ *offset += count;
+ return count;
}
-static struct file_operations ikconfig_file_ops = {
- .read = ikconfig_output_current,
- .open = ikconfig_open_current,
- .release = ikconfig_close_current,
-};
-
-static struct inode_operations ikconfig_inode_ops = {
- .permission = ikconfig_permission_current,
+static struct file_operations config_fops = {
+ .owner = THIS_MODULE,
+ .read = ikconfig_read,
};
/***************************************************/
-/* proc_read_built_with: let people read the info */
+/* built_with_show: let people read the info */
/* we have on the tools used to build this kernel */
-static int
-proc_read_built_with(char *page, char **start,
- off_t off, int count, int *eof, void *data)
+static int builtwith_show(struct seq_file *seq, void *v)
+{
+ seq_printf(seq,
+ "Kernel: %s\nCompiler: %s\nVersion_in_Makefile: %s\n",
+ ikconfig_built_with, LINUX_COMPILER, UTS_RELEASE);
+ return 0;
+}
+
+static int built_with_open(struct inode *inode, struct file *file)
{
- *eof = 1;
- return sprintf(page,
- "Kernel: %s\nCompiler: %s\nVersion_in_Makefile: %s\n",
- ikconfig_built_with, LINUX_COMPILER, UTS_RELEASE);
+ return single_open(file, builtwith_show, PDE(inode)->data);
}
+
+static struct file_operations builtwith_fops = {
+ .owner = THIS_MODULE,
+ .open = built_with_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
/***************************************************/
/* ikconfig_init: start up everything we need to */
@@ -117,41 +102,33 @@ proc_read_built_with(char *page, char **start,
int __init
ikconfig_init(void)
{
- int result = 0;
+ struct proc_dir_entry *entry;
printk(KERN_INFO "ikconfig %s with /proc/ikconfig\n",
IKCONFIG_VERSION);
/* create the ikconfig directory */
ikconfig_dir = proc_mkdir(IKCONFIG_NAME, NULL);
- if (ikconfig_dir == NULL) {
- result = -ENOMEM;
+ if (ikconfig_dir == NULL)
goto leave;
- }
ikconfig_dir->owner = THIS_MODULE;
/* create the current config file */
- current_config = create_proc_entry("config", S_IFREG | S_IRUGO,
- ikconfig_dir);
- if (current_config == NULL) {
- result = -ENOMEM;
+ entry = create_proc_entry("config", S_IFREG | S_IRUGO, ikconfig_dir);
+ if (!entry)
goto leave2;
- }
- current_config->proc_iops = &ikconfig_inode_ops;
- current_config->proc_fops = &ikconfig_file_ops;
- current_config->owner = THIS_MODULE;
- ikconfig_current_size = strlen(ikconfig_config);
- current_config->size = ikconfig_current_size;
+
+ entry->proc_fops = &config_fops;
+ entry->size = ikconfig_size = strlen(ikconfig_config);
/* create the "built with" file */
- built_with = create_proc_read_entry("built_with", 0444, ikconfig_dir,
- proc_read_built_with, NULL);
- if (built_with == NULL) {
- result = -ENOMEM;
+ entry = create_proc_entry("built_with", S_IFREG | S_IRUGO,
+ ikconfig_dir);
+ if (!entry)
goto leave3;
- }
- built_with->owner = THIS_MODULE;
- goto leave;
+ entry->proc_fops = &builtwith_fops;
+
+ return 0;
leave3:
/* remove the file from proc */
@@ -162,7 +139,7 @@ leave2:
remove_proc_entry(IKCONFIG_NAME, NULL);
leave:
- return result;
+ return -ENOMEM;
}
/***************************************************/
diff --git a/kernel/futex.c b/kernel/futex.c
index 4557addfc6d6..a4feceee661a 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -5,6 +5,9 @@
* Generalized futexes, futex requeueing, misc fixes by Ingo Molnar
* (C) Copyright 2003 Red Hat Inc, All Rights Reserved
*
+ * Removed page pinning, fix privately mapped COW pages and other cleanups
+ * (C) Copyright 2003 Jamie Lokier
+ *
* Thanks to Ben LaHaise for yelling "hashed waitqueues" loudly
* enough at me, Linus for the original (flawed) idea, Matthew
* Kirkwood for proof-of-concept implementation.
@@ -33,12 +36,32 @@
#include <linux/hash.h>
#include <linux/init.h>
#include <linux/futex.h>
-#include <linux/vcache.h>
#include <linux/mount.h>
+#include <linux/pagemap.h>
#define FUTEX_HASHBITS 8
/*
+ * Futexes are matched on equal values of this key.
+ * The key type depends on whether it's a shared or private mapping.
+ */
+union futex_key {
+ struct {
+ unsigned long pgoff;
+ struct inode *inode;
+ } shared;
+ struct {
+ unsigned long uaddr;
+ struct mm_struct *mm;
+ } private;
+ struct {
+ unsigned long word;
+ void *ptr;
+ } both;
+ int offset;
+};
+
+/*
* We use this hashed waitqueue instead of a normal wait_queue_t, so
* we can wake only the relevant ones (hashed queues may be shared):
*/
@@ -46,12 +69,8 @@ struct futex_q {
struct list_head list;
wait_queue_head_t waiters;
- /* Page struct and offset within it. */
- struct page *page;
- int offset;
-
- /* the virtual => physical COW-safe cache */
- vcache_t vcache;
+ /* Key which the futex is hashed on. */
+ union futex_key key;
/* For fd, sigio sent using these. */
int fd;
@@ -66,111 +85,149 @@ static spinlock_t futex_lock = SPIN_LOCK_UNLOCKED;
static struct vfsmount *futex_mnt;
/*
- * These are all locks that are necessery to look up a physical
- * mapping safely, and modify/search the futex hash, atomically:
+ * We hash on the keys returned from get_futex_key (see below).
*/
-static inline void lock_futex_mm(void)
+static inline struct list_head *hash_futex(union futex_key *key)
{
- spin_lock(&current->mm->page_table_lock);
- spin_lock(&vcache_lock);
- spin_lock(&futex_lock);
-}
-
-static inline void unlock_futex_mm(void)
-{
- spin_unlock(&futex_lock);
- spin_unlock(&vcache_lock);
- spin_unlock(&current->mm->page_table_lock);
+ return &futex_queues[hash_long(key->both.word
+ + (unsigned long) key->both.ptr
+ + key->offset, FUTEX_HASHBITS)];
}
/*
- * The physical page is shared, so we can hash on its address:
+ * Return 1 if two futex_keys are equal, 0 otherwise.
*/
-static inline struct list_head *hash_futex(struct page *page, int offset)
+static inline int match_futex(union futex_key *key1, union futex_key *key2)
{
- return &futex_queues[hash_long((unsigned long)page + offset,
- FUTEX_HASHBITS)];
+ return (key1->both.word == key2->both.word
+ && key1->both.ptr == key2->both.ptr
+ && key1->offset == key2->offset);
}
/*
- * Get kernel address of the user page and pin it.
+ * Get parameters which are the keys for a futex.
+ *
+ * For shared mappings, it's (page->index, vma->vm_file->f_dentry->d_inode,
+ * offset_within_page). For private mappings, it's (uaddr, current->mm).
+ * We can usually work out the index without swapping in the page.
*
- * Must be called with (and returns with) all futex-MM locks held.
+ * Returns: 0, or negative error code.
+ * The key words are stored in *key on success.
+ *
+ * Should be called with &current->mm->mmap_sem,
+ * but NOT &futex_lock or &current->mm->page_table_lock.
*/
-static inline struct page *__pin_page_atomic (struct page *page)
-{
- if (!PageReserved(page))
- get_page(page);
- return page;
-}
-
-static struct page *__pin_page(unsigned long addr)
+static int get_futex_key(unsigned long uaddr, union futex_key *key)
{
struct mm_struct *mm = current->mm;
- struct page *page, *tmp;
+ struct vm_area_struct *vma;
+ struct page *page;
int err;
/*
- * Do a quick atomic lookup first - this is the fastpath.
+ * The futex address must be "naturally" aligned.
+ */
+ key->offset = uaddr % PAGE_SIZE;
+ if (unlikely((key->offset % sizeof(u32)) != 0))
+ return -EINVAL;
+ uaddr -= key->offset;
+
+ /*
+ * The futex is hashed differently depending on whether
+ * it's in a shared or private mapping. So check vma first.
+ */
+ vma = find_extend_vma(mm, uaddr);
+ if (unlikely(!vma))
+ return -EFAULT;
+
+ /*
+ * Permissions.
*/
- page = follow_page(mm, addr, 0);
- if (likely(page != NULL))
- return __pin_page_atomic(page);
+ if (unlikely((vma->vm_flags & (VM_IO|VM_READ)) != VM_READ))
+ return (vma->vm_flags & VM_IO) ? -EPERM : -EACCES;
/*
- * No luck - need to fault in the page:
+ * Private mappings are handled in a simple way.
+ *
+ * NOTE: When userspace waits on a MAP_SHARED mapping, even if
+ * it's a read-only handle, it's expected that futexes attach to
+ * the object not the particular process. Therefore we use
+ * VM_MAYSHARE here, not VM_SHARED which is restricted to shared
+ * mappings of _writable_ handles.
*/
-repeat_lookup:
+ if (likely(!(vma->vm_flags & VM_MAYSHARE))) {
+ key->private.mm = mm;
+ key->private.uaddr = uaddr;
+ return 0;
+ }
- unlock_futex_mm();
+ /*
+ * Linear mappings are also simple.
+ */
+ key->shared.inode = vma->vm_file->f_dentry->d_inode;
+ if (likely(!(vma->vm_flags & VM_NONLINEAR))) {
+ key->shared.pgoff = (((uaddr - vma->vm_start) >> PAGE_SHIFT)
+ + vma->vm_pgoff);
+ return 0;
+ }
- down_read(&mm->mmap_sem);
- err = get_user_pages(current, mm, addr, 1, 0, 0, &page, NULL);
- up_read(&mm->mmap_sem);
+ /*
+ * We could walk the page table to read the non-linear
+ * pte, and get the page index without fetching the page
+ * from swap. But that's a lot of code to duplicate here
+ * for a rare case, so we simply fetch the page.
+ */
- lock_futex_mm();
+ /*
+ * Do a quick atomic lookup first - this is the fastpath.
+ */
+ spin_lock(&current->mm->page_table_lock);
+ page = follow_page(mm, uaddr, 0);
+ if (likely(page != NULL)) {
+ key->shared.pgoff =
+ page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
+ spin_unlock(&current->mm->page_table_lock);
+ return 0;
+ }
+ spin_unlock(&current->mm->page_table_lock);
- if (err < 0)
- return NULL;
/*
- * Since the faulting happened with locks released, we have to
- * check for races:
+ * Do it the general way.
*/
- tmp = follow_page(mm, addr, 0);
- if (tmp != page) {
+ err = get_user_pages(current, mm, uaddr, 1, 0, 0, &page, NULL);
+ if (err >= 0) {
+ key->shared.pgoff =
+ page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
put_page(page);
- goto repeat_lookup;
}
-
- return page;
+ return err;
}
+
/*
* Wake up all waiters hashed on the physical page that is mapped
* to this virtual address:
*/
-static inline int futex_wake(unsigned long uaddr, int offset, int num)
+static inline int futex_wake(unsigned long uaddr, int num)
{
struct list_head *i, *next, *head;
- struct page *page;
- int ret = 0;
+ union futex_key key;
+ int ret;
- lock_futex_mm();
+ down_read(&current->mm->mmap_sem);
- page = __pin_page(uaddr - offset);
- if (!page) {
- unlock_futex_mm();
- return -EFAULT;
- }
+ ret = get_futex_key(uaddr, &key);
+ if (unlikely(ret != 0))
+ goto out;
- head = hash_futex(page, offset);
+ head = hash_futex(&key);
+ spin_lock(&futex_lock);
list_for_each_safe(i, next, head) {
struct futex_q *this = list_entry(i, struct futex_q, list);
- if (this->page == page && this->offset == offset) {
+ if (match_futex (&this->key, &key)) {
list_del_init(i);
- __detach_vcache(&this->vcache);
wake_up_all(&this->waiters);
if (this->filp)
send_sigio(&this->filp->f_owner, this->fd, POLL_IN);
@@ -179,113 +236,74 @@ static inline int futex_wake(unsigned long uaddr, int offset, int num)
break;
}
}
+ spin_unlock(&futex_lock);
- unlock_futex_mm();
- put_page(page);
-
+out:
+ up_read(&current->mm->mmap_sem);
return ret;
}
/*
- * This gets called by the COW code, we have to rehash any
- * futexes that were pending on the old physical page, and
- * rehash it to the new physical page. The pagetable_lock
- * and vcache_lock is already held:
- */
-static void futex_vcache_callback(vcache_t *vcache, struct page *new_page)
-{
- struct futex_q *q = container_of(vcache, struct futex_q, vcache);
- struct list_head *head = hash_futex(new_page, q->offset);
-
- spin_lock(&futex_lock);
-
- if (!list_empty(&q->list)) {
- put_page(q->page);
- q->page = new_page;
- __pin_page_atomic(new_page);
- list_del(&q->list);
- list_add_tail(&q->list, head);
- }
-
- spin_unlock(&futex_lock);
-}
-
-/*
* Requeue all waiters hashed on one physical page to another
* physical page.
*/
-static inline int futex_requeue(unsigned long uaddr1, int offset1,
- unsigned long uaddr2, int offset2, int nr_wake, int nr_requeue)
+static inline int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
+ int nr_wake, int nr_requeue)
{
struct list_head *i, *next, *head1, *head2;
- struct page *page1 = NULL, *page2 = NULL;
- int ret = 0;
+ union futex_key key1, key2;
+ int ret;
- lock_futex_mm();
+ down_read(&current->mm->mmap_sem);
- page1 = __pin_page(uaddr1 - offset1);
- if (!page1)
+ ret = get_futex_key(uaddr1, &key1);
+ if (unlikely(ret != 0))
goto out;
- page2 = __pin_page(uaddr2 - offset2);
- if (!page2)
+ ret = get_futex_key(uaddr2, &key2);
+ if (unlikely(ret != 0))
goto out;
- head1 = hash_futex(page1, offset1);
- head2 = hash_futex(page2, offset2);
+ head1 = hash_futex(&key1);
+ head2 = hash_futex(&key2);
+ spin_lock(&futex_lock);
list_for_each_safe(i, next, head1) {
struct futex_q *this = list_entry(i, struct futex_q, list);
- if (this->page == page1 && this->offset == offset1) {
+ if (match_futex (&this->key, &key1)) {
list_del_init(i);
- __detach_vcache(&this->vcache);
if (++ret <= nr_wake) {
wake_up_all(&this->waiters);
if (this->filp)
send_sigio(&this->filp->f_owner,
this->fd, POLL_IN);
} else {
- put_page(this->page);
- __pin_page_atomic (page2);
list_add_tail(i, head2);
- __attach_vcache(&this->vcache, uaddr2,
- current->mm, futex_vcache_callback);
- this->offset = offset2;
- this->page = page2;
+ this->key = key2;
if (ret - nr_wake >= nr_requeue)
break;
}
}
}
+ spin_unlock(&futex_lock);
out:
- unlock_futex_mm();
-
- if (page1)
- put_page(page1);
- if (page2)
- put_page(page2);
-
+ up_read(&current->mm->mmap_sem);
return ret;
}
-static inline void __queue_me(struct futex_q *q, struct page *page,
- unsigned long uaddr, int offset,
- int fd, struct file *filp)
+static inline void queue_me(struct futex_q *q, union futex_key *key,
+ int fd, struct file *filp)
{
- struct list_head *head = hash_futex(page, offset);
+ struct list_head *head = hash_futex(key);
- q->offset = offset;
+ q->key = *key;
q->fd = fd;
q->filp = filp;
- q->page = page;
+ spin_lock(&futex_lock);
list_add_tail(&q->list, head);
- /*
- * We register a futex callback to this virtual address,
- * to make sure a COW properly rehashes the futex-queue.
- */
- __attach_vcache(&q->vcache, uaddr, current->mm, futex_vcache_callback);
+ spin_unlock(&futex_lock);
}
/* Return 1 if we were still queued (ie. 0 means we were woken) */
@@ -293,83 +311,107 @@ static inline int unqueue_me(struct futex_q *q)
{
int ret = 0;
- spin_lock(&vcache_lock);
spin_lock(&futex_lock);
if (!list_empty(&q->list)) {
list_del(&q->list);
- __detach_vcache(&q->vcache);
ret = 1;
}
spin_unlock(&futex_lock);
- spin_unlock(&vcache_lock);
return ret;
}
-static inline int futex_wait(unsigned long uaddr,
- int offset,
- int val,
- unsigned long time)
+static inline int futex_wait(unsigned long uaddr, int val, unsigned long time)
{
DECLARE_WAITQUEUE(wait, current);
- int ret = 0, curval;
- struct page *page;
+ int ret, curval;
+ union futex_key key;
struct futex_q q;
+ try_again:
init_waitqueue_head(&q.waiters);
- lock_futex_mm();
+ down_read(&current->mm->mmap_sem);
- page = __pin_page(uaddr - offset);
- if (!page) {
- unlock_futex_mm();
- return -EFAULT;
- }
- __queue_me(&q, page, uaddr, offset, -1, NULL);
+ ret = get_futex_key(uaddr, &key);
+ if (unlikely(ret != 0))
+ goto out_release_sem;
+
+ queue_me(&q, &key, -1, NULL);
/*
- * Page is pinned, but may no longer be in this address space.
- * It cannot schedule, so we access it with the spinlock held.
+ * Access the page after the futex is queued.
+ * We hold the mmap semaphore, so the mapping cannot have changed
+ * since we looked it up.
*/
if (get_user(curval, (int *)uaddr) != 0) {
- unlock_futex_mm();
ret = -EFAULT;
- goto out;
+ goto out_unqueue;
}
if (curval != val) {
- unlock_futex_mm();
ret = -EWOULDBLOCK;
- goto out;
+ goto out_unqueue;
}
+
+ /*
+ * Now the futex is queued and we have checked the data, we
+ * don't want to hold mmap_sem while we sleep.
+ */
+ up_read(&current->mm->mmap_sem);
+
/*
- * The get_user() above might fault and schedule so we
- * cannot just set TASK_INTERRUPTIBLE state when queueing
- * ourselves into the futex hash. This code thus has to
+ * There might have been scheduling since the queue_me(), as we
+ * cannot hold a spinlock across the get_user() in case it
+ * faults. So we cannot just set TASK_INTERRUPTIBLE state when
+ * queueing ourselves into the futex hash. This code thus has to
* rely on the futex_wake() code doing a wakeup after removing
* the waiter from the list.
*/
add_wait_queue(&q.waiters, &wait);
+ spin_lock(&futex_lock);
set_current_state(TASK_INTERRUPTIBLE);
- if (!list_empty(&q.list)) {
- unlock_futex_mm();
- time = schedule_timeout(time);
+
+ if (unlikely(list_empty(&q.list))) {
+ /*
+ * We were woken already.
+ */
+ spin_unlock(&futex_lock);
+ set_current_state(TASK_RUNNING);
+ return 0;
}
+
+ spin_unlock(&futex_lock);
+ time = schedule_timeout(time);
set_current_state(TASK_RUNNING);
+
/*
* NOTE: we don't remove ourselves from the waitqueue because
* we are the only user of it.
*/
- if (time == 0) {
- ret = -ETIMEDOUT;
- goto out;
- }
+
+ /*
+ * Were we woken or interrupted for a valid reason?
+ */
+ ret = unqueue_me(&q);
+ if (ret == 0)
+ return 0;
+ if (time == 0)
+ return -ETIMEDOUT;
if (signal_pending(current))
- ret = -EINTR;
-out:
- /* Were we woken up anyway? */
+ return -EINTR;
+
+ /*
+ * No, it was a spurious wakeup. Try again. Should never happen. :)
+ */
+ goto try_again;
+
+ out_unqueue:
+ /*
+ * Were we unqueued anyway?
+ */
if (!unqueue_me(&q))
ret = 0;
- put_page(q.page);
-
+ out_release_sem:
+ up_read(&current->mm->mmap_sem);
return ret;
}
@@ -378,7 +420,6 @@ static int futex_close(struct inode *inode, struct file *filp)
struct futex_q *q = filp->private_data;
unqueue_me(q);
- put_page(q->page);
kfree(filp->private_data);
return 0;
}
@@ -406,12 +447,12 @@ static struct file_operations futex_fops = {
/* Signal allows caller to avoid the race which would occur if they
set the sigio stuff up afterwards. */
-static int futex_fd(unsigned long uaddr, int offset, int signal)
+static int futex_fd(unsigned long uaddr, int signal)
{
- struct page *page = NULL;
struct futex_q *q;
+ union futex_key key;
struct file *filp;
- int ret;
+ int ret, err;
ret = -EINVAL;
if (signal < 0 || signal > _NSIG)
@@ -450,69 +491,47 @@ static int futex_fd(unsigned long uaddr, int offset, int signal)
goto out;
}
- lock_futex_mm();
-
- page = __pin_page(uaddr - offset);
- if (!page) {
- unlock_futex_mm();
+ down_read(&current->mm->mmap_sem);
+ err = get_futex_key(uaddr, &key);
+ up_read(&current->mm->mmap_sem);
+ if (unlikely(err != 0)) {
put_unused_fd(ret);
put_filp(filp);
kfree(q);
- return -EFAULT;
+ return err;
}
init_waitqueue_head(&q->waiters);
filp->private_data = q;
- __queue_me(q, page, uaddr, offset, ret, filp);
-
- unlock_futex_mm();
+ queue_me(q, &key, ret, filp);
/* Now we map fd to filp, so userspace can access it */
fd_install(ret, filp);
- page = NULL;
out:
- if (page)
- put_page(page);
return ret;
}
long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout,
unsigned long uaddr2, int val2)
{
- unsigned long pos_in_page;
int ret;
- pos_in_page = uaddr % PAGE_SIZE;
-
- /* Must be "naturally" aligned */
- if (pos_in_page % sizeof(u32))
- return -EINVAL;
-
switch (op) {
case FUTEX_WAIT:
- ret = futex_wait(uaddr, pos_in_page, val, timeout);
+ ret = futex_wait(uaddr, val, timeout);
break;
case FUTEX_WAKE:
- ret = futex_wake(uaddr, pos_in_page, val);
+ ret = futex_wake(uaddr, val);
break;
case FUTEX_FD:
/* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */
- ret = futex_fd(uaddr, pos_in_page, val);
+ ret = futex_fd(uaddr, val);
break;
case FUTEX_REQUEUE:
- {
- unsigned long pos_in_page2 = uaddr2 % PAGE_SIZE;
-
- /* Must be "naturally" aligned */
- if (pos_in_page2 % sizeof(u32))
- return -EINVAL;
-
- ret = futex_requeue(uaddr, pos_in_page, uaddr2, pos_in_page2,
- val, val2);
+ ret = futex_requeue(uaddr, uaddr2, val, val2);
break;
- }
default:
ret = -ENOSYS;
}
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 142ccfcf835b..3180fa00d248 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -35,6 +35,7 @@
#include <linux/writeback.h>
#include <linux/hugetlb.h>
#include <linux/security.h>
+#include <linux/initrd.h>
#include <asm/uaccess.h>
#ifdef CONFIG_ROOT_NFS