From 72c672587e5e1e3c12ef10731517eb73cb126e16 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 27 Jan 2009 18:03:07 -0800 Subject: [PATCH] .27 patches --- queue-2.6.27/fuse-destroy-bdi-on-umount.patch | 59 +++++ .../fuse-fix-missing-fput-on-error.patch | 40 ++++ ...se-fix-null-deref-in-fuse_file_alloc.patch | 30 +++ ...notify_read-and-fix-locking-problems.patch | 225 ++++++++++++++++++ ...etdev-after-launching-mesh-discovery.patch | 36 +++ queue-2.6.27/series | 7 + ...sysfs-fix-problems-with-binary-files.patch | 44 ++++ queue-2.6.27/x86-mm-fix-pte_free.patch | 74 ++++++ 8 files changed, 515 insertions(+) create mode 100644 queue-2.6.27/fuse-destroy-bdi-on-umount.patch create mode 100644 queue-2.6.27/fuse-fix-missing-fput-on-error.patch create mode 100644 queue-2.6.27/fuse-fix-null-deref-in-fuse_file_alloc.patch create mode 100644 queue-2.6.27/inotify-clean-up-inotify_read-and-fix-locking-problems.patch create mode 100644 queue-2.6.27/mac80211-decrement-ref-count-to-netdev-after-launching-mesh-discovery.patch create mode 100644 queue-2.6.27/series create mode 100644 queue-2.6.27/sysfs-fix-problems-with-binary-files.patch create mode 100644 queue-2.6.27/x86-mm-fix-pte_free.patch diff --git a/queue-2.6.27/fuse-destroy-bdi-on-umount.patch b/queue-2.6.27/fuse-destroy-bdi-on-umount.patch new file mode 100644 index 00000000000..ee424a47de1 --- /dev/null +++ b/queue-2.6.27/fuse-destroy-bdi-on-umount.patch @@ -0,0 +1,59 @@ +From 26c3679101dbccc054dcf370143941844ba70531 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Mon, 26 Jan 2009 15:00:59 +0100 +Subject: fuse: destroy bdi on umount + +From: Miklos Szeredi + +commit 26c3679101dbccc054dcf370143941844ba70531 upstream. + +If a fuse filesystem is unmounted but the device file descriptor +remains open and a new mount reuses the old device number, then the +mount fails with EEXIST and the following warning is printed in the +kernel log: + + WARNING: at fs/sysfs/dir.c:462 sysfs_add_one+0x35/0x3d() + sysfs: duplicate filename '0:15' can not be created + +The cause is that the bdi belonging to the fuse filesystem was +destoryed only after the device file was released. Fix this by +calling bdi_destroy() from fuse_put_super() instead. + +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/dev.c | 3 ++- + fs/fuse/inode.c | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -281,7 +281,8 @@ static void request_end(struct fuse_conn + fc->blocked = 0; + wake_up_all(&fc->blocked_waitq); + } +- if (fc->num_background == FUSE_CONGESTION_THRESHOLD) { ++ if (fc->num_background == FUSE_CONGESTION_THRESHOLD && ++ fc->connected) { + clear_bdi_congested(&fc->bdi, READ); + clear_bdi_congested(&fc->bdi, WRITE); + } +--- a/fs/fuse/inode.c ++++ b/fs/fuse/inode.c +@@ -292,6 +292,7 @@ static void fuse_put_super(struct super_ + list_del(&fc->entry); + fuse_ctl_remove_conn(fc); + mutex_unlock(&fuse_mutex); ++ bdi_destroy(&fc->bdi); + fuse_conn_put(fc); + } + +@@ -531,7 +532,6 @@ void fuse_conn_put(struct fuse_conn *fc) + if (fc->destroy_req) + fuse_request_free(fc->destroy_req); + mutex_destroy(&fc->inst_mutex); +- bdi_destroy(&fc->bdi); + kfree(fc); + } + } diff --git a/queue-2.6.27/fuse-fix-missing-fput-on-error.patch b/queue-2.6.27/fuse-fix-missing-fput-on-error.patch new file mode 100644 index 00000000000..bbf8d2a90a7 --- /dev/null +++ b/queue-2.6.27/fuse-fix-missing-fput-on-error.patch @@ -0,0 +1,40 @@ +From 3ddf1e7f57237ac7c5d5bfb7058f1ea4f970b661 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Mon, 26 Jan 2009 15:00:58 +0100 +Subject: fuse: fix missing fput on error + +From: Miklos Szeredi + +commit 3ddf1e7f57237ac7c5d5bfb7058f1ea4f970b661 upstream. + +Fix the leaking file reference if allocation or initialization of +fuse_conn failed. + +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/inode.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/fs/fuse/inode.c ++++ b/fs/fuse/inode.c +@@ -832,12 +832,16 @@ static int fuse_fill_super(struct super_ + if (!file) + return -EINVAL; + +- if (file->f_op != &fuse_dev_operations) ++ if (file->f_op != &fuse_dev_operations) { ++ fput(file); + return -EINVAL; ++ } + + fc = new_conn(sb); +- if (!fc) ++ if (!fc) { ++ fput(file); + return -ENOMEM; ++ } + + fc->flags = d.flags; + fc->user_id = d.user_id; diff --git a/queue-2.6.27/fuse-fix-null-deref-in-fuse_file_alloc.patch b/queue-2.6.27/fuse-fix-null-deref-in-fuse_file_alloc.patch new file mode 100644 index 00000000000..e2fcdc17632 --- /dev/null +++ b/queue-2.6.27/fuse-fix-null-deref-in-fuse_file_alloc.patch @@ -0,0 +1,30 @@ +From bb875b38dc5e343bdb696b2eab8233e4d195e208 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Mon, 26 Jan 2009 15:00:58 +0100 +Subject: fuse: fix NULL deref in fuse_file_alloc() + +From: Dan Carpenter + +commit bb875b38dc5e343bdb696b2eab8233e4d195e208 upstream. + +ff is set to NULL and then dereferenced on line 65. Compile tested only. + +Signed-off-by: Dan Carpenter +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/file.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -54,7 +54,7 @@ struct fuse_file *fuse_file_alloc(void) + ff->reserved_req = fuse_request_alloc(); + if (!ff->reserved_req) { + kfree(ff); +- ff = NULL; ++ return NULL; + } else { + INIT_LIST_HEAD(&ff->write_entry); + atomic_set(&ff->count, 0); diff --git a/queue-2.6.27/inotify-clean-up-inotify_read-and-fix-locking-problems.patch b/queue-2.6.27/inotify-clean-up-inotify_read-and-fix-locking-problems.patch new file mode 100644 index 00000000000..d68d11ef2da --- /dev/null +++ b/queue-2.6.27/inotify-clean-up-inotify_read-and-fix-locking-problems.patch @@ -0,0 +1,225 @@ +From 3632dee2f8b8a9720329f29eeaa4ec4669a3aff8 Mon Sep 17 00:00:00 2001 +From: Vegard Nossum +Date: Thu, 22 Jan 2009 15:29:45 +0100 +Subject: inotify: clean up inotify_read and fix locking problems + +From: Vegard Nossum + +commit 3632dee2f8b8a9720329f29eeaa4ec4669a3aff8 upstream. + +If userspace supplies an invalid pointer to a read() of an inotify +instance, the inotify device's event list mutex is unlocked twice. +This causes an unbalance which effectively leaves the data structure +unprotected, and we can trigger oopses by accessing the inotify +instance from different tasks concurrently. + +The best fix (contributed largely by Linus) is a total rewrite +of the function in question: + +On Thu, Jan 22, 2009 at 7:05 AM, Linus Torvalds wrote: +> The thing to notice is that: +> +> - locking is done in just one place, and there is no question about it +> not having an unlock. +> +> - that whole double-while(1)-loop thing is gone. +> +> - use multiple functions to make nesting and error handling sane +> +> - do error testing after doing the things you always need to do, ie do +> this: +> +> mutex_lock(..) +> ret = function_call(); +> mutex_unlock(..) +> +> .. test ret here .. +> +> instead of doing conditional exits with unlocking or freeing. +> +> So if the code is written in this way, it may still be buggy, but at least +> it's not buggy because of subtle "forgot to unlock" or "forgot to free" +> issues. +> +> This _always_ unlocks if it locked, and it always frees if it got a +> non-error kevent. + +Cc: John McCutchan +Cc: Robert Love +Signed-off-by: Vegard Nossum +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/inotify_user.c | 135 +++++++++++++++++++++++++++++------------------------- + 1 file changed, 74 insertions(+), 61 deletions(-) + +--- a/fs/inotify_user.c ++++ b/fs/inotify_user.c +@@ -427,10 +427,61 @@ static unsigned int inotify_poll(struct + return ret; + } + ++/* ++ * Get an inotify_kernel_event if one exists and is small ++ * enough to fit in "count". Return an error pointer if ++ * not large enough. ++ * ++ * Called with the device ev_mutex held. ++ */ ++static struct inotify_kernel_event *get_one_event(struct inotify_device *dev, ++ size_t count) ++{ ++ size_t event_size = sizeof(struct inotify_event); ++ struct inotify_kernel_event *kevent; ++ ++ if (list_empty(&dev->events)) ++ return NULL; ++ ++ kevent = inotify_dev_get_event(dev); ++ if (kevent->name) ++ event_size += kevent->event.len; ++ ++ if (event_size > count) ++ return ERR_PTR(-EINVAL); ++ ++ remove_kevent(dev, kevent); ++ return kevent; ++} ++ ++/* ++ * Copy an event to user space, returning how much we copied. ++ * ++ * We already checked that the event size is smaller than the ++ * buffer we had in "get_one_event()" above. ++ */ ++static ssize_t copy_event_to_user(struct inotify_kernel_event *kevent, ++ char __user *buf) ++{ ++ size_t event_size = sizeof(struct inotify_event); ++ ++ if (copy_to_user(buf, &kevent->event, event_size)) ++ return -EFAULT; ++ ++ if (kevent->name) { ++ buf += event_size; ++ ++ if (copy_to_user(buf, kevent->name, kevent->event.len)) ++ return -EFAULT; ++ ++ event_size += kevent->event.len; ++ } ++ return event_size; ++} ++ + static ssize_t inotify_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) + { +- size_t event_size = sizeof (struct inotify_event); + struct inotify_device *dev; + char __user *start; + int ret; +@@ -440,81 +491,43 @@ static ssize_t inotify_read(struct file + dev = file->private_data; + + while (1) { ++ struct inotify_kernel_event *kevent; + + prepare_to_wait(&dev->wq, &wait, TASK_INTERRUPTIBLE); + + mutex_lock(&dev->ev_mutex); +- if (!list_empty(&dev->events)) { +- ret = 0; +- break; +- } ++ kevent = get_one_event(dev, count); + mutex_unlock(&dev->ev_mutex); + +- if (file->f_flags & O_NONBLOCK) { +- ret = -EAGAIN; +- break; +- } +- +- if (signal_pending(current)) { +- ret = -EINTR; +- break; ++ if (kevent) { ++ ret = PTR_ERR(kevent); ++ if (IS_ERR(kevent)) ++ break; ++ ret = copy_event_to_user(kevent, buf); ++ free_kevent(kevent); ++ if (ret < 0) ++ break; ++ buf += ret; ++ count -= ret; ++ continue; + } + +- schedule(); +- } +- +- finish_wait(&dev->wq, &wait); +- if (ret) +- return ret; +- +- while (1) { +- struct inotify_kernel_event *kevent; +- +- ret = buf - start; +- if (list_empty(&dev->events)) ++ ret = -EAGAIN; ++ if (file->f_flags & O_NONBLOCK) + break; +- +- kevent = inotify_dev_get_event(dev); +- if (event_size + kevent->event.len > count) { +- if (ret == 0 && count > 0) { +- /* +- * could not get a single event because we +- * didn't have enough buffer space. +- */ +- ret = -EINVAL; +- } ++ ret = -EINTR; ++ if (signal_pending(current)) + 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; ++ if (start != buf) + break; +- } +- buf += event_size; +- count -= event_size; +- +- if (kevent->name) { +- if (copy_to_user(buf, kevent->name, kevent->event.len)){ +- ret = -EFAULT; +- break; +- } +- buf += kevent->event.len; +- count -= kevent->event.len; +- } + +- free_kevent(kevent); +- +- mutex_lock(&dev->ev_mutex); ++ schedule(); + } +- mutex_unlock(&dev->ev_mutex); + ++ finish_wait(&dev->wq, &wait); ++ if (start != buf && ret != -EFAULT) ++ ret = buf - start; + return ret; + } + diff --git a/queue-2.6.27/mac80211-decrement-ref-count-to-netdev-after-launching-mesh-discovery.patch b/queue-2.6.27/mac80211-decrement-ref-count-to-netdev-after-launching-mesh-discovery.patch new file mode 100644 index 00000000000..26b815d6599 --- /dev/null +++ b/queue-2.6.27/mac80211-decrement-ref-count-to-netdev-after-launching-mesh-discovery.patch @@ -0,0 +1,36 @@ +From 5dc306f3bd1d4cfdf79df39221b3036eab1ddcf3 Mon Sep 17 00:00:00 2001 +From: Brian Cavagnolo +Date: Fri, 16 Jan 2009 19:04:49 -0800 +Subject: mac80211: decrement ref count to netdev after launching mesh discovery + +From: Brian Cavagnolo + +commit 5dc306f3bd1d4cfdf79df39221b3036eab1ddcf3 upstream. + +After launching mesh discovery in tx path, reference count was not being +decremented. This was preventing module unload. + +Signed-off-by: Brian Cavagnolo +Signed-off-by: Andrey Yurovsky +Acked-by: Johannes Berg +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + net/mac80211/tx.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -1335,8 +1335,10 @@ int ieee80211_master_start_xmit(struct s + if (is_multicast_ether_addr(hdr->addr3)) + memcpy(hdr->addr1, hdr->addr3, ETH_ALEN); + else +- if (mesh_nexthop_lookup(skb, odev)) ++ if (mesh_nexthop_lookup(skb, odev)) { ++ dev_put(odev); + return 0; ++ } + if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0) + IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.sta, + fwded_frames); diff --git a/queue-2.6.27/series b/queue-2.6.27/series new file mode 100644 index 00000000000..fa9c66bcb70 --- /dev/null +++ b/queue-2.6.27/series @@ -0,0 +1,7 @@ +fuse-destroy-bdi-on-umount.patch +fuse-fix-missing-fput-on-error.patch +fuse-fix-null-deref-in-fuse_file_alloc.patch +inotify-clean-up-inotify_read-and-fix-locking-problems.patch +mac80211-decrement-ref-count-to-netdev-after-launching-mesh-discovery.patch +sysfs-fix-problems-with-binary-files.patch +x86-mm-fix-pte_free.patch diff --git a/queue-2.6.27/sysfs-fix-problems-with-binary-files.patch b/queue-2.6.27/sysfs-fix-problems-with-binary-files.patch new file mode 100644 index 00000000000..bc605863ddf --- /dev/null +++ b/queue-2.6.27/sysfs-fix-problems-with-binary-files.patch @@ -0,0 +1,44 @@ +From 4503efd0891c40e30928afb4b23dc3f99c62a6b2 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Tue, 20 Jan 2009 15:51:16 -0800 +Subject: sysfs: fix problems with binary files + +From: Greg Kroah-Hartman + +commit 4503efd0891c40e30928afb4b23dc3f99c62a6b2 upstream. + +Some sysfs binary files don't like having 0 passed to them as a size. +Fix this up at the root by just returning to the vfs if userspace asks +us for a zero sized buffer. + +Thanks to Pavel Roskin for pointing this out. + +Reported-by: Pavel Roskin +Signed-off-by: Greg Kroah-Hartman + +--- + fs/sysfs/bin.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/fs/sysfs/bin.c ++++ b/fs/sysfs/bin.c +@@ -62,6 +62,9 @@ read(struct file *file, char __user *use + loff_t offs = *off; + int count = min_t(size_t, bytes, PAGE_SIZE); + ++ if (!bytes) ++ return 0; ++ + if (size) { + if (offs > size) + return 0; +@@ -119,6 +122,9 @@ static ssize_t write(struct file *file, + loff_t offs = *off; + int count = min_t(size_t, bytes, PAGE_SIZE); + ++ if (!bytes) ++ return 0; ++ + if (size) { + if (offs > size) + return 0; diff --git a/queue-2.6.27/x86-mm-fix-pte_free.patch b/queue-2.6.27/x86-mm-fix-pte_free.patch new file mode 100644 index 00000000000..e5649d43bb3 --- /dev/null +++ b/queue-2.6.27/x86-mm-fix-pte_free.patch @@ -0,0 +1,74 @@ +From 42ef73fe134732b2e91c0326df5fd568da17c4b2 Mon Sep 17 00:00:00 2001 +From: Peter Zijlstra +Date: Fri, 23 Jan 2009 17:37:49 +0100 +Subject: x86, mm: fix pte_free() + +From: Peter Zijlstra + +commit 42ef73fe134732b2e91c0326df5fd568da17c4b2 upstream. + +On -rt we were seeing spurious bad page states like: + +Bad page state in process 'firefox' +page:c1bc2380 flags:0x40000000 mapping:c1bc2390 mapcount:0 count:0 +Trying to fix it up, but a reboot is needed +Backtrace: +Pid: 503, comm: firefox Not tainted 2.6.26.8-rt13 #3 +[] ? printk+0x14/0x19 +[] bad_page+0x4e/0x79 +[] free_hot_cold_page+0x5b/0x1d3 +[] free_hot_page+0xf/0x11 +[] __free_pages+0x20/0x2b +[] __pte_alloc+0x87/0x91 +[] handle_mm_fault+0xe4/0x733 +[] ? rt_mutex_down_read_trylock+0x57/0x63 +[] ? rt_mutex_down_read_trylock+0x57/0x63 +[] do_page_fault+0x36f/0x88a + +This is the case where a concurrent fault already installed the PTE and +we get to free the newly allocated one. + +This is due to pgtable_page_ctor() doing the spin_lock_init(&page->ptl) +which is overlaid with the {private, mapping} struct. + +union { + struct { + unsigned long private; + struct address_space *mapping; + }; + spinlock_t ptl; + struct kmem_cache *slab; + struct page *first_page; +}; + +Normally the spinlock is small enough to not stomp on page->mapping, but +PREEMPT_RT=y has huge 'spin'locks. + +But lockdep kernels should also be able to trigger this splat, as the +lock tracking code grows the spinlock to cover page->mapping. + +The obvious fix is calling pgtable_page_dtor() like the regular pte free +path __pte_free_tlb() does. + +It seems all architectures except x86 and nm10300 already do this, and +nm10300 doesn't seem to use pgtable_page_ctor(), which suggests it +doesn't do SMP or simply doesnt do MMU at all or something. + +Signed-off-by: Peter Zijlstra +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + include/asm-x86/pgalloc.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/asm-x86/pgalloc.h ++++ b/include/asm-x86/pgalloc.h +@@ -42,6 +42,7 @@ static inline void pte_free_kernel(struc + + static inline void pte_free(struct mm_struct *mm, struct page *pte) + { ++ pgtable_page_dtor(pte); + __free_page(pte); + } + -- 2.47.3