From b84f4ece16dc5a152167537328cf935a273e5d09 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Thu, 2 Oct 2008 14:50:12 -0700 Subject: [PATCH] --- yaml --- r: 110130 b: refs/heads/master c: 16dbc6c9616363fe53811abcbd935336dc0a0f01 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/fs/inotify_user.c | 27 ++++++++++++++++++++------- trunk/include/asm-x86/uaccess_64.h | 1 + 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/[refs] b/[refs] index 72ae8c3b8900..0615f2743206 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 08650869e0ec581f8d88cfdb563d37f5383abfe2 +refs/heads/master: 16dbc6c9616363fe53811abcbd935336dc0a0f01 diff --git a/trunk/fs/inotify_user.c b/trunk/fs/inotify_user.c index 60249429a253..d85c7d931cdf 100644 --- a/trunk/fs/inotify_user.c +++ b/trunk/fs/inotify_user.c @@ -323,7 +323,7 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask, } /* - * remove_kevent - cleans up and ultimately frees the given kevent + * remove_kevent - cleans up the given kevent * * Caller must hold dev->ev_mutex. */ @@ -334,7 +334,13 @@ static void remove_kevent(struct inotify_device *dev, dev->event_count--; dev->queue_size -= sizeof(struct inotify_event) + kevent->event.len; +} +/* + * free_kevent - frees the given kevent. + */ +static void free_kevent(struct inotify_kernel_event *kevent) +{ kfree(kevent->name); kmem_cache_free(event_cachep, kevent); } @@ -350,6 +356,7 @@ static void inotify_dev_event_dequeue(struct inotify_device *dev) struct inotify_kernel_event *kevent; kevent = inotify_dev_get_event(dev); remove_kevent(dev, kevent); + free_kevent(kevent); } } @@ -433,17 +440,15 @@ static ssize_t inotify_read(struct file *file, char __user *buf, dev = file->private_data; while (1) { - int events; prepare_to_wait(&dev->wq, &wait, TASK_INTERRUPTIBLE); mutex_lock(&dev->ev_mutex); - events = !list_empty(&dev->events); - mutex_unlock(&dev->ev_mutex); - if (events) { + if (!list_empty(&dev->events)) { ret = 0; break; } + mutex_unlock(&dev->ev_mutex); if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; @@ -462,7 +467,6 @@ static ssize_t inotify_read(struct file *file, char __user *buf, if (ret) return ret; - mutex_lock(&dev->ev_mutex); while (1) { struct inotify_kernel_event *kevent; @@ -481,6 +485,13 @@ static ssize_t inotify_read(struct file *file, char __user *buf, } break; } + remove_kevent(dev, kevent); + + /* + * Must perform the copy_to_user outside the mutex in order + * to avoid a lock order reversal with mmap_sem. + */ + mutex_unlock(&dev->ev_mutex); if (copy_to_user(buf, &kevent->event, event_size)) { ret = -EFAULT; @@ -498,7 +509,9 @@ static ssize_t inotify_read(struct file *file, char __user *buf, count -= kevent->event.len; } - remove_kevent(dev, kevent); + free_kevent(kevent); + + mutex_lock(&dev->ev_mutex); } mutex_unlock(&dev->ev_mutex); diff --git a/trunk/include/asm-x86/uaccess_64.h b/trunk/include/asm-x86/uaccess_64.h index 515d4dce96b5..45806d60bcbe 100644 --- a/trunk/include/asm-x86/uaccess_64.h +++ b/trunk/include/asm-x86/uaccess_64.h @@ -7,6 +7,7 @@ #include #include #include +#include #include /*