]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
add 2.6.23 mbox
authorGreg Kroah-Hartman <gregkh@suse.de>
Wed, 6 Feb 2008 23:56:11 +0000 (15:56 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 6 Feb 2008 23:56:11 +0000 (15:56 -0800)
queue-2.6.23/mbox [new file with mode: 0644]

diff --git a/queue-2.6.23/mbox b/queue-2.6.23/mbox
new file mode 100644 (file)
index 0000000..81975b2
--- /dev/null
@@ -0,0 +1,12775 @@
+From gregkh@mini.kroah.org Wed Feb  6 15:44:34 2008
+Message-Id: <20080206234434.015046654@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:03 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 01/73] SPARC64: Fix sparc64 cpu cross call hangs.
+Content-Disposition: inline; filename=fix-sparc64-cpu-cross-call-hangs.patch
+Content-Length: 2515
+Lines: 93
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+
+From: David Miller <davem@davemloft.net>
+
+[SPARC64]: Fix endless loop in cheetah_xcall_deliver().
+
+[ Upsteam commit: 0de56d1ab83323d604d95ca193dcbd28388dbabb ]
+
+We need to mask out the proper bits when testing the dispatch status
+register else we can see unrelated NACK bits from previous cross call
+sends.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ arch/sparc64/kernel/smp.c |   19 +++++++++++++------
+ 1 files changed, 13 insertions(+), 6 deletions(-)
+
+diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
+index 894b506..c399449 100644
+--- a/arch/sparc64/kernel/smp.c
++++ b/arch/sparc64/kernel/smp.c
+@@ -476,7 +476,7 @@ static inline void spitfire_xcall_deliver(u64 data0, u64 data1, u64 data2, cpuma
+  */
+ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask)
+ {
+-      u64 pstate, ver;
++      u64 pstate, ver, busy_mask;
+       int nack_busy_id, is_jbus, need_more;
+       if (cpus_empty(mask))
+@@ -508,14 +508,20 @@ retry:
+                              "i" (ASI_INTR_W));
+       nack_busy_id = 0;
++      busy_mask = 0;
+       {
+               int i;
+               for_each_cpu_mask(i, mask) {
+                       u64 target = (i << 14) | 0x70;
+-                      if (!is_jbus)
++                      if (is_jbus) {
++                              busy_mask |= (0x1UL << (i * 2));
++                      } else {
+                               target |= (nack_busy_id << 24);
++                              busy_mask |= (0x1UL <<
++                                            (nack_busy_id * 2));
++                      }
+                       __asm__ __volatile__(
+                               "stxa   %%g0, [%0] %1\n\t"
+                               "membar #Sync\n\t"
+@@ -531,15 +537,16 @@ retry:
+       /* Now, poll for completion. */
+       {
+-              u64 dispatch_stat;
++              u64 dispatch_stat, nack_mask;
+               long stuck;
+               stuck = 100000 * nack_busy_id;
++              nack_mask = busy_mask << 1;
+               do {
+                       __asm__ __volatile__("ldxa      [%%g0] %1, %0"
+                                            : "=r" (dispatch_stat)
+                                            : "i" (ASI_INTR_DISPATCH_STAT));
+-                      if (dispatch_stat == 0UL) {
++                      if (!(dispatch_stat & (busy_mask | nack_mask))) {
+                               __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+                                                    : : "r" (pstate));
+                               if (unlikely(need_more)) {
+@@ -556,12 +563,12 @@ retry:
+                       }
+                       if (!--stuck)
+                               break;
+-              } while (dispatch_stat & 0x5555555555555555UL);
++              } while (dispatch_stat & busy_mask);
+               __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+                                    : : "r" (pstate));
+-              if ((dispatch_stat & ~(0x5555555555555555UL)) == 0) {
++              if (dispatch_stat & busy_mask) {
+                       /* Busy bits will not clear, continue instead
+                        * of freezing up on this cpu.
+                        */
+-- 
+1.5.3.7
+
+_______________________________________________
+stable mailing list
+stable@linux.kernel.org
+http://linux.kernel.org/mailman/listinfo/stable
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:34 2008
+Message-Id: <20080206234434.236112759@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:04 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org,
+ Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ "Junichi Nomura" <j-nomura@ce.jp.nec.com>,
+ dm-devel@redhat.com,
+ Alasdair G Kergon <agk@redhat.com>
+Subject: [patch 02/73] dm: table detect io beyond device
+Content-Disposition: inline; filename=dm-table-detect-io-beyond-device.patch
+Content-Length: 5272
+Lines: 188
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
+
+Patch 512875bd9661368da6f993205a61213b79ba1df0 in mainline.
+
+This patch fixes a panic on shrinking a DM device if there is
+outstanding I/O to the part of the device that is being removed.
+(Normally this doesn't happen - a filesystem would be resized first,
+for example.)
+
+The bug is that __clone_and_map() assumes dm_table_find_target()
+always returns a valid pointer.  It may fail if a bio arrives from the
+block layer but its target sector is no longer included in the DM
+btree.
+
+This patch appends an empty entry to table->targets[] which will
+be returned by a lookup beyond the end of the device.
+
+After calling dm_table_find_target(), __clone_and_map() and target_message()
+check for this condition using 
+dm_target_is_valid().
+
+Sample test script to trigger oops:
+
+#!/bin/bash
+
+FILE=$(mktemp)
+LODEV=$(losetup -f)
+MAP=$(basename ${FILE})
+SIZE=4M
+
+dd if=/dev/zero of=${FILE} bs=${SIZE} count=1
+losetup ${LODEV} ${FILE}
+
+echo "0 $(blockdev --getsz ${LODEV}) linear ${LODEV} 0" |dmsetup create ${MAP}
+dmsetup suspend ${MAP}
+echo "0 1 linear ${LODEV} 0" |dmsetup load ${MAP}
+dd if=/dev/zero of=/dev/mapper/${MAP} bs=${SIZE} count=1 &
+echo "Wait til dd push some I/O"
+sleep 5
+dmsetup resume ${MAP}
+
+Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/md/dm-ioctl.c |   10 +++-------
+ drivers/md/dm-table.c |    7 ++++++-
+ drivers/md/dm.c       |   24 ++++++++++++++++++------
+ drivers/md/dm.h       |    5 +++++
+ 4 files changed, 32 insertions(+), 14 deletions(-)
+
+--- a/drivers/md/dm-ioctl.c
++++ b/drivers/md/dm-ioctl.c
+@@ -1250,21 +1250,17 @@ static int target_message(struct dm_ioct
+       if (!table)
+               goto out_argv;
+-      if (tmsg->sector >= dm_table_get_size(table)) {
++      ti = dm_table_find_target(table, tmsg->sector);
++      if (!dm_target_is_valid(ti)) {
+               DMWARN("Target message sector outside device.");
+               r = -EINVAL;
+-              goto out_table;
+-      }
+-
+-      ti = dm_table_find_target(table, tmsg->sector);
+-      if (ti->type->message)
++      } else if (ti->type->message)
+               r = ti->type->message(ti, argc, argv);
+       else {
+               DMWARN("Target type does not support messages");
+               r = -EINVAL;
+       }
+- out_table:
+       dm_table_put(table);
+  out_argv:
+       kfree(argv);
+--- a/drivers/md/dm-table.c
++++ b/drivers/md/dm-table.c
+@@ -187,8 +187,10 @@ static int alloc_targets(struct dm_table
+       /*
+        * Allocate both the target array and offset array at once.
++       * Append an empty entry to catch sectors beyond the end of
++       * the device.
+        */
+-      n_highs = (sector_t *) dm_vcalloc(num, sizeof(struct dm_target) +
++      n_highs = (sector_t *) dm_vcalloc(num + 1, sizeof(struct dm_target) +
+                                         sizeof(sector_t));
+       if (!n_highs)
+               return -ENOMEM;
+@@ -862,6 +864,9 @@ struct dm_target *dm_table_get_target(st
+ /*
+  * Search the btree for the correct target.
++ *
++ * Caller should check returned pointer with dm_target_is_valid()
++ * to trap I/O beyond end of device.
+  */
+ struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector)
+ {
+--- a/drivers/md/dm.c
++++ b/drivers/md/dm.c
+@@ -663,13 +663,19 @@ static struct bio *clone_bio(struct bio 
+       return clone;
+ }
+-static void __clone_and_map(struct clone_info *ci)
++static int __clone_and_map(struct clone_info *ci)
+ {
+       struct bio *clone, *bio = ci->bio;
+-      struct dm_target *ti = dm_table_find_target(ci->map, ci->sector);
+-      sector_t len = 0, max = max_io_len(ci->md, ci->sector, ti);
++      struct dm_target *ti;
++      sector_t len = 0, max;
+       struct dm_target_io *tio;
++      ti = dm_table_find_target(ci->map, ci->sector);
++      if (!dm_target_is_valid(ti))
++              return -EIO;
++
++      max = max_io_len(ci->md, ci->sector, ti);
++
+       /*
+        * Allocate a target io object.
+        */
+@@ -727,6 +733,9 @@ static void __clone_and_map(struct clone
+               do {
+                       if (offset) {
+                               ti = dm_table_find_target(ci->map, ci->sector);
++                              if (!dm_target_is_valid(ti))
++                                      return -EIO;
++
+                               max = max_io_len(ci->md, ci->sector, ti);
+                               tio = alloc_tio(ci->md);
+@@ -750,6 +759,8 @@ static void __clone_and_map(struct clone
+               ci->idx++;
+       }
++
++      return 0;
+ }
+ /*
+@@ -758,6 +769,7 @@ static void __clone_and_map(struct clone
+ static void __split_bio(struct mapped_device *md, struct bio *bio)
+ {
+       struct clone_info ci;
++      int error = 0;
+       ci.map = dm_get_table(md);
+       if (!ci.map) {
+@@ -777,11 +789,11 @@ static void __split_bio(struct mapped_de
+       ci.idx = bio->bi_idx;
+       start_io_acct(ci.io);
+-      while (ci.sector_count)
+-              __clone_and_map(&ci);
++      while (ci.sector_count && !error)
++              error = __clone_and_map(&ci);
+       /* drop the extra reference count */
+-      dec_pending(ci.io, 0);
++      dec_pending(ci.io, error);
+       dm_table_put(ci.map);
+ }
+ /*-----------------------------------------------------------------
+--- a/drivers/md/dm.h
++++ b/drivers/md/dm.h
+@@ -113,6 +113,11 @@ int dm_table_any_congested(struct dm_tab
+ void dm_table_unplug_all(struct dm_table *t);
+ int dm_table_flush_all(struct dm_table *t);
++/*
++ * To check the return value from dm_table_find_target().
++ */
++#define dm_target_is_valid(t) ((t)->table)
++
+ /*-----------------------------------------------------------------
+  * A registry of target types.
+  *---------------------------------------------------------------*/
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:34 2008
+Message-Id: <20080206234434.457299719@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:05 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org,
+ Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ dm-crypt@saout.de,
+ dm-devel@redhat.com,
+ Milan Broz <mbroz@redhat.com>,
+ Alasdair G Kergon <agk@redhat.com>
+Subject: [patch 03/73] dm crypt: fix write endio
+Content-Disposition: inline; filename=dm-crypt-fix-write-endio.patch
+Content-Length: 1012
+Lines: 41
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Milan Broz <mbroz@redhat.com>
+
+patch adfe47702c4726b3e045f9f83178def02833be4c in mainline.
+
+Fix BIO_UPTODATE test for write io.
+
+Signed-off-by: Milan Broz <mbroz@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/dm-crypt.c |    7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/md/dm-crypt.c
++++ b/drivers/md/dm-crypt.c
+@@ -515,6 +515,9 @@ static int crypt_endio(struct bio *clone
+       struct crypt_config *cc = io->target->private;
+       unsigned read_io = bio_data_dir(clone) == READ;
++      if (unlikely(!bio_flagged(clone, BIO_UPTODATE) && !error))
++              error = -EIO;
++
+       /*
+        * free the processed pages, even if
+        * it's only a partially completed write
+@@ -529,10 +532,8 @@ static int crypt_endio(struct bio *clone
+       if (!read_io)
+               goto out;
+-      if (unlikely(!bio_flagged(clone, BIO_UPTODATE))) {
+-              error = -EIO;
++      if (unlikely(error))
+               goto out;
+-      }
+       bio_put(clone);
+       io->post_process = 1;
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:34 2008
+Message-Id: <20080206234434.678642323@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:06 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org,
+ Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ dm-crypt@saout.de,
+ dm-devel@redhat.com,
+ Milan Broz <mbroz@redhat.com>,
+ Alasdair G Kergon <agk@redhat.com>
+Subject: [patch 04/73] dm crypt: use bio_add_page
+Content-Disposition: inline; filename=dm-crypt-use-bio_add_page.patch
+Content-Length: 2263
+Lines: 79
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Milan Broz <mbroz@redhat.com>
+
+patch 91e106259214b40e992a58fb9417da46868e19b2 in mainline.
+
+Fix possible max_phys_segments violation in cloned dm-crypt bio.
+
+In write operation dm-crypt needs to allocate new bio request
+and run crypto operation on this clone. Cloned request has always
+the same size, but number of physical segments can be increased
+and violate max_phys_segments restriction.
+
+This can lead to data corruption and serious hardware malfunction.
+This was observed when using XFS over dm-crypt and at least
+two HBA controller drivers (arcmsr, cciss) recently.
+
+Fix it by using bio_add_page() call (which tests for other
+restrictions too) instead of constructing own biovec.
+
+All versions of dm-crypt are affected by this bug.
+
+Signed-off-by: Milan Broz <mbroz@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/dm-crypt.c |   24 +++++++++++-------------
+ 1 file changed, 11 insertions(+), 13 deletions(-)
+
+--- a/drivers/md/dm-crypt.c
++++ b/drivers/md/dm-crypt.c
+@@ -399,7 +399,8 @@ static struct bio *crypt_alloc_buffer(st
+       struct bio *clone;
+       unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
+-      unsigned int i;
++      unsigned i, len;
++      struct page *page;
+       clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
+       if (!clone)
+@@ -408,10 +409,8 @@ static struct bio *crypt_alloc_buffer(st
+       clone_init(io, clone);
+       for (i = 0; i < nr_iovecs; i++) {
+-              struct bio_vec *bv = bio_iovec_idx(clone, i);
+-
+-              bv->bv_page = mempool_alloc(cc->page_pool, gfp_mask);
+-              if (!bv->bv_page)
++              page = mempool_alloc(cc->page_pool, gfp_mask);
++              if (!page)
+                       break;
+               /*
+@@ -422,15 +421,14 @@ static struct bio *crypt_alloc_buffer(st
+               if (i == (MIN_BIO_PAGES - 1))
+                       gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
+-              bv->bv_offset = 0;
+-              if (size > PAGE_SIZE)
+-                      bv->bv_len = PAGE_SIZE;
+-              else
+-                      bv->bv_len = size;
++              len = (size > PAGE_SIZE) ? PAGE_SIZE : size;
++
++              if (!bio_add_page(clone, page, len, 0)) {
++                      mempool_free(page, cc->page_pool);
++                      break;
++              }
+-              clone->bi_size += bv->bv_len;
+-              clone->bi_vcnt++;
+-              size -= bv->bv_len;
++              size -= len;
+       }
+       if (!clone->bi_size) {
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:35 2008
+Message-Id: <20080206234434.898923084@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:07 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ William Irwin <wli@holomorphy.com>,
+ Mikael Pettersson <mikpe@it.uu.se>,
+ Len Brown <len.brown@intel.com>
+Subject: [patch 05/73] ACPI: video_device_list corruption
+Content-Disposition: inline; filename=acpi-video_device_list-corruption.patch
+Content-Length: 1367
+Lines: 42
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: William Lee Irwin III <wli@holomorphy.com>
+
+The ->cap fields of struct acpi_video_device and struct acpi_video_bus
+are 1B each, not 4B. The oversized memset()'s corrupted the subsequent
+list_head fields. This resulted in silent corruption without
+CONFIG_DEBUG_LIST and BUG's with it. This patch uses sizeof() to pass
+the proper bounds to the memset() calls and thereby correct the bugs.
+
+upstream commit 98934def70b48dac74fac3738b78ab2d1a28edda
+
+Signed-off-by: William Irwin <wli@holomorphy.com>
+Acked-by: Mikael Pettersson <mikpe@it.uu.se>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/video.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/acpi/video.c
++++ b/drivers/acpi/video.c
+@@ -573,7 +573,7 @@ static void acpi_video_device_find_cap(s
+       struct acpi_video_device_brightness *br = NULL;
+-      memset(&device->cap, 0, 4);
++      memset(&device->cap, 0, sizeof(device->cap));
+       if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) {
+               device->cap._ADR = 1;
+@@ -693,7 +693,7 @@ static void acpi_video_bus_find_cap(stru
+ {
+       acpi_handle h_dummy1;
+-      memset(&video->cap, 0, 4);
++      memset(&video->cap, 0, sizeof(video->cap));
+       if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) {
+               video->cap._DOS = 1;
+       }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:35 2008
+Message-Id: <20080206234435.122403143@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:08 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Henrique Holschuh <hmh@hmh.eng.br>,
+ Len Brown <len.brown@intel.com>
+Subject: [patch 06/73] ACPI: thinkpad-acpi: fix lenovo keymap for brightness
+Content-Disposition: inline; filename=acpi-thinkpad-acpi-fix-lenovo-keymap-for-brightness.patch
+Content-Length: 1643
+Lines: 42
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+
+upstream  commit 56a185b43be05e48da7428e6a1d3e2585b232b1d
+
+Starting in 2.6.23...
+
+Several reports from X60 users complained that the default Lenovo keymap
+issuing EV_KEY KEY_BRIGHTNESS_UP/DOWN input events caused major issues when
+the proper brightness support through ACPI video.c was loaded.
+
+Therefore, remove the generation of these events by default, which is the
+right thing for T60, X60, R60, T61, X61 and R61 with their latest BIOSes.
+
+Distros that want to misuse these events into OSD reporting (which requires
+an ugly hack from hell in HAL) are welcome to set up the key map they need
+through HAL.  That way, we don't break everyone else's systems.
+
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/misc/thinkpad_acpi.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/misc/thinkpad_acpi.c
++++ b/drivers/misc/thinkpad_acpi.c
+@@ -968,9 +968,9 @@ static int __init hotkey_init(struct ibm
+               KEY_UNKNOWN,    /* 0x0C: FN+BACKSPACE */
+               KEY_UNKNOWN,    /* 0x0D: FN+INSERT */
+               KEY_UNKNOWN,    /* 0x0E: FN+DELETE */
+-              KEY_BRIGHTNESSUP,       /* 0x0F: FN+HOME (brightness up) */
++              KEY_RESERVED,   /* 0x0F: FN+HOME (brightness up) */
+               /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
+-              KEY_BRIGHTNESSDOWN,     /* 0x10: FN+END (brightness down) */
++              KEY_RESERVED,   /* 0x10: FN+END (brightness down) */
+               KEY_RESERVED,   /* 0x11: FN+PGUP (thinklight toggle) */
+               KEY_UNKNOWN,    /* 0x12: FN+PGDOWN */
+               KEY_ZOOM,       /* 0x13: FN+SPACE (zoom) */
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:35 2008
+Message-Id: <20080206234435.341377932@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:09 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@stable.org,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 07/73] SPARC64: Fix memory controller register access when non-SMP.
+Content-Disposition: inline; filename=sparc64-fix-memory-controller-register-access-when-non-smp.patch
+Content-Length: 1763
+Lines: 66
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: David Miller <davem@davemloft.net>
+
+[SPARC64]: Fix memory controller register access when non-SMP.
+
+[ Upstream commit: b332b8bc9c67165eabdfc7d10b4a2e4cc9f937d0 ]
+
+get_cpu() always returns zero on non-SMP builds, but we
+really want the physical cpu number in this code in order
+to do the right thing.
+
+Based upon a non-SMP kernel boot failure report from Bernd Zeimetz.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/sparc64/kernel/chmc.c |   16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+--- a/arch/sparc64/kernel/chmc.c
++++ b/arch/sparc64/kernel/chmc.c
+@@ -1,7 +1,6 @@
+-/* $Id: chmc.c,v 1.4 2002/01/08 16:00:14 davem Exp $
+- * memctrlr.c: Driver for UltraSPARC-III memory controller.
++/* memctrlr.c: Driver for UltraSPARC-III memory controller.
+  *
+- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
++ * Copyright (C) 2001, 2007 David S. Miller (davem@davemloft.net)
+  */
+ #include <linux/module.h>
+@@ -16,6 +15,7 @@
+ #include <linux/init.h>
+ #include <asm/spitfire.h>
+ #include <asm/chmctrl.h>
++#include <asm/cpudata.h>
+ #include <asm/oplib.h>
+ #include <asm/prom.h>
+ #include <asm/io.h>
+@@ -242,8 +242,11 @@ int chmc_getunumber(int syndrome_code,
+  */
+ static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
+ {
+-      unsigned long ret;
+-      int this_cpu = get_cpu();
++      unsigned long ret, this_cpu;
++
++      preempt_disable();
++
++      this_cpu = real_hard_smp_processor_id();
+       if (mp->portid == this_cpu) {
+               __asm__ __volatile__("ldxa      [%1] %2, %0"
+@@ -255,7 +258,8 @@ static u64 read_mcreg(struct mctrl_info 
+                                    : "r" (mp->regs + offset),
+                                      "i" (ASI_PHYS_BYPASS_EC_E));
+       }
+-      put_cpu();
++
++      preempt_enable();
+       return ret;
+ }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:35 2008
+Message-Id: <20080206234435.561150790@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:10 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 08/73] SPARC64: Fix two kernel linear mapping setup bugs.
+Content-Disposition: inline; filename=sparc64-fix-two-kernel-linear-mapping-setup-bugs.patch
+Content-Length: 3474
+Lines: 127
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: David Miller <davem@davemloft.net>
+
+[SPARC64]: Fix two kernel linear mapping setup bugs.
+
+[ Upstream commit: 8f361453d8e9a67c85b2cf9b93c642c2d8fe0462 ]
+
+This was caught and identified by Greg Onufer.
+
+Since we setup the 256M/4M bitmap table after taking over the trap
+table, it's possible for some 4M mapping to get loaded in the TLB
+beforhand which later will be 256M mappings.
+
+This can cause illegal TLB multiple-match conditions.  Fix this by
+setting up the bitmap before we take over the trap table.
+
+Next, __flush_tlb_all() was not doing anything on hypervisor
+platforms.  Fix by adding sun4v_mmu_demap_all() and calling it.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/sparc64/kernel/entry.S      |   12 ++++++++++++
+ arch/sparc64/mm/init.c           |   29 ++++++++++++++++++++---------
+ include/asm-sparc64/hypervisor.h |    4 ++++
+ 3 files changed, 36 insertions(+), 9 deletions(-)
+
+--- a/arch/sparc64/kernel/entry.S
++++ b/arch/sparc64/kernel/entry.S
+@@ -2593,3 +2593,15 @@ sun4v_mmustat_info:
+       retl
+        nop
+       .size   sun4v_mmustat_info, .-sun4v_mmustat_info
++
++      .globl  sun4v_mmu_demap_all
++      .type   sun4v_mmu_demap_all,#function
++sun4v_mmu_demap_all:
++      clr     %o0
++      clr     %o1
++      mov     HV_MMU_ALL, %o2
++      mov     HV_FAST_MMU_DEMAP_ALL, %o5
++      ta      HV_FAST_TRAP
++      retl
++       nop
++      .size   sun4v_mmu_demap_all, .-sun4v_mmu_demap_all
+--- a/arch/sparc64/mm/init.c
++++ b/arch/sparc64/mm/init.c
+@@ -1135,14 +1135,9 @@ static void __init mark_kpte_bitmap(unsi
+       }
+ }
+-static void __init kernel_physical_mapping_init(void)
++static void __init init_kpte_bitmap(void)
+ {
+       unsigned long i;
+-#ifdef CONFIG_DEBUG_PAGEALLOC
+-      unsigned long mem_alloced = 0UL;
+-#endif
+-
+-      read_obp_memory("reg", &pall[0], &pall_ents);
+       for (i = 0; i < pall_ents; i++) {
+               unsigned long phys_start, phys_end;
+@@ -1151,14 +1146,24 @@ static void __init kernel_physical_mappi
+               phys_end = phys_start + pall[i].reg_size;
+               mark_kpte_bitmap(phys_start, phys_end);
++      }
++}
++static void __init kernel_physical_mapping_init(void)
++{
+ #ifdef CONFIG_DEBUG_PAGEALLOC
++      unsigned long i, mem_alloced = 0UL;
++
++      for (i = 0; i < pall_ents; i++) {
++              unsigned long phys_start, phys_end;
++
++              phys_start = pall[i].phys_addr;
++              phys_end = phys_start + pall[i].reg_size;
++
+               mem_alloced += kernel_map_range(phys_start, phys_end,
+                                               PAGE_KERNEL);
+-#endif
+       }
+-#ifdef CONFIG_DEBUG_PAGEALLOC
+       printk("Allocated %ld bytes for kernel page tables.\n",
+              mem_alloced);
+@@ -1400,6 +1405,10 @@ void __init paging_init(void)
+       
+       inherit_prom_mappings();
+       
++      read_obp_memory("reg", &pall[0], &pall_ents);
++
++      init_kpte_bitmap();
++
+       /* Ok, we can use our TLB miss and window trap handlers safely.  */
+       setup_tba();
+@@ -1854,7 +1863,9 @@ void __flush_tlb_all(void)
+                            "wrpr      %0, %1, %%pstate"
+                            : "=r" (pstate)
+                            : "i" (PSTATE_IE));
+-      if (tlb_type == spitfire) {
++      if (tlb_type == hypervisor) {
++              sun4v_mmu_demap_all();
++      } else if (tlb_type == spitfire) {
+               for (i = 0; i < 64; i++) {
+                       /* Spitfire Errata #32 workaround */
+                       /* NOTE: Always runs on spitfire, so no
+--- a/include/asm-sparc64/hypervisor.h
++++ b/include/asm-sparc64/hypervisor.h
+@@ -709,6 +709,10 @@ extern unsigned long sun4v_mmu_tsb_ctx0(
+  */
+ #define HV_FAST_MMU_DEMAP_ALL         0x24
++#ifndef __ASSEMBLY__
++extern void sun4v_mmu_demap_all(void);
++#endif
++
+ /* mmu_map_perm_addr()
+  * TRAP:      HV_FAST_TRAP
+  * FUNCTION:  HV_FAST_MMU_MAP_PERM_ADDR
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:35 2008
+Message-Id: <20080206234435.780537506@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:11 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ Herbert Xu <herbert@gondor.apana.org.au>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 09/73] IPSEC: Fix potential dst leak in xfrm_lookup
+Content-Disposition: inline; filename=ipsec-fix-potential-dst-leak-in-xfrm_lookup.patch
+Content-Length: 1324
+Lines: 57
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[IPSEC]: Fix potential dst leak in xfrm_lookup
+
+[ Upstream commit: 75b8c133267053c9986a7c8db5131f0e7349e806 ]
+
+If we get an error during the actual policy lookup we don't free the
+original dst while the caller expects us to always free the original
+dst in case of error.
+
+This patch fixes that.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/xfrm/xfrm_policy.c |    9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/net/xfrm/xfrm_policy.c
++++ b/net/xfrm/xfrm_policy.c
+@@ -1479,8 +1479,9 @@ restart:
+       if (sk && sk->sk_policy[1]) {
+               policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
++              err = PTR_ERR(policy);
+               if (IS_ERR(policy))
+-                      return PTR_ERR(policy);
++                      goto dropdst;
+       }
+       if (!policy) {
+@@ -1491,8 +1492,9 @@ restart:
+               policy = flow_cache_lookup(fl, dst_orig->ops->family,
+                                          dir, xfrm_policy_lookup);
++              err = PTR_ERR(policy);
+               if (IS_ERR(policy))
+-                      return PTR_ERR(policy);
++                      goto dropdst;
+       }
+       if (!policy)
+@@ -1661,8 +1663,9 @@ restart:
+       return 0;
+ error:
+-      dst_release(dst_orig);
+       xfrm_pols_put(pols, npols);
++dropdst:
++      dst_release(dst_orig);
+       *dst_p = NULL;
+       return err;
+ }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:36 2008
+Message-Id: <20080206234436.000353150@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:12 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@stable.org,
+ Pavel Emelyanov <xemul@openvz.org>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 10/73] VLAN: Lost rtnl_unlock() in vlan_ioctl()
+Content-Disposition: inline; filename=vlan-lost-rtnl_unlock-in-vlan_ioctl.patch
+Content-Length: 829
+Lines: 30
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Pavel Emelyanov <xemul@openvz.org>
+
+[VLAN]: Lost rtnl_unlock() in vlan_ioctl()
+
+[ Upstream commit: e35de02615f97b785dc6f73cba421cea06bcbd10 ]
+
+The SET_VLAN_NAME_TYPE_CMD command w/o CAP_NET_ADMIN capability
+doesn't release the rtnl lock.
+
+Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/8021q/vlan.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/8021q/vlan.c
++++ b/net/8021q/vlan.c
+@@ -768,7 +768,7 @@ static int vlan_ioctl_handler(void __use
+       case SET_VLAN_NAME_TYPE_CMD:
+               err = -EPERM;
+               if (!capable(CAP_NET_ADMIN))
+-                      return -EPERM;
++                      break;
+               if ((args.u.name_type >= 0) &&
+                   (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) {
+                       vlan_name_type = args.u.name_type;
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:36 2008
+Message-Id: <20080206234436.219714936@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:13 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org,
+ torvalds@linux-foundation.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ ctusar@videon-central.com,
+ jirislaby@gmail.com
+Subject: [patch 11/73] tty: fix logic change introduced by wait_event_interruptible_timeout()
+Content-Disposition: inline; filename=tty-fix-logic-change-introduced-by-wait_event_interruptible_timeout.patch
+Content-Length: 2030
+Lines: 50
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: "Cory T. Tusar" <ctusar@videon-central.com>
+
+patch db99247ac68fc352100090ad7704fb5efb9327b6 in mainline.
+
+Commit 5a52bd4a2dcb570333ce6fe2e16cd311650dbdc8 introduced a subtle logic
+change in tty_wait_until_sent().  The original version would only error out
+of the 'do { ...  } while (timeout)' loop if signal_pending() evaluated to
+true; a timeout or break due to an empty buffer would fall out of the loop
+and into the tty->driver->wait_until_sent handling.  The current
+implementation will error out on either a pending signal or an empty
+buffer, falling through to the tty->driver->wait_until_sent handling only
+on a timeout.
+
+The ->wait_until_sent() will not be reached if the buffer empties before
+timeout jiffies have elapsed.  This behavior differs from that prior to commit
+5a52bd4a2dcb570333ce6fe2e16cd311650dbdc8.
+
+I turned this up while using a little serial download utility to bootstrap an
+ARM-based eval board.  The util worked fine on 2.6.22.x, but consistently
+failed on 2.6.23.x.  Once I'd determined that, I narrowed things down with git
+bisect, and found the above difference in logic in tty_wait_until_sent() by
+inspection.
+
+This change reverts the logic flow in tty_wait_until_sent() to match that
+prior to the aforementioned commit.
+
+Signed-off-by: Cory T. Tusar <ctusar@videon-central.com>
+Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Acked-by: Jiri Slaby <jirislaby@gmail.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/tty_ioctl.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/char/tty_ioctl.c
++++ b/drivers/char/tty_ioctl.c
+@@ -62,7 +62,7 @@ void tty_wait_until_sent(struct tty_stru
+       if (!timeout)
+               timeout = MAX_SCHEDULE_TIMEOUT;
+       if (wait_event_interruptible_timeout(tty->write_wait,
+-                      !tty->driver->chars_in_buffer(tty), timeout))
++                      !tty->driver->chars_in_buffer(tty), timeout) < 0)
+               return;
+       if (tty->driver->wait_until_sent)
+               tty->driver->wait_until_sent(tty, timeout);
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:36 2008
+Message-Id: <20080206234436.439239950@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:14 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ Herbert Xu <herbert@gondor.apana.org.au>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 12/73] IPV4 raw: Strengthen check on validity of iph->ihl
+Content-Disposition: inline; filename=ipv4-raw-strengthen-check-on-validity-of-iph-ihl.patch
+Content-Length: 1298
+Lines: 44
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[IPV4] raw: Strengthen check on validity of iph->ihl
+
+[ Upstream commit: f844c74fe07321953e2dd227fe35280075f18f60 ]
+
+We currently check that iph->ihl is bounded by the real length and that
+the real length is greater than the minimum IP header length.  However,
+we did not check the caes where iph->ihl is less than the minimum IP
+header length.
+
+This breaks because some ip_fast_csum implementations assume that which
+is quite reasonable.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/ipv4/raw.c |    4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/net/ipv4/raw.c
++++ b/net/ipv4/raw.c
+@@ -270,6 +270,7 @@ static int raw_send_hdrinc(struct sock *
+       int hh_len;
+       struct iphdr *iph;
+       struct sk_buff *skb;
++      unsigned int iphlen;
+       int err;
+       if (length > rt->u.dst.dev->mtu) {
+@@ -303,7 +304,8 @@ static int raw_send_hdrinc(struct sock *
+               goto error_fault;
+       /* We don't modify invalid header */
+-      if (length >= sizeof(*iph) && iph->ihl * 4U <= length) {
++      iphlen = iph->ihl * 4;
++      if (iphlen >= sizeof(*iph) && iphlen <= length) {
+               if (!iph->saddr)
+                       iph->saddr = rt->rt_src;
+               iph->check   = 0;
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:36 2008
+Message-Id: <20080206234436.660443603@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:15 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Stephen Hemminger <shemminger@linux-foundation.org>
+Subject: [patch 13/73] sky2: disable rx checksum on Yukon XL
+Content-Disposition: inline; filename=sky2-xl-chksum
+Content-Length: 1557
+Lines: 51
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+
+Backport of 8b31cfbcd1b54362ef06c85beb40e65a349169a2
+
+The Marvell Yukon XL chipset appears to have a hardware glitch
+where it will repeat the checksum of the last packet. Of course, this is
+timing sensitive and only happens sometimes...
+
+More info: http://bugzilla.kernel.org/show_bug.cgi?id=9381
+
+As a workaround just disable hardware checksumming by default on
+this chip version. The earlier workaround for PCIX, dual port
+was also on Yukon XL so don't need to disable checksumming there.
+
+Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/net/sky2.c |    6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+--- a/drivers/net/sky2.c
++++ b/drivers/net/sky2.c
+@@ -1307,15 +1307,11 @@ static int sky2_up(struct net_device *de
+        */
+       if (otherdev && netif_running(otherdev) &&
+           (cap = pci_find_capability(hw->pdev, PCI_CAP_ID_PCIX))) {
+-              struct sky2_port *osky2 = netdev_priv(otherdev);
+               u16 cmd;
+               cmd = sky2_pci_read16(hw, cap + PCI_X_CMD);
+               cmd &= ~PCI_X_CMD_MAX_SPLIT;
+               sky2_pci_write16(hw, cap + PCI_X_CMD, cmd);
+-
+-              sky2->rx_csum = 0;
+-              osky2->rx_csum = 0;
+       }
+       if (netif_msg_ifup(sky2))
+@@ -4017,7 +4013,7 @@ static __devinit struct net_device *sky2
+       sky2->duplex = -1;
+       sky2->speed = -1;
+       sky2->advertising = sky2_supported_modes(hw);
+-      sky2->rx_csum = 1;
++      sky2->rx_csum = (hw->chip_id != CHIP_ID_YUKON_XL);
+       sky2->wol = wol;
+       spin_lock_init(&sky2->phy_lock);
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:37 2008
+Message-Id: <20080206234436.879588746@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:16 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Peter Tyser <ptyser@xes-inc.com>,
+ Stephen Hemminger <shemminger@linux-foundation.org>
+Subject: [patch 14/73] sky2: RX lockup fix
+Content-Disposition: inline; filename=sky2-1
+Content-Length: 1922
+Lines: 50
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+
+Backport commit 798fdd07fcc131f396e521febb4a7d42559bf4b5
+
+I'm using a Marvell 88E8062 on a custom PPC64 blade and ran into RX
+lockups while validating the sky2 driver.  The receive MAC FIFO would
+become stuck during testing with high traffic.  One port of the 88E8062
+would lockup, while the other port remained functional.  Re-inserting
+the sky2 module would not fix the problem - only a power cycle would.
+
+I looked over Marvell's most recent sk98lin driver and it looks like
+they had a "workaround" for the Yukon XL that the sky2 doesn't have yet.
+The sk98lin driver disables the RX MAC FIFO flush feature for all
+revisions of the Yukon XL.
+
+According to skgeinit.c of the sk98lin driver, "Flushing must be enabled
+(needed for ASF see dev. #4.29), but the flushing mask should be
+disabled (see dev. #4.115)".  Nice. I implemented this same change in
+the sky2 driver and verified that the RX lockup I was seeing was
+resolved.
+
+Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
+Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/net/sky2.c |    9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/sky2.c
++++ b/drivers/net/sky2.c
+@@ -812,8 +812,13 @@ static void sky2_mac_init(struct sky2_hw
+       sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg);
+-      /* Flush Rx MAC FIFO on any flow control or error */
+-      sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);
++      if (hw->chip_id == CHIP_ID_YUKON_XL) {
++              /* Hardware errata - clear flush mask */
++              sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), 0);
++      } else {
++              /* Flush Rx MAC FIFO on any flow control or error */
++              sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);
++      }
+       /* Set threshold to 0xa (64 bytes) + 1 to workaround pause bug  */
+       reg = RX_GMF_FL_THR_DEF + 1;
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:37 2008
+Message-Id: <20080206234437.099577612@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:17 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Patrick Mansfield <patmans@us.ibm.com>,
+ Anton Blanchard <anton@samba.org>,
+ Paul Mackerras <paulus@samba.org>
+Subject: [patch 15/73] POWERPC: Change fallocate to match unistd.h on powerpc
+Content-Disposition: inline; filename=powerpc-change-fallocate-to-match-unistd.h-on-powerpc.patch
+Content-Length: 966
+Lines: 37
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Patrick Mansfield <patmans@us.ibm.com>
+
+patch f2205fbb5a8933514fd343cc329df631802b4543 in mainline.
+
+Fix the fallocate system call on powerpc to match its unistd.h.
+
+This implies none of these system calls are currently working with the
+unistd.h sys call values:
+       fallocate
+       signalfd
+       timerfd
+       eventfd
+       sync_file_range2
+
+Signed-off-by: Patrick Mansfield <patmans@us.ibm.com>
+Acked-by: Anton Blanchard <anton@samba.org>
+Signed-off-by: Paul Mackerras <paulus@samba.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/asm-powerpc/systbl.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/asm-powerpc/systbl.h
++++ b/include/asm-powerpc/systbl.h
+@@ -308,8 +308,8 @@ COMPAT_SYS_SPU(move_pages)
+ SYSCALL_SPU(getcpu)
+ COMPAT_SYS(epoll_pwait)
+ COMPAT_SYS_SPU(utimensat)
+-COMPAT_SYS(fallocate)
+ COMPAT_SYS_SPU(signalfd)
+ COMPAT_SYS_SPU(timerfd)
+ SYSCALL_SPU(eventfd)
+ COMPAT_SYS_SPU(sync_file_range2)
++COMPAT_SYS(fallocate)
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:37 2008
+Message-Id: <20080206234437.318807774@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:18 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ Julia Lawall <julia@diku.dk>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 16/73] X25: Add missing x25_neigh_put
+Content-Disposition: inline; filename=x25-add-missing-x25_neigh_put.patch
+Content-Length: 1662
+Lines: 75
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Julia Lawall <julia@diku.dk>
+
+[X25]: Add missing x25_neigh_put
+
+[ Upstream commit: 76975f8a3186dae501584d0155ea410464f62815 ]
+
+The function x25_get_neigh increments a reference count.  At the point of
+the second goto out, the result of calling x25_get_neigh is only stored in
+a local variable, and thus no one outside the function will be able to
+decrease the reference count.  Thus, x25_neigh_put should be called before
+the return in this case.
+
+The problem was found using the following semantic match.
+(http://www.emn.fr/x-info/coccinelle/)
+
+// <smpl>
+
+@@
+type T,T1,T2;
+identifier E;
+statement S;
+expression x1,x2,x3;
+int ret;
+@@
+
+  T E;
+  ...
+* if ((E = x25_get_neigh(...)) == NULL)
+  S
+  ... when != x25_neigh_put(...,(T1)E,...)
+      when != if (E != NULL) { ... x25_neigh_put(...,(T1)E,...); ...}
+      when != x1 = (T1)E
+      when != E = x3;
+      when any
+  if (...) {
+    ... when != x25_neigh_put(...,(T2)E,...)
+        when != if (E != NULL) { ... x25_neigh_put(...,(T2)E,...); ...}
+        when != x2 = (T2)E
+(
+*   return;
+|
+*   return ret;
+)
+  }
+// </smpl>
+
+Signed-off-by: Julia Lawall <julia@diku.dk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/x25/x25_forward.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/net/x25/x25_forward.c
++++ b/net/x25/x25_forward.c
+@@ -118,13 +118,14 @@ int x25_forward_data(int lci, struct x25
+               goto out;
+       if ( (skbn = pskb_copy(skb, GFP_ATOMIC)) == NULL){
+-              goto out;
++              goto output;
+       }
+       x25_transmit_link(skbn, nb);
+-      x25_neigh_put(nb);
+       rc = 1;
++output:
++      x25_neigh_put(nb);
+ out:
+       return rc;
+ }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:37 2008
+Message-Id: <20080206234437.538245796@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:19 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ Russ Dill <Russ.Dill@asu.edu>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 17/73] NET: mcs7830 passes msecs instead of jiffies to usb_control_msg
+Content-Disposition: inline; filename=net-mcs7830-passes-msecs-instead-of-jiffies-to-usb_control_msg.patch
+Content-Length: 1214
+Lines: 39
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Russ Dill <Russ.Dill@asu.edu>
+
+[NET]: mcs7830 passes msecs instead of jiffies to usb_control_msg
+
+[ Upstream commit 1d39da3dcaad4231f0fa75024b1d6d710a2ced74 ]
+
+usb_control_msg was changed long ago (2.6.12-pre) to take milliseconds
+instead of jiffies. Oddly, mcs7830 wasn't added until 2.6.19-rc3.
+
+Signed-off-by: Russ Dill <Russ.Dill@asu.edu>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/usb/mcs7830.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/usb/mcs7830.c
++++ b/drivers/net/usb/mcs7830.c
+@@ -94,7 +94,7 @@ static int mcs7830_get_reg(struct usbnet
+       ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ,
+                             MCS7830_RD_BMREQ, 0x0000, index, data,
+-                            size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
++                            size, MCS7830_CTRL_TIMEOUT);
+       return ret;
+ }
+@@ -105,7 +105,7 @@ static int mcs7830_set_reg(struct usbnet
+       ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ,
+                             MCS7830_WR_BMREQ, 0x0000, index, data,
+-                            size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
++                            size, MCS7830_CTRL_TIMEOUT);
+       return ret;
+ }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:37 2008
+Message-Id: <20080206234437.757172423@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:20 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ Russ Dill <Russ.Dill@asu.edu>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 18/73] NET: kaweth was forgotten in msec switchover of usb_start_wait_urb
+Content-Disposition: inline; filename=net-kaweth-was-forgotten-in-msec-switchover-of-usb_start_wait_urb.patch
+Content-Length: 907
+Lines: 30
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Russ Dill <Russ.Dill@asu.edu>
+
+[NET]: kaweth was forgotten in msec switchover of usb_start_wait_urb
+
+[ Upstream commit: 2b2b2e35b71e5be8bc06cc0ff38df15dfedda19b ]
+
+Back in 2.6.12-pre, usb_start_wait_urb was switched over to take
+milliseconds instead of jiffies. kaweth.c was never updated to match.
+
+Signed-off-by: Russ Dill <Russ.Dill@asu.edu>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/usb/kaweth.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/usb/kaweth.c
++++ b/drivers/net/usb/kaweth.c
+@@ -70,7 +70,7 @@
+ #define KAWETH_TX_TIMEOUT             (5 * HZ)
+ #define KAWETH_SCRATCH_SIZE           32
+ #define KAWETH_FIRMWARE_BUF_SIZE      4096
+-#define KAWETH_CONTROL_TIMEOUT                (30 * HZ)
++#define KAWETH_CONTROL_TIMEOUT                (30000)
+ #define KAWETH_STATUS_BROKEN          0x0000001
+ #define KAWETH_STATUS_CLOSING         0x0000002
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:38 2008
+Message-Id: <20080206234437.979506347@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:21 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ maximilian attems <max@stro.at>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 19/73] IRDA: irda_create() nuke user triggable printk
+Content-Disposition: inline; filename=irda-irda_create-nuke-user-triggable-printk.patch
+Content-Length: 809
+Lines: 32
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: maximilian attems <max@stro.at>
+
+[IRDA]: irda_create() nuke user triggable printk
+
+[ Upstream commit: 9e8d6f8959c356d8294d45f11231331c3e1bcae6 ]
+
+easy to trigger as user with sfuzz.
+
+irda_create() is quiet on unknown sock->type,
+match this behaviour for SOCK_DGRAM unknown protocol
+
+Signed-off-by: maximilian attems <max@stro.at>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/irda/af_irda.c |    2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/net/irda/af_irda.c
++++ b/net/irda/af_irda.c
+@@ -1115,8 +1115,6 @@ static int irda_create(struct socket *so
+                       self->max_sdu_size_rx = TTP_SAR_UNBOUND;
+                       break;
+               default:
+-                      IRDA_ERROR("%s: protocol not supported!\n",
+-                                 __FUNCTION__);
+                       return -ESOCKTNOSUPPORT;
+               }
+               break;
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:38 2008
+Message-Id: <20080206234438.200408126@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:22 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ Mark McLoughlin <markmc@redhat.com>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 20/73] INET: Fix netdev renaming and inet address labels
+Content-Disposition: inline; filename=inet-fix-netdev-renaming-and-inet-address-labels.patch
+Content-Length: 1356
+Lines: 45
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Mark McLoughlin <markmc@redhat.com>
+
+[INET]: Fix netdev renaming and inet address labels
+
+[ Upstream commit: 44344b2a85f03326c7047a8c861b0c625c674839 ]
+
+When re-naming an interface, the previous secondary address
+labels get lost e.g.
+
+  $> brctl addbr foo
+  $> ip addr add 192.168.0.1 dev foo
+  $> ip addr add 192.168.0.2 dev foo label foo:00
+  $> ip addr show dev foo | grep inet
+    inet 192.168.0.1/32 scope global foo
+    inet 192.168.0.2/32 scope global foo:00
+  $> ip link set foo name bar
+  $> ip addr show dev bar | grep inet
+    inet 192.168.0.1/32 scope global bar
+    inet 192.168.0.2/32 scope global bar:2
+
+Turns out to be a simple thinko in inetdev_changename() - clearly we
+want to look at the address label, rather than the device name, for
+a suffix to retain.
+
+Signed-off-by: Mark McLoughlin <markmc@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/ipv4/devinet.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/ipv4/devinet.c
++++ b/net/ipv4/devinet.c
+@@ -1030,7 +1030,7 @@ static void inetdev_changename(struct ne
+               memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
+               if (named++ == 0)
+                       continue;
+-              dot = strchr(ifa->ifa_label, ':');
++              dot = strchr(old, ':');
+               if (dot == NULL) {
+                       sprintf(old, ":%d", named);
+                       dot = old;
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:38 2008
+Message-Id: <20080206234438.419782069@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:23 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ Li Zefan <lizf@cn.fujitsu.com>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 21/73] CONNECTOR: Dont touch queue dev after decrement of ref count.
+Content-Disposition: inline; filename=connector-don-t-touch-queue-dev-after-decrement-of-ref-count.patch
+Content-Length: 828
+Lines: 31
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Li Zefan <lizf@cn.fujitsu.com>
+
+[CONNECTOR]: Don't touch queue dev after decrement of ref count.
+
+[ Upstream commit: cf585ae8ae9ac7287a6d078425ea32f22bf7f1f7 ]
+
+cn_queue_free_callback() will touch 'dev'(i.e. cbq->pdev), so it
+should be called before atomic_dec(&dev->refcnt).
+
+Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/connector/cn_queue.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/connector/cn_queue.c
++++ b/drivers/connector/cn_queue.c
+@@ -99,8 +99,8 @@ int cn_queue_add_callback(struct cn_queu
+       spin_unlock_bh(&dev->queue_lock);
+       if (found) {
+-              atomic_dec(&dev->refcnt);
+               cn_queue_free_callback(cbq);
++              atomic_dec(&dev->refcnt);
+               return -EINVAL;
+       }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:38 2008
+Message-Id: <20080206234438.640737428@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:24 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ Herbert Xu <herbert@gondor.apana.org.au>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 22/73] ATM: Check IP header validity in mpc_send_packet
+Content-Disposition: inline; filename=atm-check-ip-header-validity-in-mpc_send_packet.patch
+Content-Length: 1396
+Lines: 40
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ATM]: Check IP header validity in mpc_send_packet
+
+[ Upstream commit: 1c9b7aa1eb40ab708ef3242f74b9a61487623168 ]
+
+Al went through the ip_fast_csum callers and found this piece of code
+that did not validate the IP header.  While root crashing the machine
+by sending bogus packets through raw or AF_PACKET sockets isn't that
+serious, it is still nice to react gracefully.
+
+This patch ensures that the skb has enough data for an IP header and
+that the header length field is valid.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/atm/mpc.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/net/atm/mpc.c
++++ b/net/atm/mpc.c
+@@ -542,6 +542,13 @@ static int mpc_send_packet(struct sk_buf
+       if (eth->h_proto != htons(ETH_P_IP))
+               goto non_ip; /* Multi-Protocol Over ATM :-) */
++      /* Weed out funny packets (e.g., AF_PACKET or raw). */
++      if (skb->len < ETH_HLEN + sizeof(struct iphdr))
++              goto non_ip;
++      skb_set_network_header(skb, ETH_HLEN);
++      if (skb->len < ETH_HLEN + ip_hdr(skb)->ihl * 4 || ip_hdr(skb)->ihl < 5)
++              goto non_ip;
++
+       while (i < mpc->number_of_mps_macs) {
+               if (!compare_ether_addr(eth->h_dest, (mpc->mps_macs + i*ETH_ALEN)))
+                       if ( send_via_shortcut(skb, mpc) == 0 )           /* try shortcut */
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:39 2008
+Message-Id: <20080206234438.860494638@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:25 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ Eric Dumazet <dada1@cosmosbay.com>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 23/73] IPV4 ROUTE: ip_rt_dump() is unecessary slow
+Content-Disposition: inline; filename=ipv4-route-ip_rt_dump-is-unecessary-slow.patch
+Content-Length: 4304
+Lines: 74
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Eric Dumazet <dada1@cosmosbay.com>
+
+[IPV4] ROUTE: ip_rt_dump() is unecessary slow
+
+[ Upstream commit: d8c9283089287341c85a0a69de32c2287a990e71 ]
+
+I noticed "ip route list cache x.y.z.t" can be *very* slow.
+
+While strace-ing -T it I also noticed that first part of route cache
+is fetched quite fast :
+
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"p\0\0\0\30\0\2\0\254i\202
+GXm\0\0\2  \0\376\0\0\2\0\2\0"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3772 <0.000047>
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\234\0\0\0\30\0\2\0\254i\
+202GXm\0\0\2  \0\376\0\0\1\0\2"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3736 <0.000042>
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\204\0\0\0\30\0\2\0\254i\
+202GXm\0\0\2  \0\376\0\0\1\0\2"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3740 <0.000055>
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\234\0\0\0\30\0\2\0\254i\
+202GXm\0\0\2  \0\376\0\0\1\0\2"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3712 <0.000043>
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\204\0\0\0\30\0\2\0\254i\
+202GXm\0\0\2  \0\376\0\0\1\0\2"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3732 <0.000053>
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"p\0\0\0\30\0\2\0\254i\202
+GXm\0\0\2  \0\376\0\0\2\0\2\0"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3708 <0.000052>
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"p\0\0\0\30\0\2\0\254i\202
+GXm\0\0\2  \0\376\0\0\2\0\2\0"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3680 <0.000041>
+
+while the part at the end of the table is more expensive:
+
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\204\0\0\0\30\0\2\0\254i\202GXm\0\0\2  \0\376\0\0\1\0\2"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3656 <0.003857>
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\204\0\0\0\30\0\2\0\254i\202GXm\0\0\2  \0\376\0\0\1\0\2"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3772 <0.003891>
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"p\0\0\0\30\0\2\0\254i\202GXm\0\0\2  \0\376\0\0\2\0\2\0"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3712 <0.003765>
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"p\0\0\0\30\0\2\0\254i\202GXm\0\0\2  \0\376\0\0\2\0\2\0"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3700 <0.003879>
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"p\0\0\0\30\0\2\0\254i\202GXm\0\0\2  \0\376\0\0\2\0\2\0"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3676 <0.003797>
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"p\0\0\0\30\0\2\0\254i\202GXm\0\0\2  \0\376\0\0\2\0\2\0"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3724 <0.003856>
+recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\234\0\0\0\30\0\2\0\254i\202GXm\0\0\2  \0\376\0\0\1\0\2"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 3736 <0.003848>
+
+The following patch corrects this performance/latency problem,
+removing quadratic behavior.
+
+Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/ipv4/route.c |    8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -2648,11 +2648,10 @@ int ip_rt_dump(struct sk_buff *skb,  str
+       int idx, s_idx;
+       s_h = cb->args[0];
++      if (s_h < 0)
++              s_h = 0;
+       s_idx = idx = cb->args[1];
+-      for (h = 0; h <= rt_hash_mask; h++) {
+-              if (h < s_h) continue;
+-              if (h > s_h)
+-                      s_idx = 0;
++      for (h = s_h; h <= rt_hash_mask; h++) {
+               rcu_read_lock_bh();
+               for (rt = rcu_dereference(rt_hash_table[h].chain), idx = 0; rt;
+                    rt = rcu_dereference(rt->u.dst.rt_next), idx++) {
+@@ -2669,6 +2668,7 @@ int ip_rt_dump(struct sk_buff *skb,  str
+                       dst_release(xchg(&skb->dst, NULL));
+               }
+               rcu_read_unlock_bh();
++              s_idx = 0;
+       }
+ done:
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:39 2008
+Message-Id: <20080206234439.080909509@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:26 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ Chas Williams <chas@cmf.nrl.navy.mil>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 24/73] ATM: delay irq setup until card is configured
+Content-Disposition: inline; filename=atm-delay-irq-setup-until-card-is-configured.patch
+Content-Length: 1744
+Lines: 58
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Chas Williams <chas@cmf.nrl.navy.mil>
+
+[ATM]: [nicstar] delay irq setup until card is configured
+
+[ Upstream commit: 52961955aa180959158faeb9fd6b4f8a591450f5 ]
+
+Signed-off-by: Chas Williams <chas@cmf.nrl.navy.mil>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/atm/nicstar.c |   19 +++++++++----------
+ 1 file changed, 9 insertions(+), 10 deletions(-)
+
+--- a/drivers/atm/nicstar.c
++++ b/drivers/atm/nicstar.c
+@@ -625,14 +625,6 @@ static int __devinit ns_init_card(int i,
+    if (mac[i] == NULL)
+       nicstar_init_eprom(card->membase);
+-   if (request_irq(pcidev->irq, &ns_irq_handler, IRQF_DISABLED | IRQF_SHARED, "nicstar", card) != 0)
+-   {
+-      printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
+-      error = 9;
+-      ns_init_card_error(card, error);
+-      return error;
+-   }
+-
+    /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */
+    writel(0x00000000, card->membase + VPM);
+       
+@@ -858,8 +850,6 @@ static int __devinit ns_init_card(int i,
+       card->iovpool.count++;
+    }
+-   card->intcnt = 0;
+-
+    /* Configure NICStAR */
+    if (card->rct_size == 4096)
+       ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES;
+@@ -868,6 +858,15 @@ static int __devinit ns_init_card(int i,
+    card->efbie = 1;
++   card->intcnt = 0;
++   if (request_irq(pcidev->irq, &ns_irq_handler, IRQF_DISABLED | IRQF_SHARED, "nicstar", card) != 0)
++   {
++      printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
++      error = 9;
++      ns_init_card_error(card, error);
++      return error;
++   }
++
+    /* Register device */
+    card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
+    if (card->atmdev == NULL)
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:39 2008
+Message-Id: <20080206234439.300363124@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:27 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ Herbert Xu <herbert@gondor.apana.org.au>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 25/73] IPSEC: Avoid undefined shift operation when testing algorithm ID
+Content-Disposition: inline; filename=ipsec-avoid-undefined-shift-operation-when-testing-algorithm-id.patch
+Content-Length: 1703
+Lines: 55
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[IPSEC]: Avoid undefined shift operation when testing algorithm ID
+
+[ Upstream commit: f398035f2dec0a6150833b0bc105057953594edb ]
+
+The aalgos/ealgos fields are only 32 bits wide.  However, af_key tries
+to test them with the expression 1 << id where id can be as large as
+253.  This produces different behaviour on different architectures.
+
+The following patch explicitly checks whether ID is greater than 31
+and fails the check if that's the case.
+
+We cannot easily extend the mask to be longer than 32 bits due to
+exposure to user-space.  Besides, this whole interface is obsolete
+anyway in favour of the xfrm_user interface which doesn't use this
+bit mask in templates (well not within the kernel anyway).
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/key/af_key.c |   14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+--- a/net/key/af_key.c
++++ b/net/key/af_key.c
+@@ -2780,12 +2780,22 @@ static struct sadb_msg *pfkey_get_base_m
+ static inline int aalg_tmpl_set(struct xfrm_tmpl *t, struct xfrm_algo_desc *d)
+ {
+-      return t->aalgos & (1 << d->desc.sadb_alg_id);
++      unsigned int id = d->desc.sadb_alg_id;
++
++      if (id >= sizeof(t->aalgos) * 8)
++              return 0;
++
++      return (t->aalgos >> id) & 1;
+ }
+ static inline int ealg_tmpl_set(struct xfrm_tmpl *t, struct xfrm_algo_desc *d)
+ {
+-      return t->ealgos & (1 << d->desc.sadb_alg_id);
++      unsigned int id = d->desc.sadb_alg_id;
++
++      if (id >= sizeof(t->ealgos) * 8)
++              return 0;
++
++      return (t->ealgos >> id) & 1;
+ }
+ static int count_ah_combs(struct xfrm_tmpl *t)
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:39 2008
+Message-Id: <20080206234439.519463592@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:28 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 26/73] NET: Correct two mistaken skb_reset_mac_header() conversions.
+Content-Disposition: inline; filename=net-correct-two-mistaken-skb_reset_mac_header-conversions.patch
+Content-Length: 1227
+Lines: 48
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: David Miller <davem@davemloft.net>
+
+[NET]: Correct two mistaken skb_reset_mac_header() conversions.
+
+[ Upstream commit: c6e6ca712b5cc06a662f900c0484d49d7334af64 ]
+
+This operation helper abstracts:
+
+       skb->mac_header = skb->data;
+
+but it was done in two more places which were actually:
+
+       skb->mac_header = skb->network_header;
+
+and those are corrected here.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/ax25/ax25_in.c  |    2 +-
+ net/netrom/nr_dev.c |    2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/net/ax25/ax25_in.c
++++ b/net/ax25/ax25_in.c
+@@ -124,7 +124,7 @@ int ax25_rx_iframe(ax25_cb *ax25, struct
+               }
+               skb_pull(skb, 1);       /* Remove PID */
+-              skb_reset_mac_header(skb);
++              skb->mac_header = skb->network_header;
+               skb_reset_network_header(skb);
+               skb->dev      = ax25->ax25_dev->dev;
+               skb->pkt_type = PACKET_HOST;
+--- a/net/netrom/nr_dev.c
++++ b/net/netrom/nr_dev.c
+@@ -56,7 +56,7 @@ int nr_rx_ip(struct sk_buff *skb, struct
+       /* Spoof incoming device */
+       skb->dev      = dev;
+-      skb_reset_mac_header(skb);
++      skb->mac_header = skb->network_header;
+       skb_reset_network_header(skb);
+       skb->pkt_type = PACKET_HOST;
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:39 2008
+Message-Id: <20080206234439.738984598@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:29 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ Timo Teras <timo.teras@iki.fi>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 27/73] IPV4: ip_gre: set mac_header correctly in receive path
+Content-Disposition: inline; filename=ipv4-ip_gre-set-mac_header-correctly-in-receive-path.patch
+Content-Length: 836
+Lines: 30
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Timo Teras <timo.teras@iki.fi>
+
+[IPV4] ip_gre: set mac_header correctly in receive path
+
+[ Upstream commit: 1d0691674764098304ae4c63c715f5883b4d3784 ]
+
+mac_header update in ipgre_recv() was incorrectly changed to
+skb_reset_mac_header() when it was introduced.
+
+Signed-off-by: Timo Teras <timo.teras@iki.fi>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/ipv4/ip_gre.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/ipv4/ip_gre.c
++++ b/net/ipv4/ip_gre.c
+@@ -613,7 +613,7 @@ static int ipgre_rcv(struct sk_buff *skb
+                               offset += 4;
+               }
+-              skb_reset_mac_header(skb);
++              skb->mac_header = skb->network_header;
+               __pskb_pull(skb, offset);
+               skb_reset_network_header(skb);
+               skb_postpull_rcsum(skb, skb_transport_header(skb), offset);
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:40 2008
+Message-Id: <20080206234439.957983956@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:30 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Al Viro <viro@zeniv.linux.org.uk>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 28/73] CASSINI: Fix endianness bug.
+Content-Disposition: inline; filename=cassini_1.patch
+Content-Length: 3131
+Lines: 106
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+[ Upstream commit: e5e025401f6e926c1d9dc3f3f2813cf98a2d8708 ]
+
+Here's proposed fix for RX checksum handling in cassini; it affects
+little-endian working with half-duplex gigabit, but obviously needs
+testing on big-endian too.
+
+The problem is, we need to convert checksum to fixed-endian *before*
+correcting for (unstripped) FCS.  On big-endian it won't matter
+(conversion is no-op), on little-endian it will, but only if FCS is
+not stripped by hardware; i.e. in half-duplex gigabit mode when
+->crc_size is set.
+
+cassini.c part is that fix, cassini.h one consists of trivial
+endianness annotations.  With that applied the sucker is endian-clean,
+according to sparse.
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/cassini.c |    8 +++++---
+ drivers/net/cassini.h |   18 +++++++++---------
+ 2 files changed, 14 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/cassini.c
++++ b/drivers/net/cassini.c
+@@ -1979,6 +1979,7 @@ static int cas_rx_process_pkt(struct cas
+       struct cas_page *page;
+       struct sk_buff *skb;
+       void *addr, *crcaddr;
++      __sum16 csum;
+       char *p;
+       hlen = CAS_VAL(RX_COMP2_HDR_SIZE, words[1]);
+@@ -2158,14 +2159,15 @@ end_copy_pkt:
+               skb_put(skb, alloclen);
+       }
+-      i = CAS_VAL(RX_COMP4_TCP_CSUM, words[3]);
++      csum = (__force __sum16)htons(CAS_VAL(RX_COMP4_TCP_CSUM, words[3]));
+       if (cp->crc_size) {
+               /* checksum includes FCS. strip it out. */
+-              i = csum_fold(csum_partial(crcaddr, cp->crc_size, i));
++              csum = csum_fold(csum_partial(crcaddr, cp->crc_size,
++                                            csum_unfold(csum)));
+               if (addr)
+                       cas_page_unmap(addr);
+       }
+-      skb->csum = ntohs(i ^ 0xffff);
++      skb->csum = csum_unfold(~csum);
+       skb->ip_summed = CHECKSUM_COMPLETE;
+       skb->protocol = eth_type_trans(skb, cp->dev);
+       return len;
+--- a/drivers/net/cassini.h
++++ b/drivers/net/cassini.h
+@@ -4122,8 +4122,8 @@ cas_saturn_patch_t cas_saturn_patch[] = 
+                                                            inserted into
+                                                            outgoing frame. */
+ struct cas_tx_desc {
+-      u64     control;
+-      u64     buffer;
++      __le64     control;
++      __le64     buffer;
+ };
+ /* descriptor ring for free buffers contains page-sized buffers. the index
+@@ -4131,8 +4131,8 @@ struct cas_tx_desc {
+  * the completion ring.
+  */
+ struct cas_rx_desc {
+-      u64     index;
+-      u64     buffer;
++      __le64     index;
++      __le64     buffer;
+ };
+ /* received packets are put on the completion ring. */
+@@ -4210,10 +4210,10 @@ struct cas_rx_desc {
+ #define RX_INDEX_RELEASE                  0x0000000000002000ULL
+ struct cas_rx_comp {
+-      u64     word1;
+-      u64     word2;
+-      u64     word3;
+-      u64     word4;
++      __le64     word1;
++      __le64     word2;
++      __le64     word3;
++      __le64     word4;
+ };
+ enum link_state {
+@@ -4252,7 +4252,7 @@ struct cas_init_block {
+       struct cas_rx_comp rxcs[N_RX_COMP_RINGS][INIT_BLOCK_RX_COMP];
+       struct cas_rx_desc rxds[N_RX_DESC_RINGS][INIT_BLOCK_RX_DESC];
+       struct cas_tx_desc txds[N_TX_RINGS][INIT_BLOCK_TX];
+-      u64 tx_compwb;
++      __le64 tx_compwb;
+ };
+ /* tiny buffers to deal with target abort issue. we allocate a bit
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:40 2008
+Message-Id: <20080206234440.177341225@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:31 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ "David S. Miller" <davem@davemloft.net>,
+ Nick Piggin <npiggin@suse.de>
+Subject: [patch 29/73] CASSINI: Revert dont touch page_count.
+Content-Disposition: inline; filename=cassini_2.patch
+Content-Length: 3740
+Lines: 125
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: David Miller <davem@davemloft.net>
+
+[ Upstream commit: 9de4dfb4c7176e5bb232a21cdd8df78da2b15cac ]
+
+This reverts changeset fa4f0774d7c6cccb4d1fda76b91dd8eddcb2dd6a
+([CASSINI]: dont touch page_count) because it breaks the driver.
+
+The local page counting added by this changeset did not account
+for the asynchronous page count changes done by kfree_skb()
+and friends.
+
+The change adds extra atomics and on top of it all appears to be
+totally unnecessary as well.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Acked-by: Nick Piggin <npiggin@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/cassini.c |   36 ++++--------------------------------
+ 1 file changed, 4 insertions(+), 32 deletions(-)
+
+--- a/drivers/net/cassini.c
++++ b/drivers/net/cassini.c
+@@ -336,30 +336,6 @@ static inline void cas_mask_intr(struct 
+               cas_disable_irq(cp, i);
+ }
+-static inline void cas_buffer_init(cas_page_t *cp)
+-{
+-      struct page *page = cp->buffer;
+-      atomic_set((atomic_t *)&page->lru.next, 1);
+-}
+-
+-static inline int cas_buffer_count(cas_page_t *cp)
+-{
+-      struct page *page = cp->buffer;
+-      return atomic_read((atomic_t *)&page->lru.next);
+-}
+-
+-static inline void cas_buffer_inc(cas_page_t *cp)
+-{
+-      struct page *page = cp->buffer;
+-      atomic_inc((atomic_t *)&page->lru.next);
+-}
+-
+-static inline void cas_buffer_dec(cas_page_t *cp)
+-{
+-      struct page *page = cp->buffer;
+-      atomic_dec((atomic_t *)&page->lru.next);
+-}
+-
+ static void cas_enable_irq(struct cas *cp, const int ring)
+ {
+       if (ring == 0) { /* all but TX_DONE */
+@@ -497,7 +473,6 @@ static int cas_page_free(struct cas *cp,
+ {
+       pci_unmap_page(cp->pdev, page->dma_addr, cp->page_size,
+                      PCI_DMA_FROMDEVICE);
+-      cas_buffer_dec(page);
+       __free_pages(page->buffer, cp->page_order);
+       kfree(page);
+       return 0;
+@@ -527,7 +502,6 @@ static cas_page_t *cas_page_alloc(struct
+       page->buffer = alloc_pages(flags, cp->page_order);
+       if (!page->buffer)
+               goto page_err;
+-      cas_buffer_init(page);
+       page->dma_addr = pci_map_page(cp->pdev, page->buffer, 0,
+                                     cp->page_size, PCI_DMA_FROMDEVICE);
+       return page;
+@@ -606,7 +580,7 @@ static void cas_spare_recover(struct cas
+       list_for_each_safe(elem, tmp, &list) {
+               cas_page_t *page = list_entry(elem, cas_page_t, list);
+-              if (cas_buffer_count(page) > 1)
++              if (page_count(page->buffer) > 1)
+                       continue;
+               list_del(elem);
+@@ -1374,7 +1348,7 @@ static inline cas_page_t *cas_page_spare
+       cas_page_t *page = cp->rx_pages[1][index];
+       cas_page_t *new;
+-      if (cas_buffer_count(page) == 1)
++      if (page_count(page->buffer) == 1)
+               return page;
+       new = cas_page_dequeue(cp);
+@@ -1394,7 +1368,7 @@ static cas_page_t *cas_page_swap(struct 
+       cas_page_t **page1 = cp->rx_pages[1];
+       /* swap if buffer is in use */
+-      if (cas_buffer_count(page0[index]) > 1) {
++      if (page_count(page0[index]->buffer) > 1) {
+               cas_page_t *new = cas_page_spare(cp, index);
+               if (new) {
+                       page1[index] = page0[index];
+@@ -2066,7 +2040,6 @@ static int cas_rx_process_pkt(struct cas
+               skb->len      += hlen - swivel;
+               get_page(page->buffer);
+-              cas_buffer_inc(page);
+               frag->page = page->buffer;
+               frag->page_offset = off;
+               frag->size = hlen - swivel;
+@@ -2091,7 +2064,6 @@ static int cas_rx_process_pkt(struct cas
+                       frag++;
+                       get_page(page->buffer);
+-                      cas_buffer_inc(page);
+                       frag->page = page->buffer;
+                       frag->page_offset = 0;
+                       frag->size = hlen;
+@@ -2255,7 +2227,7 @@ static int cas_post_rxds_ringN(struct ca
+       released = 0;
+       while (entry != last) {
+               /* make a new buffer if it's still in use */
+-              if (cas_buffer_count(page[entry]) > 1) {
++              if (page_count(page[entry]->buffer) > 1) {
+                       cas_page_t *new = cas_page_dequeue(cp);
+                       if (!new) {
+                               /* let the timer know that we need to
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:40 2008
+Message-Id: <20080206234440.396937434@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:32 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 30/73] CASSINI: Set skb->truesize properly on receive packets.
+Content-Disposition: inline; filename=cassini_3.patch
+Content-Length: 668
+Lines: 26
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: David Miller <davem@davemloft.net>
+
+[ Upstream commit: d011a231675b240157a3c335dd53e9b849d7d30d ]
+
+skb->truesize was not being incremented at all to
+reflect the page based data added to RX SKBs.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/cassini.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/cassini.c
++++ b/drivers/net/cassini.c
+@@ -2037,6 +2037,7 @@ static int cas_rx_process_pkt(struct cas
+               skb_shinfo(skb)->nr_frags++;
+               skb->data_len += hlen - swivel;
++              skb->truesize += hlen - swivel;
+               skb->len      += hlen - swivel;
+               get_page(page->buffer);
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:40 2008
+Message-Id: <20080206234440.617186936@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:33 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 31/73] SPARC64: Fix OOPS in dma_sync_*_for_device()
+Content-Disposition: inline; filename=sparc64-fix-oops-in-dma_sync_-_for_device.patch
+Content-Length: 2274
+Lines: 67
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: David Miller <davem@davemloft.net>
+
+[SPARC64]: Fix OOPS in dma_sync_*_for_device()
+
+[ Upstream commit: 36bb61346d9e64b55285f27363e93a6e96f2abba ]
+
+I included these operations vector cases for situations
+where we never need to do anything, the entries aren't
+filled in by any implementation, so we OOPS trying to
+invoke NULL pointer functions.
+
+Really make them NOPs, to fix the bug.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/asm-sparc64/dma-mapping.h |   12 +++---------
+ 1 file changed, 3 insertions(+), 9 deletions(-)
+
+--- a/include/asm-sparc64/dma-mapping.h
++++ b/include/asm-sparc64/dma-mapping.h
+@@ -25,15 +25,9 @@ struct dma_ops {
+       void (*sync_single_for_cpu)(struct device *dev,
+                                   dma_addr_t dma_handle, size_t size,
+                                   enum dma_data_direction direction);
+-      void (*sync_single_for_device)(struct device *dev,
+-                                     dma_addr_t dma_handle, size_t size,
+-                                     enum dma_data_direction direction);
+       void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg,
+                               int nelems,
+                               enum dma_data_direction direction);
+-      void (*sync_sg_for_device)(struct device *dev, struct scatterlist *sg,
+-                                 int nelems,
+-                                 enum dma_data_direction direction);
+ };
+ extern const struct dma_ops *dma_ops;
+@@ -105,7 +99,7 @@ static inline void dma_sync_single_for_d
+                                             size_t size,
+                                             enum dma_data_direction direction)
+ {
+-      dma_ops->sync_single_for_device(dev, dma_handle, size, direction);
++      /* No flushing needed to sync cpu writes to the device.  */
+ }
+ static inline void dma_sync_single_range_for_cpu(struct device *dev,
+@@ -123,7 +117,7 @@ static inline void dma_sync_single_range
+                                                   size_t size,
+                                                   enum dma_data_direction direction)
+ {
+-      dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
++      /* No flushing needed to sync cpu writes to the device.  */
+ }
+@@ -138,7 +132,7 @@ static inline void dma_sync_sg_for_devic
+                                         struct scatterlist *sg, int nelems,
+                                         enum dma_data_direction direction)
+ {
+-      dma_ops->sync_sg_for_device(dev, sg, nelems, direction);
++      /* No flushing needed to sync cpu writes to the device.  */
+ }
+ static inline int dma_mapping_error(dma_addr_t dma_addr)
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:41 2008
+Message-Id: <20080206234440.835773675@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:34 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ bunk@kernel.org,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 32/73] SPARC64: Implement pci_resource_to_user()
+Content-Disposition: inline; filename=sparc64-implement-pci_resource_to_user.patch
+Content-Length: 1574
+Lines: 55
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: David Miller <davem@davemloft.net>
+
+[SPARC64]: Implement pci_resource_to_user()
+
+[ Upstream commit: bcea1db16ba1c45ccebb3bfb8441642d1342c4d5 ]
+
+This makes libpciaccess able to mmap() resources of the
+device properly.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/sparc64/kernel/pci.c |   16 ++++++++++++++++
+ include/asm-sparc64/pci.h |    4 ++++
+ 2 files changed, 20 insertions(+)
+
+--- a/arch/sparc64/kernel/pci.c
++++ b/arch/sparc64/kernel/pci.c
+@@ -1276,4 +1276,20 @@ int pci_dma_supported(struct pci_dev *pd
+       return (device_mask & dma_addr_mask) == dma_addr_mask;
+ }
++void pci_resource_to_user(const struct pci_dev *pdev, int bar,
++                        const struct resource *rp, resource_size_t *start,
++                        resource_size_t *end)
++{
++      struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
++      unsigned long offset;
++
++      if (rp->flags & IORESOURCE_IO)
++              offset = pbm->io_space.start;
++      else
++              offset = pbm->mem_space.start;
++
++      *start = rp->start - offset;
++      *end = rp->end - offset;
++}
++
+ #endif /* !(CONFIG_PCI) */
+--- a/include/asm-sparc64/pci.h
++++ b/include/asm-sparc64/pci.h
+@@ -200,6 +200,10 @@ static inline int pci_get_legacy_ide_irq
+ struct device_node;
+ extern struct device_node *pci_device_to_OF_node(struct pci_dev *pdev);
++#define HAVE_ARCH_PCI_RESOURCE_TO_USER
++extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
++                               const struct resource *rsrc,
++                               resource_size_t *start, resource_size_t *end);
+ #endif /* __KERNEL__ */
+ #endif /* __SPARC64_PCI_H */
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:41 2008
+Message-Id: <20080206234441.054961766@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:35 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ linux-acpi@vger.kernel.org,
+ Adrian Bunk <bunk@stusta.de>,
+ Bob Moore <robert.moore@intel.com>,
+ Len Brown <len.brown@intel.com>
+Subject: [patch 33/73] ACPICA: fix acpi-cpufreq boot crash due to _PSD return-by-reference
+Content-Disposition: inline; filename=acpica-fix-acpi-cpufreq-boot-crash-due-to-_psd-return-by-reference.patch
+Content-Length: 4661
+Lines: 144
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Bob Moore <robert.moore@intel.com>
+
+patch 152c300d007c70c4a1847dad39ecdaba22e7d457 in mainline.
+
+Changed resolution of named references in packages
+
+Fixed a problem with the Package operator where all named
+references were created as object references and left otherwise
+unresolved. According to the ACPI specification, a Package can
+only contain Data Objects or references to control methods. The
+implication is that named references to Data Objects (Integer,
+Buffer, String, Package, BufferField, Field) should be resolved
+immediately upon package creation. This is the approach taken
+with this change. References to all other named objects (Methods,
+Devices, Scopes, etc.) are all now properly created as reference objects.
+
+http://bugzilla.kernel.org/show_bug.cgi?id=5328
+http://bugzilla.kernel.org/show_bug.cgi?id=9429
+
+Signed-off-by: Bob Moore <robert.moore@intel.com>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/dispatcher/dsobject.c |   91 ++++++++++++++++++++++++++++++++++---
+ 1 file changed, 85 insertions(+), 6 deletions(-)
+
+--- a/drivers/acpi/dispatcher/dsobject.c
++++ b/drivers/acpi/dispatcher/dsobject.c
+@@ -137,6 +137,71 @@ acpi_ds_build_internal_object(struct acp
+                               return_ACPI_STATUS(status);
+                       }
+               }
++
++              /* Special object resolution for elements of a package */
++
++              if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) ||
++                  (op->common.parent->common.aml_opcode ==
++                   AML_VAR_PACKAGE_OP)) {
++                      /*
++                       * Attempt to resolve the node to a value before we insert it into
++                       * the package. If this is a reference to a common data type,
++                       * resolve it immediately. According to the ACPI spec, package
++                       * elements can only be "data objects" or method references.
++                       * Attempt to resolve to an Integer, Buffer, String or Package.
++                       * If cannot, return the named reference (for things like Devices,
++                       * Methods, etc.) Buffer Fields and Fields will resolve to simple
++                       * objects (int/buf/str/pkg).
++                       *
++                       * NOTE: References to things like Devices, Methods, Mutexes, etc.
++                       * will remain as named references. This behavior is not described
++                       * in the ACPI spec, but it appears to be an oversight.
++                       */
++                      obj_desc = (union acpi_operand_object *)op->common.node;
++
++                      status =
++                          acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR
++                                                        (struct
++                                                         acpi_namespace_node,
++                                                         &obj_desc),
++                                                        walk_state);
++                      if (ACPI_FAILURE(status)) {
++                              return_ACPI_STATUS(status);
++                      }
++
++                      switch (op->common.node->type) {
++                              /*
++                               * For these types, we need the actual node, not the subobject.
++                               * However, the subobject got an extra reference count above.
++                               */
++                      case ACPI_TYPE_MUTEX:
++                      case ACPI_TYPE_METHOD:
++                      case ACPI_TYPE_POWER:
++                      case ACPI_TYPE_PROCESSOR:
++                      case ACPI_TYPE_EVENT:
++                      case ACPI_TYPE_REGION:
++                      case ACPI_TYPE_DEVICE:
++                      case ACPI_TYPE_THERMAL:
++
++                              obj_desc =
++                                  (union acpi_operand_object *)op->common.
++                                  node;
++                              break;
++
++                      default:
++                              break;
++                      }
++
++                      /*
++                       * If above resolved to an operand object, we are done. Otherwise,
++                       * we have a NS node, we must create the package entry as a named
++                       * reference.
++                       */
++                      if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) !=
++                          ACPI_DESC_TYPE_NAMED) {
++                              goto exit;
++                      }
++              }
+       }
+       /* Create and init a new internal ACPI object */
+@@ -156,6 +221,7 @@ acpi_ds_build_internal_object(struct acp
+               return_ACPI_STATUS(status);
+       }
++      exit:
+       *obj_desc_ptr = obj_desc;
+       return_ACPI_STATUS(AE_OK);
+ }
+@@ -356,12 +422,25 @@ acpi_ds_build_internal_package_obj(struc
+       arg = arg->common.next;
+       for (i = 0; arg && (i < element_count); i++) {
+               if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
+-
+-                      /* This package element is already built, just get it */
+-
+-                      obj_desc->package.elements[i] =
+-                          ACPI_CAST_PTR(union acpi_operand_object,
+-                                        arg->common.node);
++                      if (arg->common.node->type == ACPI_TYPE_METHOD) {
++                              /*
++                               * A method reference "looks" to the parser to be a method
++                               * invocation, so we special case it here
++                               */
++                              arg->common.aml_opcode = AML_INT_NAMEPATH_OP;
++                              status =
++                                  acpi_ds_build_internal_object(walk_state,
++                                                                arg,
++                                                                &obj_desc->
++                                                                package.
++                                                                elements[i]);
++                      } else {
++                              /* This package element is already built, just get it */
++
++                              obj_desc->package.elements[i] =
++                                  ACPI_CAST_PTR(union acpi_operand_object,
++                                                arg->common.node);
++                      }
+               } else {
+                       status = acpi_ds_build_internal_object(walk_state, arg,
+                                                              &obj_desc->
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:41 2008
+Message-Id: <20080206234441.275190213@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:36 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Zhao Yakui <yakui.zhao@intel.com>,
+ Zhang Rui <rui.zhang@intel.com>,
+ Len Brown <len.brown@intel.com>
+Subject: [patch 34/73] ACPI: Not register gsi for PCI IDE controller in legacy mode
+Content-Disposition: inline; filename=acpi-not-register-gsi-for-pci-ide-controller-in-legacy-mode.patch
+Content-Length: 1253
+Lines: 42
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Alan Cox <alan@lxorguk.ukuu.org.uk>
+
+patch 96c2a8766bf4fe91abac863749c11637fabcc64f in mainline.
+
+When PCI IDE controller works in legacy mode and no PRT entry is found
+in ACPI PRT table, OSPM will neither read the irq number from the IDE
+PCI configuration space nor call the function of acpi_register_gsi to
+register gsi.
+
+http://bugzilla.kernel.org/show_bug.cgi?id=5637
+
+Signed-off-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
+Signed-off-by: Zhang Rui <rui.zhang@intel.com>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/pci_irq.c |    9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/acpi/pci_irq.c
++++ b/drivers/acpi/pci_irq.c
+@@ -429,6 +429,15 @@ int acpi_pci_irq_enable(struct pci_dev *
+                                         &polarity, &link,
+                                         acpi_pci_allocate_irq);
++      if (irq < 0) {
++              /*
++               * IDE legacy mode controller IRQs are magic. Why do compat
++               * extensions always make such a nasty mess.
++               */
++              if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE &&
++                              (dev->class & 0x05) == 0)
++                      return 0;
++      }
+       /*
+        * No IRQ known to the ACPI subsystem - maybe the BIOS / 
+        * driver reported one, then use it. Exit in any case.
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:41 2008
+Message-Id: <20080206234441.494505939@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:37 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Bob Moore <robert.moore@intel.com>,
+ Len Brown <len.brown@intel.com>
+Subject: [patch 35/73] ACPICA: fix acpi_serialize hang regression
+Content-Disposition: inline; filename=acpica-fix-acpi_serialize-hang-regression.patch
+Content-Length: 1615
+Lines: 54
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Bob Moore <robert.moore@intel.com>
+
+patch 014d433f35d7f34b55dcc7b57c7635aaefc3757f in mainline.
+
+http://bugzilla.kernel.org/show_bug.cgi?id=8171
+
+Signed-off-by: Bob Moore <robert.moore@intel.com>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/events/evregion.c |    8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/acpi/events/evregion.c
++++ b/drivers/acpi/events/evregion.c
+@@ -344,7 +344,7 @@ acpi_ev_address_space_dispatch(union acp
+                * setup will potentially execute control methods
+                * (e.g., _REG method for this region)
+                */
+-              acpi_ex_relinquish_interpreter();
++              acpi_ex_exit_interpreter();
+               status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
+                                     handler_desc->address_space.context,
+@@ -352,7 +352,7 @@ acpi_ev_address_space_dispatch(union acp
+               /* Re-enter the interpreter */
+-              acpi_ex_reacquire_interpreter();
++              acpi_ex_enter_interpreter();
+               /* Check for failure of the Region Setup */
+@@ -405,7 +405,7 @@ acpi_ev_address_space_dispatch(union acp
+                * exit the interpreter because the handler *might* block -- we don't
+                * know what it will do, so we can't hold the lock on the intepreter.
+                */
+-              acpi_ex_relinquish_interpreter();
++              acpi_ex_exit_interpreter();
+       }
+       /* Call the handler */
+@@ -426,7 +426,7 @@ acpi_ev_address_space_dispatch(union acp
+                * We just returned from a non-default handler, we must re-enter the
+                * interpreter
+                */
+-              acpi_ex_reacquire_interpreter();
++              acpi_ex_enter_interpreter();
+       }
+       return_ACPI_STATUS(status);
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:41 2008
+Message-Id: <20080206234441.713766671@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:38 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Zhao Yakui <yakui.zhao@intel.com>,
+ Len Brown <len.brown@intel.com>
+Subject: [patch 36/73] ACPI: apply quirk_ich6_lpc_acpi to more ICH8 and ICH9
+Content-Disposition: inline; filename=acpi-apply-quirk_ich6_lpc_acpi-to-more-ich8-and-ich9.patch
+Content-Length: 1962
+Lines: 44
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Zhao Yakui <yakui.zhao@intel.com>
+
+patch d1ec7298fcefd7e4d1ca612da402ce9e5d5e2c13 in mainline.
+
+It is important that these resources be reserved
+to avoid conflicts with well known ACPI registers.
+
+Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/pci/quirks.c    |    6 ++++++
+ include/linux/pci_ids.h |    2 ++
+ 2 files changed, 8 insertions(+)
+
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -465,6 +465,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi );
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi );
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich6_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich6_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich6_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich6_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich6_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich6_lpc_acpi );
+ /*
+  * VIA ACPI: One IO region pointed to by longword at
+--- a/include/linux/pci_ids.h
++++ b/include/linux/pci_ids.h
+@@ -2287,6 +2287,8 @@
+ #define PCI_DEVICE_ID_INTEL_ICH9_4    0x2914
+ #define PCI_DEVICE_ID_INTEL_ICH9_5    0x2919
+ #define PCI_DEVICE_ID_INTEL_ICH9_6    0x2930
++#define PCI_DEVICE_ID_INTEL_ICH9_7    0x2916
++#define PCI_DEVICE_ID_INTEL_ICH9_8    0x2918
+ #define PCI_DEVICE_ID_INTEL_82855PM_HB        0x3340
+ #define PCI_DEVICE_ID_INTEL_82830_HB  0x3575
+ #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:42 2008
+Message-Id: <20080206234441.933729155@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:39 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Len Brown <len.brown@intel.com>,
+ "Rafael J. Wysocki" <rjw@sisk.pl>
+Subject: [patch 37/73] PM: ACPI and APM must not be enabled at the same time
+Content-Disposition: inline; filename=pm-acpi-and-apm-must-not-be-enabled-at-the-same-time.patch
+Content-Length: 3932
+Lines: 165
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Len Brown <len.brown@intel.com>
+
+patch 9f9adecd2d0e4f88fa0e8cb06c6ec207748df70a in mainline.
+
+ACPI and APM used "pm_active" to guarantee that
+they would not be simultaneously active.
+
+But pm_active was recently moved under CONFIG_PM_LEGACY,
+so that without CONFIG_PM_LEGACY, pm_active became a NOP --
+allowing ACPI and APM to both be simultaneously enabled.
+This caused unpredictable results, including boot hangs.
+
+Further, the code under CONFIG_PM_LEGACY is scheduled
+for removal.
+
+So replace pm_active with pm_flags.
+pm_flags depends only on CONFIG_PM,
+which is present for both CONFIG_APM and CONFIG_ACPI.
+
+http://bugzilla.kernel.org/show_bug.cgi?id=9194
+
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/i386/kernel/apm.c    |   10 +++-------
+ drivers/acpi/bus.c        |    7 ++-----
+ include/linux/pm.h        |    9 +++++++++
+ include/linux/pm_legacy.h |    6 ------
+ kernel/power/main.c       |    3 +++
+ kernel/power/pm.c         |    4 ----
+ 6 files changed, 17 insertions(+), 22 deletions(-)
+
+--- a/arch/i386/kernel/apm.c
++++ b/arch/i386/kernel/apm.c
+@@ -2256,14 +2256,12 @@ static int __init apm_init(void)
+               apm_info.disabled = 1;
+               return -ENODEV;
+       }
+-      if (PM_IS_ACTIVE()) {
++      if (pm_flags & PM_ACPI) {
+               printk(KERN_NOTICE "apm: overridden by ACPI.\n");
+               apm_info.disabled = 1;
+               return -ENODEV;
+       }
+-#ifdef CONFIG_PM_LEGACY
+-      pm_active = 1;
+-#endif
++      pm_flags |= PM_APM;
+       /*
+        * Set up a segment that references the real mode segment 0x40
+@@ -2366,9 +2364,7 @@ static void __exit apm_exit(void)
+               kthread_stop(kapmd_task);
+               kapmd_task = NULL;
+       }
+-#ifdef CONFIG_PM_LEGACY
+-      pm_active = 0;
+-#endif
++      pm_flags &= ~PM_APM;
+ }
+ module_init(apm_init);
+--- a/drivers/acpi/bus.c
++++ b/drivers/acpi/bus.c
+@@ -29,7 +29,6 @@
+ #include <linux/list.h>
+ #include <linux/sched.h>
+ #include <linux/pm.h>
+-#include <linux/pm_legacy.h>
+ #include <linux/device.h>
+ #include <linux/proc_fs.h>
+ #ifdef CONFIG_X86
+@@ -757,16 +756,14 @@ static int __init acpi_init(void)
+       result = acpi_bus_init();
+       if (!result) {
+-#ifdef CONFIG_PM_LEGACY
+-              if (!PM_IS_ACTIVE())
+-                      pm_active = 1;
++              if (!(pm_flags & PM_APM))
++                      pm_flags |= PM_ACPI;
+               else {
+                       printk(KERN_INFO PREFIX
+                              "APM is already active, exiting\n");
+                       disable_acpi();
+                       result = -ENODEV;
+               }
+-#endif
+       } else
+               disable_acpi();
+--- a/include/linux/pm.h
++++ b/include/linux/pm.h
+@@ -344,6 +344,15 @@ static inline int call_platform_enable_w
+               device_set_wakeup_enable(dev,val); \
+       } while(0)
++/*
++ * Global Power Management flags
++ * Used to keep APM and ACPI from both being active
++ */
++extern unsigned int   pm_flags;
++
++#define PM_APM        1
++#define PM_ACPI       2
++
+ #endif /* __KERNEL__ */
+ #endif /* _LINUX_PM_H */
+--- a/include/linux/pm_legacy.h
++++ b/include/linux/pm_legacy.h
+@@ -4,10 +4,6 @@
+ #ifdef CONFIG_PM_LEGACY
+-extern int pm_active;
+-
+-#define PM_IS_ACTIVE() (pm_active != 0)
+-
+ /*
+  * Register a device with power management
+  */
+@@ -21,8 +17,6 @@ int __deprecated pm_send_all(pm_request_
+ #else /* CONFIG_PM_LEGACY */
+-#define PM_IS_ACTIVE() 0
+-
+ static inline struct pm_dev *pm_register(pm_dev_t type,
+                                        unsigned long id,
+                                        pm_callback callback)
+--- a/kernel/power/main.c
++++ b/kernel/power/main.c
+@@ -27,6 +27,9 @@ BLOCKING_NOTIFIER_HEAD(pm_chain_head);
+ DEFINE_MUTEX(pm_mutex);
++unsigned int pm_flags;
++EXPORT_SYMBOL(pm_flags);
++
+ #ifdef CONFIG_SUSPEND
+ /* This is just an arbitrary number */
+--- a/kernel/power/pm.c
++++ b/kernel/power/pm.c
+@@ -27,8 +27,6 @@
+ #include <linux/interrupt.h>
+ #include <linux/mutex.h>
+-int pm_active;
+-
+ /*
+  *    Locking notes:
+  *            pm_devs_lock can be a semaphore providing pm ops are not called
+@@ -204,6 +202,4 @@ int pm_send_all(pm_request_t rqst, void 
+ EXPORT_SYMBOL(pm_register);
+ EXPORT_SYMBOL(pm_send_all);
+-EXPORT_SYMBOL(pm_active);
+-
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:42 2008
+Message-Id: <20080206234442.154111788@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:40 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Herbert Xu <herbert@gondor.apana.org.au>
+Subject: [patch 38/73] CRYPTO: padlock: Fix spurious ECB page fault
+Content-Disposition: inline; filename=crypto-padlock-fix-spurious-ecb-page-fault.patch
+Content-Length: 3203
+Lines: 99
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[CRYPTO] padlock: Fix spurious ECB page fault
+
+[ Upstream commit: d4a7dd8e637b322faaa934ffcd6dd07711af831f ]
+[ Upstream commit: 490fe3f05be3f7c87d7932bcb6e6e53e3db2cd9c ]
+
+The xcryptecb instruction always processes an even number of blocks so
+we need to ensure th existence of an extra block if we have to process
+an odd number of blocks.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/crypto/padlock-aes.c |   53 +++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 49 insertions(+), 4 deletions(-)
+
+--- a/drivers/crypto/padlock-aes.c
++++ b/drivers/crypto/padlock-aes.c
+@@ -419,13 +419,58 @@ static int aes_set_key(struct crypto_tfm
+ /* ====== Encryption/decryption routines ====== */
+ /* These are the real call to PadLock. */
++static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key,
++                                void *control_word)
++{
++      asm volatile (".byte 0xf3,0x0f,0xa7,0xc8"       /* rep xcryptecb */
++                    : "+S"(input), "+D"(output)
++                    : "d"(control_word), "b"(key), "c"(1));
++}
++
++static void aes_crypt_copy(const u8 *in, u8 *out, u32 *key, struct cword *cword)
++{
++      u8 buf[AES_BLOCK_SIZE * 2 + PADLOCK_ALIGNMENT - 1];
++      u8 *tmp = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT);
++
++      memcpy(tmp, in, AES_BLOCK_SIZE);
++      padlock_xcrypt(tmp, out, key, cword);
++}
++
++static inline void aes_crypt(const u8 *in, u8 *out, u32 *key,
++                           struct cword *cword)
++{
++      asm volatile ("pushfl; popfl");
++
++      /* padlock_xcrypt requires at least two blocks of data. */
++      if (unlikely(!(((unsigned long)in ^ (PAGE_SIZE - AES_BLOCK_SIZE)) &
++                     (PAGE_SIZE - 1)))) {
++              aes_crypt_copy(in, out, key, cword);
++              return;
++      }
++
++      padlock_xcrypt(in, out, key, cword);
++}
++
+ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
+                                     void *control_word, u32 count)
+ {
++      if (count == 1) {
++              aes_crypt(input, output, key, control_word);
++              return;
++      }
++
+       asm volatile ("pushfl; popfl");         /* enforce key reload. */
+-      asm volatile (".byte 0xf3,0x0f,0xa7,0xc8"       /* rep xcryptecb */
++      asm volatile ("test $1, %%cl;"
++                    "je 1f;"
++                    "lea -1(%%ecx), %%eax;"
++                    "mov $1, %%ecx;"
++                    ".byte 0xf3,0x0f,0xa7,0xc8;"      /* rep xcryptecb */
++                    "mov %%eax, %%ecx;"
++                    "1:"
++                    ".byte 0xf3,0x0f,0xa7,0xc8"       /* rep xcryptecb */
+                     : "+S"(input), "+D"(output)
+-                    : "d"(control_word), "b"(key), "c"(count));
++                    : "d"(control_word), "b"(key), "c"(count)
++                    : "ax");
+ }
+ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
+@@ -443,13 +488,13 @@ static inline u8 *padlock_xcrypt_cbc(con
+ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+ {
+       struct aes_ctx *ctx = aes_ctx(tfm);
+-      padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt, 1);
++      aes_crypt(in, out, ctx->E, &ctx->cword.encrypt);
+ }
+ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+ {
+       struct aes_ctx *ctx = aes_ctx(tfm);
+-      padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, 1);
++      aes_crypt(in, out, ctx->D, &ctx->cword.decrypt);
+ }
+ static struct crypto_alg aes_alg = {
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:42 2008
+Message-Id: <20080206234442.372908680@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:41 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org,
+ Greg KH <greg@kroah.com>
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk
+Subject: [patch 39/73] USB: update sierra.c with latest device ids that are in 2.6.24-rc7
+Content-Disposition: inline; filename=usb-update-sierra.c-with-latest-device-ids-that-are-in-2.6.24-rc7.patch
+Content-Length: 2360
+Lines: 44
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Greg Kroah-Hartman <gregkh@suse.de>
+
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/sierra.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/usb/serial/sierra.c
++++ b/drivers/usb/serial/sierra.c
+@@ -100,6 +100,7 @@ static struct usb_device_id id_table [] 
+       { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
++      { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */
+       { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
+       { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+       { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
+@@ -108,6 +109,7 @@ static struct usb_device_id id_table [] 
+       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
+       { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
+       { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
++      { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Thinkpad internal) */
+       { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+       { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
+       { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
+@@ -136,6 +138,7 @@ static struct usb_device_id id_table_3po
+       { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
++      { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */
+       { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
+       { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+       { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/
+@@ -144,6 +147,7 @@ static struct usb_device_id id_table_3po
+       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
+       { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
+       { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
++      { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Thinkpad internal) */
+       { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+       { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
+       { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:42 2008
+Message-Id: <20080206234442.593177242@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:42 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Thomas Gleixner <tglx@linutronix.de>,
+ Ingo Molnar <mingo@elte.hu>
+Subject: [patch 40/73] clockevents: fix reprogramming decision in oneshot broadcast
+Content-Disposition: inline; filename=clockevents-fix-reprogramming-decision-in-oneshot-broadcast.patch
+Content-Length: 3675
+Lines: 120
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Thomas Gleixner <tglx@linutronix.de>
+
+patch cdc6f27d9e3c2f7ca1a3e19c6eabb1ad6a2add5d in mainline.
+
+A previous version of the code did the reprogramming of the broadcast
+device in the return from idle code. This was removed, but the logic in
+tick_handle_oneshot_broadcast() was kept the same.
+
+When a broadcast interrupt happens we signal the expiry to all CPUs
+which have an expired event. If none of the CPUs has an expired event,
+which can happen in dyntick mode, then we reprogram the broadcast
+device. We do not reprogram otherwise, but this is only correct if all
+CPUs, which are in the idle broadcast state have been woken up.
+
+The code ignores, that there might be pending not yet expired events on
+other CPUs, which are in the idle broadcast state. So the delivery of
+those events can be delayed for quite a time.
+
+Change the tick_handle_oneshot_broadcast() function to check for CPUs,
+which are in broadcast state and are not woken up by the current event,
+and enforce the rearming of the broadcast device for those CPUs.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Ingo Molnar <mingo@elte.hu>
+
+---
+ kernel/time/tick-broadcast.c |   56 ++++++++++++++++---------------------------
+ 1 file changed, 21 insertions(+), 35 deletions(-)
+
+--- a/kernel/time/tick-broadcast.c
++++ b/kernel/time/tick-broadcast.c
+@@ -387,45 +387,19 @@ int tick_resume_broadcast_oneshot(struct
+ }
+ /*
+- * Reprogram the broadcast device:
+- *
+- * Called with tick_broadcast_lock held and interrupts disabled.
+- */
+-static int tick_broadcast_reprogram(void)
+-{
+-      ktime_t expires = { .tv64 = KTIME_MAX };
+-      struct tick_device *td;
+-      int cpu;
+-
+-      /*
+-       * Find the event which expires next:
+-       */
+-      for (cpu = first_cpu(tick_broadcast_oneshot_mask); cpu != NR_CPUS;
+-           cpu = next_cpu(cpu, tick_broadcast_oneshot_mask)) {
+-              td = &per_cpu(tick_cpu_device, cpu);
+-              if (td->evtdev->next_event.tv64 < expires.tv64)
+-                      expires = td->evtdev->next_event;
+-      }
+-
+-      if (expires.tv64 == KTIME_MAX)
+-              return 0;
+-
+-      return tick_broadcast_set_event(expires, 0);
+-}
+-
+-/*
+  * Handle oneshot mode broadcasting
+  */
+ static void tick_handle_oneshot_broadcast(struct clock_event_device *dev)
+ {
+       struct tick_device *td;
+       cpumask_t mask;
+-      ktime_t now;
++      ktime_t now, next_event;
+       int cpu;
+       spin_lock(&tick_broadcast_lock);
+ again:
+       dev->next_event.tv64 = KTIME_MAX;
++      next_event.tv64 = KTIME_MAX;
+       mask = CPU_MASK_NONE;
+       now = ktime_get();
+       /* Find all expired events */
+@@ -434,19 +408,31 @@ again:
+               td = &per_cpu(tick_cpu_device, cpu);
+               if (td->evtdev->next_event.tv64 <= now.tv64)
+                       cpu_set(cpu, mask);
++              else if (td->evtdev->next_event.tv64 < next_event.tv64)
++                      next_event.tv64 = td->evtdev->next_event.tv64;
+       }
+       /*
+-       * Wakeup the cpus which have an expired event. The broadcast
+-       * device is reprogrammed in the return from idle code.
++       * Wakeup the cpus which have an expired event.
++       */
++      tick_do_broadcast(mask);
++
++      /*
++       * Two reasons for reprogram:
++       *
++       * - The global event did not expire any CPU local
++       * events. This happens in dyntick mode, as the maximum PIT
++       * delta is quite small.
++       *
++       * - There are pending events on sleeping CPUs which were not
++       * in the event mask
+        */
+-      if (!tick_do_broadcast(mask)) {
++      if (next_event.tv64 != KTIME_MAX) {
+               /*
+-               * The global event did not expire any CPU local
+-               * events. This happens in dyntick mode, as the
+-               * maximum PIT delta is quite small.
++               * Rearm the broadcast device. If event expired,
++               * repeat the above
+                */
+-              if (tick_broadcast_reprogram())
++              if (tick_broadcast_set_event(next_event, 0))
+                       goto again;
+       }
+       spin_unlock(&tick_broadcast_lock);
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:43 2008
+Message-Id: <20080206234442.813032280@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:43 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org,
+ Greg KH <greg@kroah.com>
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ "Rafael J. Wysocki" <rjw@sisk.pl>
+Subject: [patch 41/73] Freezer: Fix APM emulation breakage
+Content-Disposition: inline; filename=freezer-fix-apm-emulation-breakage.patch
+Content-Length: 3454
+Lines: 113
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Rafael J. Wysocki <rjw@sisk.pl>
+
+The APM emulation is currently broken as a result of commit
+831441862956fffa17b9801db37e6ea1650b0f69
+"Freezer: make kernel threads nonfreezable by default"
+that removed the PF_NOFREEZE annotations from apm_ioctl() without
+adding the appropriate freezer hooks.  Fix it and remove the
+unnecessary variable flags from apm_ioctl().
+
+This problem has been fixed in the mainline by
+commit cb43c54ca05c01533c45e4d3abfe8f99b7acf624
+"Freezer: Fix APM emulation breakage".
+
+Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/apm-emulation.c |   15 ++++++++-------
+ include/linux/freezer.h      |   23 +++++++++++++++++++++++
+ 2 files changed, 31 insertions(+), 7 deletions(-)
+
+--- a/drivers/char/apm-emulation.c
++++ b/drivers/char/apm-emulation.c
+@@ -295,7 +295,6 @@ static int
+ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
+ {
+       struct apm_user *as = filp->private_data;
+-      unsigned long flags;
+       int err = -EINVAL;
+       if (!as->suser || !as->writer)
+@@ -331,10 +330,16 @@ apm_ioctl(struct inode * inode, struct f
+                        * Wait for the suspend/resume to complete.  If there
+                        * are pending acknowledges, we wait here for them.
+                        */
+-                      flags = current->flags;
++                      freezer_do_not_count();
+                       wait_event(apm_suspend_waitqueue,
+                                  as->suspend_state == SUSPEND_DONE);
++
++                      /*
++                       * Since we are waiting until the suspend is done, the
++                       * try_to_freeze() in freezer_count() will not trigger
++                       */
++                      freezer_count();
+               } else {
+                       as->suspend_state = SUSPEND_WAIT;
+                       mutex_unlock(&state_lock);
+@@ -362,14 +367,10 @@ apm_ioctl(struct inode * inode, struct f
+                        * Wait for the suspend/resume to complete.  If there
+                        * are pending acknowledges, we wait here for them.
+                        */
+-                      flags = current->flags;
+-
+-                      wait_event_interruptible(apm_suspend_waitqueue,
++                      wait_event_freezable(apm_suspend_waitqueue,
+                                        as->suspend_state == SUSPEND_DONE);
+               }
+-              current->flags = flags;
+-
+               mutex_lock(&state_lock);
+               err = as->suspend_result;
+               as->suspend_state = SUSPEND_NONE;
+--- a/include/linux/freezer.h
++++ b/include/linux/freezer.h
+@@ -4,6 +4,7 @@
+ #define FREEZER_H_INCLUDED
+ #include <linux/sched.h>
++#include <linux/wait.h>
+ #ifdef CONFIG_PM_SLEEP
+ /*
+@@ -126,6 +127,24 @@ static inline void set_freezable(void)
+       current->flags &= ~PF_NOFREEZE;
+ }
++/*
++ * Freezer-friendly wrapper around wait_event_interruptible(), originally
++ * defined in <linux/wait.h>
++ */
++
++#define wait_event_freezable(wq, condition)                           \
++({                                                                    \
++      int __retval;                                                   \
++      do {                                                            \
++              __retval = wait_event_interruptible(wq,                 \
++                              (condition) || freezing(current));      \
++              if (__retval && !freezing(current))                     \
++                      break;                                          \
++              else if (!(condition))                                  \
++                      __retval = -ERESTARTSYS;                        \
++      } while (try_to_freeze());                                      \
++      __retval;                                                       \
++})
+ #else /* !CONFIG_PM_SLEEP */
+ static inline int frozen(struct task_struct *p) { return 0; }
+ static inline int freezing(struct task_struct *p) { return 0; }
+@@ -143,6 +162,10 @@ static inline void freezer_do_not_count(
+ static inline void freezer_count(void) {}
+ static inline int freezer_should_skip(struct task_struct *p) { return 0; }
+ static inline void set_freezable(void) {}
++
++#define wait_event_freezable(wq, condition)                           \
++              wait_event_interruptible(wq, condition)
++
+ #endif /* !CONFIG_PM_SLEEP */
+ #endif        /* FREEZER_H_INCLUDED */
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:43 2008
+Message-Id: <20080206234443.037651509@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:44 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Ingo Molnar <mingo@elte.hu>,
+ Alan Cox <alan@redhat.com>,
+ Christoph Hellwig <hch@lst.de>,
+ Al Viro <viro@ftp.linux.org.uk>,
+ maximilian attems <max@stro.at>
+Subject: [patch 42/73] vfs: coredumping fix (CVE-2007-6206)
+Content-Disposition: inline; filename=vfs-coredumping-fix.patch
+Content-Length: 1073
+Lines: 41
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Ingo Molnar <mingo@elte.hu>
+
+vfs: coredumping fix
+
+patch c46f739dd39db3b07ab5deb4e3ec81e1c04a91af in mainline
+
+fix: http://bugzilla.kernel.org/show_bug.cgi?id=3043
+
+only allow coredumping to the same uid that the coredumping
+task runs under.
+
+Signed-off-by: Ingo Molnar <mingo@elte.hu>
+Acked-by: Alan Cox <alan@redhat.com>
+Acked-by: Christoph Hellwig <hch@lst.de>
+Acked-by: Al Viro <viro@ftp.linux.org.uk>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: maximilian attems <max@stro.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/exec.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -1786,6 +1786,12 @@ int do_coredump(long signr, int exit_cod
+          but keep the previous behaviour for now. */
+       if (!ispipe && !S_ISREG(inode->i_mode))
+               goto close_fail;
++      /*
++       * Dont allow local users get cute and trick others to coredump
++       * into their pre-created files:
++       */
++      if (inode->i_uid != current->fsuid)
++              goto close_fail;
+       if (!file->f_op)
+               goto close_fail;
+       if (!file->f_op->write)
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:43 2008
+Message-Id: <20080206234443.258473934@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:45 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org,
+ torvalds@linux-foundation.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ dhaval@linux.vnet.ibm.com,
+ clameter@sgi.com
+Subject: [patch 43/73] quicklists: do not release off node pages early
+Content-Disposition: inline; filename=quicklists-do-not-release-off-node-pages-early.patch
+Content-Length: 929
+Lines: 37
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Christoph Lameter <clameter@sgi.com>
+
+patch ed367fc3a7349b17354c7acef551533337764859 in mainline.
+
+quicklists must keep even off node pages on the quicklists until the TLB
+flush has been completed.
+
+Signed-off-by: Christoph Lameter <clameter@sgi.com>
+Cc: Dhaval Giani <dhaval@linux.vnet.ibm.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/linux/quicklist.h |    8 --------
+ 1 file changed, 8 deletions(-)
+
+--- a/include/linux/quicklist.h
++++ b/include/linux/quicklist.h
+@@ -56,14 +56,6 @@ static inline void __quicklist_free(int 
+       struct page *page)
+ {
+       struct quicklist *q;
+-      int nid = page_to_nid(page);
+-
+-      if (unlikely(nid != numa_node_id())) {
+-              if (dtor)
+-                      dtor(p);
+-              __free_page(page);
+-              return;
+-      }
+       q = &get_cpu_var(quicklist)[nr];
+       *(void **)p = q->page;
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:43 2008
+Message-Id: <20080206234443.478551262@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:46 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ clameter@sgi.com
+Subject: [patch 44/73] quicklists: Only consider memory that can be used with GFP_KERNEL
+Content-Disposition: inline; filename=quicklists-only-consider-memory-that-can-be-used-with-gfp_kernel.patch
+Content-Length: 1444
+Lines: 43
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Christoph Lameter <clameter@sgi.com>
+
+patch 96990a4ae979df9e235d01097d6175759331e88c in mainline.
+
+Quicklists calculates the size of the quicklists based on the number of
+free pages.  This must be the number of free pages that can be allocated
+with GFP_KERNEL.  node_page_state() includes the pages in ZONE_HIGHMEM and
+ZONE_MOVABLE which may lead the quicklists to become too large causing OOM.
+
+Signed-off-by: Christoph Lameter <clameter@sgi.com>
+Tested-by: Dhaval Giani <dhaval@linux.vnet.ibm.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/quicklist.c |   12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/mm/quicklist.c
++++ b/mm/quicklist.c
+@@ -26,9 +26,17 @@ DEFINE_PER_CPU(struct quicklist, quickli
+ static unsigned long max_pages(unsigned long min_pages)
+ {
+       unsigned long node_free_pages, max;
++      struct zone *zones = NODE_DATA(numa_node_id())->node_zones;
++
++      node_free_pages =
++#ifdef CONFIG_ZONE_DMA
++              zone_page_state(&zones[ZONE_DMA], NR_FREE_PAGES) +
++#endif
++#ifdef CONFIG_ZONE_DMA32
++              zone_page_state(&zones[ZONE_DMA32], NR_FREE_PAGES) +
++#endif
++              zone_page_state(&zones[ZONE_NORMAL], NR_FREE_PAGES);
+-      node_free_pages = node_page_state(numa_node_id(),
+-                      NR_FREE_PAGES);
+       max = node_free_pages / FRACTION_OF_NODE_MEM;
+       return max(max, min_pages);
+ }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:43 2008
+Message-Id: <20080206234443.697543103@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:47 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ greg@kroah.com,
+ greearb@candelatech.com,
+ divy@chelsio.com,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 45/73] chelsio: Fix skb->dev setting
+Content-Disposition: inline; filename=chelsio-fix-skb-dev-setting.patch
+Content-Length: 974
+Lines: 32
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Divy Le Ray <divy@chelsio.com>
+
+patch 7de6af0f23b25df8da9719ecae1916b669d0b03d in mainline.
+
+eth_type_trans() now sets skb->dev.
+Access skb->def after it gets set.
+
+Signed-off-by: Divy Le Ray <divy@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/chelsio/sge.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/chelsio/sge.c
++++ b/drivers/net/chelsio/sge.c
+@@ -1379,11 +1379,11 @@ static void sge_rx(struct sge *sge, stru
+       }
+       __skb_pull(skb, sizeof(*p));
+-      skb->dev->last_rx = jiffies;
+       st = per_cpu_ptr(sge->port_stats[p->iff], smp_processor_id());
+       st->rx_packets++;
+       skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev);
++      skb->dev->last_rx = jiffies;
+       if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff &&
+           skb->protocol == htons(ETH_P_IP) &&
+           (skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) {
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:44 2008
+Message-Id: <20080206234443.915967605@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:48 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ greg@kroah.com,
+ greearb@candelatech.com,
+ divy@chelsio.com,
+ Jeff Garzik <jeff@garzik.org>
+Subject: [patch 46/73] cxgb: fix T2 GSO
+Content-Disposition: inline; filename=cxgb-fix-t2-gso.patch
+Content-Length: 3341
+Lines: 106
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Divy Le Ray <divy@chelsio.com>
+
+patch 7832ee034b6ef78aab020c9ec1348544cd65ccbd in mainline.
+
+The patch ensures that a GSO skb has enough headroom
+to push an encapsulating cpl_tx_pkt_lso header.
+
+Signed-off-by: Divy Le Ray <divy@chelsio.com>
+Signed-off-by: Jeff Garzik <jeff@garzik.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/chelsio/cxgb2.c |    3 ++-
+ drivers/net/chelsio/sge.c   |   34 +++++++++++++++-------------------
+ drivers/net/chelsio/sge.h   |    1 +
+ 3 files changed, 18 insertions(+), 20 deletions(-)
+
+--- a/drivers/net/chelsio/cxgb2.c
++++ b/drivers/net/chelsio/cxgb2.c
+@@ -397,7 +397,8 @@ static char stats_strings[][ETH_GSTRING_
+       "TxTso",
+       "RxVlan",
+       "TxVlan",
+-
++      "TxNeedHeadroom",
++
+       /* Interrupt stats */
+       "rx drops",
+       "pure_rsps",
+--- a/drivers/net/chelsio/sge.c
++++ b/drivers/net/chelsio/sge.c
+@@ -991,6 +991,7 @@ void t1_sge_get_port_stats(const struct 
+               ss->tx_packets += st->tx_packets;
+               ss->tx_cso += st->tx_cso;
+               ss->tx_tso += st->tx_tso;
++              ss->tx_need_hdrroom += st->tx_need_hdrroom;
+               ss->vlan_xtract += st->vlan_xtract;
+               ss->vlan_insert += st->vlan_insert;
+       }
+@@ -1851,7 +1852,8 @@ int t1_start_xmit(struct sk_buff *skb, s
+ {
+       struct adapter *adapter = dev->priv;
+       struct sge *sge = adapter->sge;
+-      struct sge_port_stats *st = per_cpu_ptr(sge->port_stats[dev->if_port], smp_processor_id());
++      struct sge_port_stats *st = per_cpu_ptr(sge->port_stats[dev->if_port],
++                                              smp_processor_id());
+       struct cpl_tx_pkt *cpl;
+       struct sk_buff *orig_skb = skb;
+       int ret;
+@@ -1859,6 +1861,18 @@ int t1_start_xmit(struct sk_buff *skb, s
+       if (skb->protocol == htons(ETH_P_CPL5))
+               goto send;
++      /*
++       * We are using a non-standard hard_header_len.
++       * Allocate more header room in the rare cases it is not big enough.
++       */
++      if (unlikely(skb_headroom(skb) < dev->hard_header_len - ETH_HLEN)) {
++              skb = skb_realloc_headroom(skb, sizeof(struct cpl_tx_pkt_lso));
++              ++st->tx_need_hdrroom;
++              dev_kfree_skb_any(orig_skb);
++              if (!skb)
++                      return NETDEV_TX_OK;
++      }
++
+       if (skb_shinfo(skb)->gso_size) {
+               int eth_type;
+               struct cpl_tx_pkt_lso *hdr;
+@@ -1892,24 +1906,6 @@ int t1_start_xmit(struct sk_buff *skb, s
+                       return NETDEV_TX_OK;
+               }
+-              /*
+-               * We are using a non-standard hard_header_len and some kernel
+-               * components, such as pktgen, do not handle it right.
+-               * Complain when this happens but try to fix things up.
+-               */
+-              if (unlikely(skb_headroom(skb) < dev->hard_header_len - ETH_HLEN)) {
+-                      pr_debug("%s: headroom %d header_len %d\n", dev->name,
+-                               skb_headroom(skb), dev->hard_header_len);
+-
+-                      if (net_ratelimit())
+-                              printk(KERN_ERR "%s: inadequate headroom in "
+-                                     "Tx packet\n", dev->name);
+-                      skb = skb_realloc_headroom(skb, sizeof(*cpl));
+-                      dev_kfree_skb_any(orig_skb);
+-                      if (!skb)
+-                              return NETDEV_TX_OK;
+-              }
+-
+               if (!(adapter->flags & UDP_CSUM_CAPABLE) &&
+                   skb->ip_summed == CHECKSUM_PARTIAL &&
+                   ip_hdr(skb)->protocol == IPPROTO_UDP) {
+--- a/drivers/net/chelsio/sge.h
++++ b/drivers/net/chelsio/sge.h
+@@ -64,6 +64,7 @@ struct sge_port_stats {
+       u64 tx_tso;          /* # of TSO requests */
+       u64 vlan_xtract;     /* # of VLAN tag extractions */
+       u64 vlan_insert;     /* # of VLAN tag insertions */
++      u64 tx_need_hdrroom; /* # of TX skbs in need of more header room */
+ };
+ struct sk_buff;
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:44 2008
+Message-Id: <20080206234444.135996646@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:49 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ divy@chelsio.com,
+ greearb@candelatech.com,
+ greg@kroah.com,
+ Jeff Garzik <jeff@garzik.org>
+Subject: [patch 47/73] cxgb: fix stats
+Content-Disposition: inline; filename=cxgb-fix-stats.patch
+Content-Length: 9977
+Lines: 298
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Divy Le Ray <divy@chelsio.com>
+
+patch e0348b9ae5374f9a24424ae680bcd80724415f60 in mainline.
+
+Fix MAC stats accounting.
+Fix get_stats.
+
+Signed-off-by: Divy Le Ray <divy@chelsio.com>
+Signed-off-by: Jeff Garzik <jeff@garzik.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/chelsio/cxgb2.c  |   67 +++++++++++++++++++------
+ drivers/net/chelsio/pm3393.c |  112 +++++++++++++++++--------------------------
+ drivers/net/chelsio/sge.c    |    4 -
+ drivers/net/chelsio/sge.h    |    2 
+ 4 files changed, 96 insertions(+), 89 deletions(-)
+
+--- a/drivers/net/chelsio/cxgb2.c
++++ b/drivers/net/chelsio/cxgb2.c
+@@ -370,7 +370,9 @@ static char stats_strings[][ETH_GSTRING_
+       "TxInternalMACXmitError",
+       "TxFramesWithExcessiveDeferral",
+       "TxFCSErrors",
+-
++      "TxJumboFramesOk",
++      "TxJumboOctetsOk",
++
+       "RxOctetsOK",
+       "RxOctetsBad",
+       "RxUnicastFramesOK",
+@@ -388,11 +390,11 @@ static char stats_strings[][ETH_GSTRING_
+       "RxInRangeLengthErrors",
+       "RxOutOfRangeLengthField",
+       "RxFrameTooLongErrors",
++      "RxJumboFramesOk",
++      "RxJumboOctetsOk",
+       /* Port stats */
+-      "RxPackets",
+       "RxCsumGood",
+-      "TxPackets",
+       "TxCsumOffload",
+       "TxTso",
+       "RxVlan",
+@@ -455,23 +457,56 @@ static void get_stats(struct net_device 
+       const struct cmac_statistics *s;
+       const struct sge_intr_counts *t;
+       struct sge_port_stats ss;
+-      unsigned int len;
+       s = mac->ops->statistics_update(mac, MAC_STATS_UPDATE_FULL);
+-
+-      len = sizeof(u64)*(&s->TxFCSErrors + 1 - &s->TxOctetsOK);
+-      memcpy(data, &s->TxOctetsOK, len);
+-      data += len;
+-
+-      len = sizeof(u64)*(&s->RxFrameTooLongErrors + 1 - &s->RxOctetsOK);
+-      memcpy(data, &s->RxOctetsOK, len);
+-      data += len;
+-
++      t = t1_sge_get_intr_counts(adapter->sge);
+       t1_sge_get_port_stats(adapter->sge, dev->if_port, &ss);
+-      memcpy(data, &ss, sizeof(ss));
+-      data += sizeof(ss);
+-      t = t1_sge_get_intr_counts(adapter->sge);
++      *data++ = s->TxOctetsOK;
++      *data++ = s->TxOctetsBad;
++      *data++ = s->TxUnicastFramesOK;
++      *data++ = s->TxMulticastFramesOK;
++      *data++ = s->TxBroadcastFramesOK;
++      *data++ = s->TxPauseFrames;
++      *data++ = s->TxFramesWithDeferredXmissions;
++      *data++ = s->TxLateCollisions;
++      *data++ = s->TxTotalCollisions;
++      *data++ = s->TxFramesAbortedDueToXSCollisions;
++      *data++ = s->TxUnderrun;
++      *data++ = s->TxLengthErrors;
++      *data++ = s->TxInternalMACXmitError;
++      *data++ = s->TxFramesWithExcessiveDeferral;
++      *data++ = s->TxFCSErrors;
++      *data++ = s->TxJumboFramesOK;
++      *data++ = s->TxJumboOctetsOK;
++
++      *data++ = s->RxOctetsOK;
++      *data++ = s->RxOctetsBad;
++      *data++ = s->RxUnicastFramesOK;
++      *data++ = s->RxMulticastFramesOK;
++      *data++ = s->RxBroadcastFramesOK;
++      *data++ = s->RxPauseFrames;
++      *data++ = s->RxFCSErrors;
++      *data++ = s->RxAlignErrors;
++      *data++ = s->RxSymbolErrors;
++      *data++ = s->RxDataErrors;
++      *data++ = s->RxSequenceErrors;
++      *data++ = s->RxRuntErrors;
++      *data++ = s->RxJabberErrors;
++      *data++ = s->RxInternalMACRcvError;
++      *data++ = s->RxInRangeLengthErrors;
++      *data++ = s->RxOutOfRangeLengthField;
++      *data++ = s->RxFrameTooLongErrors;
++      *data++ = s->RxJumboFramesOK;
++      *data++ = s->RxJumboOctetsOK;
++
++      *data++ = ss.rx_cso_good;
++      *data++ = ss.tx_cso;
++      *data++ = ss.tx_tso;
++      *data++ = ss.vlan_xtract;
++      *data++ = ss.vlan_insert;
++      *data++ = ss.tx_need_hdrroom;
++
+       *data++ = t->rx_drops;
+       *data++ = t->pure_rsps;
+       *data++ = t->unhandled_irqs;
+--- a/drivers/net/chelsio/pm3393.c
++++ b/drivers/net/chelsio/pm3393.c
+@@ -45,7 +45,7 @@
+ #include <linux/crc32.h>
+-#define OFFSET(REG_ADDR)    (REG_ADDR << 2)
++#define OFFSET(REG_ADDR)    ((REG_ADDR) << 2)
+ /* Max frame size PM3393 can handle. Includes Ethernet header and CRC. */
+ #define MAX_FRAME_SIZE  9600
+@@ -428,69 +428,26 @@ static int pm3393_set_speed_duplex_fc(st
+       return 0;
+ }
+-static void pm3393_rmon_update(struct adapter *adapter, u32 offs, u64 *val,
+-                             int over)
+-{
+-      u32 val0, val1, val2;
+-
+-      t1_tpi_read(adapter, offs, &val0);
+-      t1_tpi_read(adapter, offs + 4, &val1);
+-      t1_tpi_read(adapter, offs + 8, &val2);
+-
+-      *val &= ~0ull << 40;
+-      *val |= val0 & 0xffff;
+-      *val |= (val1 & 0xffff) << 16;
+-      *val |= (u64)(val2 & 0xff) << 32;
+-
+-      if (over)
+-              *val += 1ull << 40;
++#define RMON_UPDATE(mac, name, stat_name) \
++{ \
++      t1_tpi_read((mac)->adapter, OFFSET(name), &val0);     \
++      t1_tpi_read((mac)->adapter, OFFSET((name)+1), &val1); \
++      t1_tpi_read((mac)->adapter, OFFSET((name)+2), &val2); \
++      (mac)->stats.stat_name = (u64)(val0 & 0xffff) | \
++                               ((u64)(val1 & 0xffff) << 16) | \
++                               ((u64)(val2 & 0xff) << 32) | \
++                               ((mac)->stats.stat_name & \
++                                      0xffffff0000000000ULL); \
++      if (ro & \
++          (1ULL << ((name - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2))) \
++              (mac)->stats.stat_name += 1ULL << 40; \
+ }
+ static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
+                                                             int flag)
+ {
+-      static struct {
+-              unsigned int reg;
+-              unsigned int offset;
+-      } hw_stats [] = {
+-
+-#define HW_STAT(name, stat_name) \
+-      { name, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+-
+-              /* Rx stats */
+-              HW_STAT(RxOctetsReceivedOK, RxOctetsOK),
+-              HW_STAT(RxUnicastFramesReceivedOK, RxUnicastFramesOK),
+-              HW_STAT(RxMulticastFramesReceivedOK, RxMulticastFramesOK),
+-              HW_STAT(RxBroadcastFramesReceivedOK, RxBroadcastFramesOK),
+-              HW_STAT(RxPAUSEMACCtrlFramesReceived, RxPauseFrames),
+-              HW_STAT(RxFrameCheckSequenceErrors, RxFCSErrors),
+-              HW_STAT(RxFramesLostDueToInternalMACErrors,
+-                              RxInternalMACRcvError),
+-              HW_STAT(RxSymbolErrors, RxSymbolErrors),
+-              HW_STAT(RxInRangeLengthErrors, RxInRangeLengthErrors),
+-              HW_STAT(RxFramesTooLongErrors , RxFrameTooLongErrors),
+-              HW_STAT(RxJabbers, RxJabberErrors),
+-              HW_STAT(RxFragments, RxRuntErrors),
+-              HW_STAT(RxUndersizedFrames, RxRuntErrors),
+-              HW_STAT(RxJumboFramesReceivedOK, RxJumboFramesOK),
+-              HW_STAT(RxJumboOctetsReceivedOK, RxJumboOctetsOK),
+-
+-              /* Tx stats */
+-              HW_STAT(TxOctetsTransmittedOK, TxOctetsOK),
+-              HW_STAT(TxFramesLostDueToInternalMACTransmissionError,
+-                              TxInternalMACXmitError),
+-              HW_STAT(TxTransmitSystemError, TxFCSErrors),
+-              HW_STAT(TxUnicastFramesTransmittedOK, TxUnicastFramesOK),
+-              HW_STAT(TxMulticastFramesTransmittedOK, TxMulticastFramesOK),
+-              HW_STAT(TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK),
+-              HW_STAT(TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames),
+-              HW_STAT(TxJumboFramesReceivedOK, TxJumboFramesOK),
+-              HW_STAT(TxJumboOctetsReceivedOK, TxJumboOctetsOK)
+-      }, *p = hw_stats;
+-      u64 ro;
+-      u32 val0, val1, val2, val3;
+-      u64 *stats = (u64 *) &mac->stats;
+-      unsigned int i;
++      u64     ro;
++      u32     val0, val1, val2, val3;
+       /* Snap the counters */
+       pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
+@@ -504,14 +461,35 @@ static const struct cmac_statistics *pm3
+       ro = ((u64)val0 & 0xffff) | (((u64)val1 & 0xffff) << 16) |
+               (((u64)val2 & 0xffff) << 32) | (((u64)val3 & 0xffff) << 48);
+-      for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
+-              unsigned reg = p->reg - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW;
+-
+-              pm3393_rmon_update((mac)->adapter, OFFSET(p->reg),
+-                                 stats + p->offset, ro & (reg >> 2));
+-      }
+-
+-
++      /* Rx stats */
++      RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK);
++      RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK);
++      RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK);
++      RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK);
++      RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames);
++      RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors);
++      RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors,
++                              RxInternalMACRcvError);
++      RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
++      RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors);
++      RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors);
++      RMON_UPDATE(mac, RxJabbers, RxJabberErrors);
++      RMON_UPDATE(mac, RxFragments, RxRuntErrors);
++      RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors);
++      RMON_UPDATE(mac, RxJumboFramesReceivedOK, RxJumboFramesOK);
++      RMON_UPDATE(mac, RxJumboOctetsReceivedOK, RxJumboOctetsOK);
++
++      /* Tx stats */
++      RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK);
++      RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError,
++                              TxInternalMACXmitError);
++      RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors);
++      RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK);
++      RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK);
++      RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK);
++      RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames);
++      RMON_UPDATE(mac, TxJumboFramesReceivedOK, TxJumboFramesOK);
++      RMON_UPDATE(mac, TxJumboOctetsReceivedOK, TxJumboOctetsOK);
+       return &mac->stats;
+ }
+--- a/drivers/net/chelsio/sge.c
++++ b/drivers/net/chelsio/sge.c
+@@ -986,9 +986,7 @@ void t1_sge_get_port_stats(const struct 
+       for_each_possible_cpu(cpu) {
+               struct sge_port_stats *st = per_cpu_ptr(sge->port_stats[port], cpu);
+-              ss->rx_packets += st->rx_packets;
+               ss->rx_cso_good += st->rx_cso_good;
+-              ss->tx_packets += st->tx_packets;
+               ss->tx_cso += st->tx_cso;
+               ss->tx_tso += st->tx_tso;
+               ss->tx_need_hdrroom += st->tx_need_hdrroom;
+@@ -1381,7 +1379,6 @@ static void sge_rx(struct sge *sge, stru
+       __skb_pull(skb, sizeof(*p));
+       st = per_cpu_ptr(sge->port_stats[p->iff], smp_processor_id());
+-      st->rx_packets++;
+       skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev);
+       skb->dev->last_rx = jiffies;
+@@ -1951,7 +1948,6 @@ int t1_start_xmit(struct sk_buff *skb, s
+               cpl->vlan_valid = 0;
+ send:
+-      st->tx_packets++;
+       dev->trans_start = jiffies;
+       ret = t1_sge_tx(skb, adapter, 0, dev);
+--- a/drivers/net/chelsio/sge.h
++++ b/drivers/net/chelsio/sge.h
+@@ -57,9 +57,7 @@ struct sge_intr_counts {
+ };
+ struct sge_port_stats {
+-      u64 rx_packets;      /* # of Ethernet packets received */
+       u64 rx_cso_good;     /* # of successful RX csum offloads */
+-      u64 tx_packets;      /* # of TX packets */
+       u64 tx_cso;          /* # of TX checksum offloads */
+       u64 tx_tso;          /* # of TSO requests */
+       u64 vlan_xtract;     /* # of VLAN tag extractions */
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:44 2008
+Message-Id: <20080206234444.357962003@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:50 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Dmitry Torokhov <dtor@mail.ru>,
+ Al Viro <viro@ZenIV.linux.org.uk>
+Subject: [patch 48/73] Input: implement proper locking in input core
+Content-Disposition: inline; filename=input-implement-proper-locking-in-input-core.patch
+Content-Length: 33952
+Lines: 1130
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+patch 8006479c9b75fb6594a7b746af3d7f1fbb68f18f in mainline.
+
+Also add some kerneldoc documentation to input.h
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/input.c |  666 ++++++++++++++++++++++++++++++++++++--------------
+ include/linux/input.h |  112 +++++++-
+ 2 files changed, 595 insertions(+), 183 deletions(-)
+
+--- a/drivers/input/input.c
++++ b/drivers/input/input.c
+@@ -17,10 +17,10 @@
+ #include <linux/major.h>
+ #include <linux/proc_fs.h>
+ #include <linux/seq_file.h>
+-#include <linux/interrupt.h>
+ #include <linux/poll.h>
+ #include <linux/device.h>
+ #include <linux/mutex.h>
++#include <linux/rcupdate.h>
+ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+ MODULE_DESCRIPTION("Input core");
+@@ -31,167 +31,244 @@ MODULE_LICENSE("GPL");
+ static LIST_HEAD(input_dev_list);
+ static LIST_HEAD(input_handler_list);
++/*
++ * input_mutex protects access to both input_dev_list and input_handler_list.
++ * This also causes input_[un]register_device and input_[un]register_handler
++ * be mutually exclusive which simplifies locking in drivers implementing
++ * input handlers.
++ */
++static DEFINE_MUTEX(input_mutex);
++
+ static struct input_handler *input_table[8];
+-/**
+- * input_event() - report new input event
+- * @dev: device that generated the event
+- * @type: type of the event
+- * @code: event code
+- * @value: value of the event
+- *
+- * This function should be used by drivers implementing various input devices
+- * See also input_inject_event()
+- */
+-void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
++static inline int is_event_supported(unsigned int code,
++                                   unsigned long *bm, unsigned int max)
+ {
+-      struct input_handle *handle;
++      return code <= max && test_bit(code, bm);
++}
+-      if (type > EV_MAX || !test_bit(type, dev->evbit))
+-              return;
++static int input_defuzz_abs_event(int value, int old_val, int fuzz)
++{
++      if (fuzz) {
++              if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2)
++                      return old_val;
+-      add_input_randomness(type, code, value);
++              if (value > old_val - fuzz && value < old_val + fuzz)
++                      return (old_val * 3 + value) / 4;
+-      switch (type) {
++              if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2)
++                      return (old_val + value) / 2;
++      }
+-              case EV_SYN:
+-                      switch (code) {
+-                              case SYN_CONFIG:
+-                                      if (dev->event)
+-                                              dev->event(dev, type, code, value);
+-                                      break;
+-
+-                              case SYN_REPORT:
+-                                      if (dev->sync)
+-                                              return;
+-                                      dev->sync = 1;
+-                                      break;
+-                      }
+-                      break;
++      return value;
++}
+-              case EV_KEY:
++/*
++ * Pass event through all open handles. This function is called with
++ * dev->event_lock held and interrupts disabled. Because of that we
++ * do not need to use rcu_read_lock() here although we are using RCU
++ * to access handle list. Note that because of that write-side uses
++ * synchronize_sched() instead of synchronize_ru().
++ */
++static void input_pass_event(struct input_dev *dev,
++                           unsigned int type, unsigned int code, int value)
++{
++      struct input_handle *handle = rcu_dereference(dev->grab);
+-                      if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
+-                              return;
++      if (handle)
++              handle->handler->event(handle, type, code, value);
++      else
++              list_for_each_entry_rcu(handle, &dev->h_list, d_node)
++                      if (handle->open)
++                              handle->handler->event(handle,
++                                                      type, code, value);
++}
+-                      if (value == 2)
+-                              break;
++/*
++ * Generate software autorepeat event. Note that we take
++ * dev->event_lock here to avoid racing with input_event
++ * which may cause keys get "stuck".
++ */
++static void input_repeat_key(unsigned long data)
++{
++      struct input_dev *dev = (void *) data;
++      unsigned long flags;
+-                      change_bit(code, dev->key);
++      spin_lock_irqsave(&dev->event_lock, flags);
+-                      if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && dev->timer.data && value) {
+-                              dev->repeat_key = code;
+-                              mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
+-                      }
++      if (test_bit(dev->repeat_key, dev->key) &&
++          is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
+-                      break;
++              input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
+-              case EV_SW:
++              if (dev->sync) {
++                      /*
++                       * Only send SYN_REPORT if we are not in a middle
++                       * of driver parsing a new hardware packet.
++                       * Otherwise assume that the driver will send
++                       * SYN_REPORT once it's done.
++                       */
++                      input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
++              }
+-                      if (code > SW_MAX || !test_bit(code, dev->swbit) || !!test_bit(code, dev->sw) == value)
+-                              return;
++              if (dev->rep[REP_PERIOD])
++                      mod_timer(&dev->timer, jiffies +
++                                      msecs_to_jiffies(dev->rep[REP_PERIOD]));
++      }
+-                      change_bit(code, dev->sw);
++      spin_unlock_irqrestore(&dev->event_lock, flags);
++}
+-                      break;
++static void input_start_autorepeat(struct input_dev *dev, int code)
++{
++      if (test_bit(EV_REP, dev->evbit) &&
++          dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
++          dev->timer.data) {
++              dev->repeat_key = code;
++              mod_timer(&dev->timer,
++                        jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
++      }
++}
+-              case EV_ABS:
++#define INPUT_IGNORE_EVENT    0
++#define INPUT_PASS_TO_HANDLERS        1
++#define INPUT_PASS_TO_DEVICE  2
++#define INPUT_PASS_TO_ALL     (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
+-                      if (code > ABS_MAX || !test_bit(code, dev->absbit))
+-                              return;
++static void input_handle_event(struct input_dev *dev,
++                             unsigned int type, unsigned int code, int value)
++{
++      int disposition = INPUT_IGNORE_EVENT;
+-                      if (dev->absfuzz[code]) {
+-                              if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) &&
+-                                  (value < dev->abs[code] + (dev->absfuzz[code] >> 1)))
+-                                      return;
+-
+-                              if ((value > dev->abs[code] - dev->absfuzz[code]) &&
+-                                  (value < dev->abs[code] + dev->absfuzz[code]))
+-                                      value = (dev->abs[code] * 3 + value) >> 2;
+-
+-                              if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) &&
+-                                  (value < dev->abs[code] + (dev->absfuzz[code] << 1)))
+-                                      value = (dev->abs[code] + value) >> 1;
+-                      }
++      switch (type) {
+-                      if (dev->abs[code] == value)
+-                              return;
++      case EV_SYN:
++              switch (code) {
++              case SYN_CONFIG:
++                      disposition = INPUT_PASS_TO_ALL;
++                      break;
+-                      dev->abs[code] = value;
++              case SYN_REPORT:
++                      if (!dev->sync) {
++                              dev->sync = 1;
++                              disposition = INPUT_PASS_TO_HANDLERS;
++                      }
+                       break;
++              }
++              break;
+-              case EV_REL:
++      case EV_KEY:
++              if (is_event_supported(code, dev->keybit, KEY_MAX) &&
++                  !!test_bit(code, dev->key) != value) {
+-                      if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0))
+-                              return;
++                      if (value != 2) {
++                              __change_bit(code, dev->key);
++                              if (value)
++                                      input_start_autorepeat(dev, code);
++                      }
+-                      break;
++                      disposition = INPUT_PASS_TO_HANDLERS;
++              }
++              break;
+-              case EV_MSC:
++      case EV_SW:
++              if (is_event_supported(code, dev->swbit, SW_MAX) &&
++                  !!test_bit(code, dev->sw) != value) {
+-                      if (code > MSC_MAX || !test_bit(code, dev->mscbit))
+-                              return;
++                      __change_bit(code, dev->sw);
++                      disposition = INPUT_PASS_TO_HANDLERS;
++              }
++              break;
++
++      case EV_ABS:
++              if (is_event_supported(code, dev->absbit, ABS_MAX)) {
+-                      if (dev->event)
+-                              dev->event(dev, type, code, value);
++                      value = input_defuzz_abs_event(value,
++                                      dev->abs[code], dev->absfuzz[code]);
+-                      break;
++                      if (dev->abs[code] != value) {
++                              dev->abs[code] = value;
++                              disposition = INPUT_PASS_TO_HANDLERS;
++                      }
++              }
++              break;
+-              case EV_LED:
++      case EV_REL:
++              if (is_event_supported(code, dev->relbit, REL_MAX) && value)
++                      disposition = INPUT_PASS_TO_HANDLERS;
+-                      if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
+-                              return;
++              break;
+-                      change_bit(code, dev->led);
++      case EV_MSC:
++              if (is_event_supported(code, dev->mscbit, MSC_MAX))
++                      disposition = INPUT_PASS_TO_ALL;
+-                      if (dev->event)
+-                              dev->event(dev, type, code, value);
++              break;
+-                      break;
++      case EV_LED:
++              if (is_event_supported(code, dev->ledbit, LED_MAX) &&
++                  !!test_bit(code, dev->led) != value) {
+-              case EV_SND:
++                      __change_bit(code, dev->led);
++                      disposition = INPUT_PASS_TO_ALL;
++              }
++              break;
+-                      if (code > SND_MAX || !test_bit(code, dev->sndbit))
+-                              return;
++      case EV_SND:
++              if (is_event_supported(code, dev->sndbit, SND_MAX)) {
+                       if (!!test_bit(code, dev->snd) != !!value)
+-                              change_bit(code, dev->snd);
++                              __change_bit(code, dev->snd);
++                      disposition = INPUT_PASS_TO_ALL;
++              }
++              break;
+-                      if (dev->event)
+-                              dev->event(dev, type, code, value);
++      case EV_REP:
++              if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
++                      dev->rep[code] = value;
++                      disposition = INPUT_PASS_TO_ALL;
++              }
++              break;
+-                      break;
++      case EV_FF:
++              if (value >= 0)
++                      disposition = INPUT_PASS_TO_ALL;
++              break;
++      }
+-              case EV_REP:
++      if (type != EV_SYN)
++              dev->sync = 0;
+-                      if (code > REP_MAX || value < 0 || dev->rep[code] == value)
+-                              return;
++      if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
++              dev->event(dev, type, code, value);
+-                      dev->rep[code] = value;
+-                      if (dev->event)
+-                              dev->event(dev, type, code, value);
++      if (disposition & INPUT_PASS_TO_HANDLERS)
++              input_pass_event(dev, type, code, value);
++}
+-                      break;
++/**
++ * input_event() - report new input event
++ * @dev: device that generated the event
++ * @type: type of the event
++ * @code: event code
++ * @value: value of the event
++ *
++ * This function should be used by drivers implementing various input
++ * devices. See also input_inject_event().
++ */
+-              case EV_FF:
++void input_event(struct input_dev *dev,
++               unsigned int type, unsigned int code, int value)
++{
++      unsigned long flags;
+-                      if (value < 0)
+-                              return;
++      if (is_event_supported(type, dev->evbit, EV_MAX)) {
+-                      if (dev->event)
+-                              dev->event(dev, type, code, value);
+-                      break;
++              spin_lock_irqsave(&dev->event_lock, flags);
++              add_input_randomness(type, code, value);
++              input_handle_event(dev, type, code, value);
++              spin_unlock_irqrestore(&dev->event_lock, flags);
+       }
+-
+-      if (type != EV_SYN)
+-              dev->sync = 0;
+-
+-      if (dev->grab)
+-              dev->grab->handler->event(dev->grab, type, code, value);
+-      else
+-              list_for_each_entry(handle, &dev->h_list, d_node)
+-                      if (handle->open)
+-                              handle->handler->event(handle, type, code, value);
+ }
+ EXPORT_SYMBOL(input_event);
+@@ -202,102 +279,230 @@ EXPORT_SYMBOL(input_event);
+  * @code: event code
+  * @value: value of the event
+  *
+- * Similar to input_event() but will ignore event if device is "grabbed" and handle
+- * injecting event is not the one that owns the device.
++ * Similar to input_event() but will ignore event if device is
++ * "grabbed" and handle injecting event is not the one that owns
++ * the device.
+  */
+-void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
++void input_inject_event(struct input_handle *handle,
++                      unsigned int type, unsigned int code, int value)
+ {
+-      if (!handle->dev->grab || handle->dev->grab == handle)
+-              input_event(handle->dev, type, code, value);
+-}
+-EXPORT_SYMBOL(input_inject_event);
+-
+-static void input_repeat_key(unsigned long data)
+-{
+-      struct input_dev *dev = (void *) data;
++      struct input_dev *dev = handle->dev;
++      struct input_handle *grab;
++      unsigned long flags;
+-      if (!test_bit(dev->repeat_key, dev->key))
+-              return;
++      if (is_event_supported(type, dev->evbit, EV_MAX)) {
++              spin_lock_irqsave(&dev->event_lock, flags);
+-      input_event(dev, EV_KEY, dev->repeat_key, 2);
+-      input_sync(dev);
++              grab = rcu_dereference(dev->grab);
++              if (!grab || grab == handle)
++                      input_handle_event(dev, type, code, value);
+-      if (dev->rep[REP_PERIOD])
+-              mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD]));
++              spin_unlock_irqrestore(&dev->event_lock, flags);
++      }
+ }
++EXPORT_SYMBOL(input_inject_event);
++/**
++ * input_grab_device - grabs device for exclusive use
++ * @handle: input handle that wants to own the device
++ *
++ * When a device is grabbed by an input handle all events generated by
++ * the device are delivered only to this handle. Also events injected
++ * by other input handles are ignored while device is grabbed.
++ */
+ int input_grab_device(struct input_handle *handle)
+ {
+-      if (handle->dev->grab)
+-              return -EBUSY;
++      struct input_dev *dev = handle->dev;
++      int retval;
+-      handle->dev->grab = handle;
+-      return 0;
++      retval = mutex_lock_interruptible(&dev->mutex);
++      if (retval)
++              return retval;
++
++      if (dev->grab) {
++              retval = -EBUSY;
++              goto out;
++      }
++
++      rcu_assign_pointer(dev->grab, handle);
++      /*
++       * Not using synchronize_rcu() because read-side is protected
++       * by a spinlock with interrupts off instead of rcu_read_lock().
++       */
++      synchronize_sched();
++
++ out:
++      mutex_unlock(&dev->mutex);
++      return retval;
+ }
+ EXPORT_SYMBOL(input_grab_device);
+-void input_release_device(struct input_handle *handle)
++static void __input_release_device(struct input_handle *handle)
+ {
+       struct input_dev *dev = handle->dev;
+       if (dev->grab == handle) {
+-              dev->grab = NULL;
++              rcu_assign_pointer(dev->grab, NULL);
++              /* Make sure input_pass_event() notices that grab is gone */
++              synchronize_sched();
+               list_for_each_entry(handle, &dev->h_list, d_node)
+-                      if (handle->handler->start)
++                      if (handle->open && handle->handler->start)
+                               handle->handler->start(handle);
+       }
+ }
++
++/**
++ * input_release_device - release previously grabbed device
++ * @handle: input handle that owns the device
++ *
++ * Releases previously grabbed device so that other input handles can
++ * start receiving input events. Upon release all handlers attached
++ * to the device have their start() method called so they have a change
++ * to synchronize device state with the rest of the system.
++ */
++void input_release_device(struct input_handle *handle)
++{
++      struct input_dev *dev = handle->dev;
++
++      mutex_lock(&dev->mutex);
++      __input_release_device(handle);
++      mutex_unlock(&dev->mutex);
++}
+ EXPORT_SYMBOL(input_release_device);
++/**
++ * input_open_device - open input device
++ * @handle: handle through which device is being accessed
++ *
++ * This function should be called by input handlers when they
++ * want to start receive events from given input device.
++ */
+ int input_open_device(struct input_handle *handle)
+ {
+       struct input_dev *dev = handle->dev;
+-      int err;
++      int retval;
+-      err = mutex_lock_interruptible(&dev->mutex);
+-      if (err)
+-              return err;
++      retval = mutex_lock_interruptible(&dev->mutex);
++      if (retval)
++              return retval;
++
++      if (dev->going_away) {
++              retval = -ENODEV;
++              goto out;
++      }
+       handle->open++;
+       if (!dev->users++ && dev->open)
+-              err = dev->open(dev);
++              retval = dev->open(dev);
+-      if (err)
+-              handle->open--;
++      if (retval) {
++              dev->users--;
++              if (!--handle->open) {
++                      /*
++                       * Make sure we are not delivering any more events
++                       * through this handle
++                       */
++                      synchronize_sched();
++              }
++      }
++ out:
+       mutex_unlock(&dev->mutex);
+-
+-      return err;
++      return retval;
+ }
+ EXPORT_SYMBOL(input_open_device);
+-int input_flush_device(struct input_handle* handle, struct file* file)
++int input_flush_device(struct input_handle *handle, struct file *file)
+ {
+-      if (handle->dev->flush)
+-              return handle->dev->flush(handle->dev, file);
++      struct input_dev *dev = handle->dev;
++      int retval;
+-      return 0;
++      retval = mutex_lock_interruptible(&dev->mutex);
++      if (retval)
++              return retval;
++
++      if (dev->flush)
++              retval = dev->flush(dev, file);
++
++      mutex_unlock(&dev->mutex);
++      return retval;
+ }
+ EXPORT_SYMBOL(input_flush_device);
++/**
++ * input_close_device - close input device
++ * @handle: handle through which device is being accessed
++ *
++ * This function should be called by input handlers when they
++ * want to stop receive events from given input device.
++ */
+ void input_close_device(struct input_handle *handle)
+ {
+       struct input_dev *dev = handle->dev;
+-      input_release_device(handle);
+-
+       mutex_lock(&dev->mutex);
++      __input_release_device(handle);
++
+       if (!--dev->users && dev->close)
+               dev->close(dev);
+-      handle->open--;
++
++      if (!--handle->open) {
++              /*
++               * synchronize_sched() makes sure that input_pass_event()
++               * completed and that no more input events are delivered
++               * through this handle
++               */
++              synchronize_sched();
++      }
+       mutex_unlock(&dev->mutex);
+ }
+ EXPORT_SYMBOL(input_close_device);
++/*
++ * Prepare device for unregistering
++ */
++static void input_disconnect_device(struct input_dev *dev)
++{
++      struct input_handle *handle;
++      int code;
++
++      /*
++       * Mark device as going away. Note that we take dev->mutex here
++       * not to protect access to dev->going_away but rather to ensure
++       * that there are no threads in the middle of input_open_device()
++       */
++      mutex_lock(&dev->mutex);
++      dev->going_away = 1;
++      mutex_unlock(&dev->mutex);
++
++      spin_lock_irq(&dev->event_lock);
++
++      /*
++       * Simulate keyup events for all pressed keys so that handlers
++       * are not left with "stuck" keys. The driver may continue
++       * generate events even after we done here but they will not
++       * reach any handlers.
++       */
++      if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
++              for (code = 0; code <= KEY_MAX; code++) {
++                      if (is_event_supported(code, dev->keybit, KEY_MAX) &&
++                          test_bit(code, dev->key)) {
++                              input_pass_event(dev, EV_KEY, code, 0);
++                      }
++              }
++              input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
++      }
++
++      list_for_each_entry(handle, &dev->h_list, d_node)
++              handle->open = 0;
++
++      spin_unlock_irq(&dev->event_lock);
++}
++
+ static int input_fetch_keycode(struct input_dev *dev, int scancode)
+ {
+       switch (dev->keycodesize) {
+@@ -473,7 +678,8 @@ static unsigned int input_proc_devices_p
+ static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
+ {
+-      /* acquire lock here ... Yes, we do need locking, I knowi, I know... */
++      if (mutex_lock_interruptible(&input_mutex))
++              return NULL;
+       return seq_list_start(&input_dev_list, *pos);
+ }
+@@ -485,7 +691,7 @@ static void *input_devices_seq_next(stru
+ static void input_devices_seq_stop(struct seq_file *seq, void *v)
+ {
+-      /* release lock here */
++      mutex_unlock(&input_mutex);
+ }
+ static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
+@@ -569,7 +775,9 @@ static const struct file_operations inpu
+ static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
+ {
+-      /* acquire lock here ... Yes, we do need locking, I knowi, I know... */
++      if (mutex_lock_interruptible(&input_mutex))
++              return NULL;
++
+       seq->private = (void *)(unsigned long)*pos;
+       return seq_list_start(&input_handler_list, *pos);
+ }
+@@ -582,7 +790,7 @@ static void *input_handlers_seq_next(str
+ static void input_handlers_seq_stop(struct seq_file *seq, void *v)
+ {
+-      /* release lock here */
++      mutex_unlock(&input_mutex);
+ }
+ static int input_handlers_seq_show(struct seq_file *seq, void *v)
+@@ -1005,6 +1213,7 @@ struct input_dev *input_allocate_device(
+               dev->dev.class = &input_class;
+               device_initialize(&dev->dev);
+               mutex_init(&dev->mutex);
++              spin_lock_init(&dev->event_lock);
+               INIT_LIST_HEAD(&dev->h_list);
+               INIT_LIST_HEAD(&dev->node);
+@@ -1022,7 +1231,7 @@ EXPORT_SYMBOL(input_allocate_device);
+  * This function should only be used if input_register_device()
+  * was not called yet or if it failed. Once device was registered
+  * use input_unregister_device() and memory will be freed once last
+- * refrence to the device is dropped.
++ * reference to the device is dropped.
+  *
+  * Device should be allocated by input_allocate_device().
+  *
+@@ -1092,6 +1301,18 @@ void input_set_capability(struct input_d
+ }
+ EXPORT_SYMBOL(input_set_capability);
++/**
++ * input_register_device - register device with input core
++ * @dev: device to be registered
++ *
++ * This function registers device with input core. The device must be
++ * allocated with input_allocate_device() and all it's capabilities
++ * set up before registering.
++ * If function fails the device must be freed with input_free_device().
++ * Once device has been successfully registered it can be unregistered
++ * with input_unregister_device(); input_free_device() should not be
++ * called in this case.
++ */
+ int input_register_device(struct input_dev *dev)
+ {
+       static atomic_t input_no = ATOMIC_INIT(0);
+@@ -1099,7 +1320,7 @@ int input_register_device(struct input_d
+       const char *path;
+       int error;
+-      set_bit(EV_SYN, dev->evbit);
++      __set_bit(EV_SYN, dev->evbit);
+       /*
+        * If delay and period are pre-set by the driver, then autorepeating
+@@ -1120,8 +1341,6 @@ int input_register_device(struct input_d
+       if (!dev->setkeycode)
+               dev->setkeycode = input_default_setkeycode;
+-      list_add_tail(&dev->node, &input_dev_list);
+-
+       snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
+                "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
+@@ -1137,49 +1356,79 @@ int input_register_device(struct input_d
+               dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
+       kfree(path);
++      error = mutex_lock_interruptible(&input_mutex);
++      if (error) {
++              device_del(&dev->dev);
++              return error;
++      }
++
++      list_add_tail(&dev->node, &input_dev_list);
++
+       list_for_each_entry(handler, &input_handler_list, node)
+               input_attach_handler(dev, handler);
+       input_wakeup_procfs_readers();
++      mutex_unlock(&input_mutex);
++
+       return 0;
+ }
+ EXPORT_SYMBOL(input_register_device);
++/**
++ * input_unregister_device - unregister previously registered device
++ * @dev: device to be unregistered
++ *
++ * This function unregisters an input device. Once device is unregistered
++ * the caller should not try to access it as it may get freed at any moment.
++ */
+ void input_unregister_device(struct input_dev *dev)
+ {
+       struct input_handle *handle, *next;
+-      int code;
+-      for (code = 0; code <= KEY_MAX; code++)
+-              if (test_bit(code, dev->key))
+-                      input_report_key(dev, code, 0);
+-      input_sync(dev);
++      input_disconnect_device(dev);
+-      del_timer_sync(&dev->timer);
++      mutex_lock(&input_mutex);
+       list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
+               handle->handler->disconnect(handle);
+       WARN_ON(!list_empty(&dev->h_list));
++      del_timer_sync(&dev->timer);
+       list_del_init(&dev->node);
+-      device_unregister(&dev->dev);
+-
+       input_wakeup_procfs_readers();
++
++      mutex_unlock(&input_mutex);
++
++      device_unregister(&dev->dev);
+ }
+ EXPORT_SYMBOL(input_unregister_device);
++/**
++ * input_register_handler - register a new input handler
++ * @handler: handler to be registered
++ *
++ * This function registers a new input handler (interface) for input
++ * devices in the system and attaches it to all input devices that
++ * are compatible with the handler.
++ */
+ int input_register_handler(struct input_handler *handler)
+ {
+       struct input_dev *dev;
++      int retval;
++
++      retval = mutex_lock_interruptible(&input_mutex);
++      if (retval)
++              return retval;
+       INIT_LIST_HEAD(&handler->h_list);
+       if (handler->fops != NULL) {
+-              if (input_table[handler->minor >> 5])
+-                      return -EBUSY;
+-
++              if (input_table[handler->minor >> 5]) {
++                      retval = -EBUSY;
++                      goto out;
++              }
+               input_table[handler->minor >> 5] = handler;
+       }
+@@ -1189,14 +1438,26 @@ int input_register_handler(struct input_
+               input_attach_handler(dev, handler);
+       input_wakeup_procfs_readers();
+-      return 0;
++
++ out:
++      mutex_unlock(&input_mutex);
++      return retval;
+ }
+ EXPORT_SYMBOL(input_register_handler);
++/**
++ * input_unregister_handler - unregisters an input handler
++ * @handler: handler to be unregistered
++ *
++ * This function disconnects a handler from its input devices and
++ * removes it from lists of known handlers.
++ */
+ void input_unregister_handler(struct input_handler *handler)
+ {
+       struct input_handle *handle, *next;
++      mutex_lock(&input_mutex);
++
+       list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
+               handler->disconnect(handle);
+       WARN_ON(!list_empty(&handler->h_list));
+@@ -1207,14 +1468,50 @@ void input_unregister_handler(struct inp
+               input_table[handler->minor >> 5] = NULL;
+       input_wakeup_procfs_readers();
++
++      mutex_unlock(&input_mutex);
+ }
+ EXPORT_SYMBOL(input_unregister_handler);
++/**
++ * input_register_handle - register a new input handle
++ * @handle: handle to register
++ *
++ * This function puts a new input handle onto device's
++ * and handler's lists so that events can flow through
++ * it once it is opened using input_open_device().
++ *
++ * This function is supposed to be called from handler's
++ * connect() method.
++ */
+ int input_register_handle(struct input_handle *handle)
+ {
+       struct input_handler *handler = handle->handler;
++      struct input_dev *dev = handle->dev;
++      int error;
++
++      /*
++       * We take dev->mutex here to prevent race with
++       * input_release_device().
++       */
++      error = mutex_lock_interruptible(&dev->mutex);
++      if (error)
++              return error;
++      list_add_tail_rcu(&handle->d_node, &dev->h_list);
++      mutex_unlock(&dev->mutex);
++      /*
++       * We don't use synchronize_rcu() here because we rely
++       * on dev->event_lock to protect read-side critical
++       * section in input_pass_event().
++       */
++      synchronize_sched();
+-      list_add_tail(&handle->d_node, &handle->dev->h_list);
++      /*
++       * Since we are supposed to be called from ->connect()
++       * which is mutually exclusive with ->disconnect()
++       * we can't be racing with input_unregister_handle()
++       * and so separate lock is not needed here.
++       */
+       list_add_tail(&handle->h_node, &handler->h_list);
+       if (handler->start)
+@@ -1224,10 +1521,29 @@ int input_register_handle(struct input_h
+ }
+ EXPORT_SYMBOL(input_register_handle);
++/**
++ * input_unregister_handle - unregister an input handle
++ * @handle: handle to unregister
++ *
++ * This function removes input handle from device's
++ * and handler's lists.
++ *
++ * This function is supposed to be called from handler's
++ * disconnect() method.
++ */
+ void input_unregister_handle(struct input_handle *handle)
+ {
++      struct input_dev *dev = handle->dev;
++
+       list_del_init(&handle->h_node);
+-      list_del_init(&handle->d_node);
++
++      /*
++       * Take dev->mutex to prevent race with input_release_device().
++       */
++      mutex_lock(&dev->mutex);
++      list_del_rcu(&handle->d_node);
++      mutex_unlock(&dev->mutex);
++      synchronize_sched();
+ }
+ EXPORT_SYMBOL(input_unregister_handle);
+--- a/include/linux/input.h
++++ b/include/linux/input.h
+@@ -853,7 +853,7 @@ struct ff_rumble_effect {
+  *    defining effect parameters
+  *
+  * This structure is sent through ioctl from the application to the driver.
+- * To create a new effect aplication should set its @id to -1; the kernel
++ * To create a new effect application should set its @id to -1; the kernel
+  * will return assigned @id which can later be used to update or delete
+  * this effect.
+  *
+@@ -933,9 +933,82 @@ struct ff_effect {
+ #define BIT(x)        (1UL<<((x)%BITS_PER_LONG))
+ #define LONG(x) ((x)/BITS_PER_LONG)
++/**
++ * struct input_dev - represents an input device
++ * @name: name of the device
++ * @phys: physical path to the device in the system hierarchy
++ * @uniq: unique identification code for the device (if device has it)
++ * @id: id of the device (struct input_id)
++ * @evbit: bitmap of types of events supported by the device (EV_KEY,
++ *    EV_REL, etc.)
++ * @keybit: bitmap of keys/buttons this device has
++ * @relbit: bitmap of relative axes for the device
++ * @absbit: bitmap of absolute axes for the device
++ * @mscbit: bitmap of miscellaneous events supported by the device
++ * @ledbit: bitmap of leds present on the device
++ * @sndbit: bitmap of sound effects supported by the device
++ * @ffbit: bitmap of force feedback effects supported by the device
++ * @swbit: bitmap of switches present on the device
++ * @keycodemax: size of keycode table
++ * @keycodesize: size of elements in keycode table
++ * @keycode: map of scancodes to keycodes for this device
++ * @setkeycode: optional method to alter current keymap, used to implement
++ *    sparse keymaps. If not supplied default mechanism will be used
++ * @getkeycode: optional method to retrieve current keymap. If not supplied
++ *    default mechanism will be used
++ * @ff: force feedback structure associated with the device if device
++ *    supports force feedback effects
++ * @repeat_key: stores key code of the last key pressed; used to implement
++ *    software autorepeat
++ * @timer: timer for software autorepeat
++ * @sync: set to 1 when there were no new events since last EV_SYNC
++ * @abs: current values for reports from absolute axes
++ * @rep: current values for autorepeat parameters (delay, rate)
++ * @key: reflects current state of device's keys/buttons
++ * @led: reflects current state of device's LEDs
++ * @snd: reflects current state of sound effects
++ * @sw: reflects current state of device's switches
++ * @absmax: maximum values for events coming from absolute axes
++ * @absmin: minimum values for events coming from absolute axes
++ * @absfuzz: describes noisiness for axes
++ * @absflat: size of the center flat position (used by joydev)
++ * @open: this method is called when the very first user calls
++ *    input_open_device(). The driver must prepare the device
++ *    to start generating events (start polling thread,
++ *    request an IRQ, submit URB, etc.)
++ * @close: this method is called when the very last user calls
++ *    input_close_device().
++ * @flush: purges the device. Most commonly used to get rid of force
++ *    feedback effects loaded into the device when disconnecting
++ *    from it
++ * @event: event handler for events sent _to_ the device, like EV_LED
++ *    or EV_SND. The device is expected to carry out the requested
++ *    action (turn on a LED, play sound, etc.) The call is protected
++ *    by @event_lock and must not sleep
++ * @grab: input handle that currently has the device grabbed (via
++ *    EVIOCGRAB ioctl). When a handle grabs a device it becomes sole
++ *    recipient for all input events coming from the device
++ * @event_lock: this spinlock is is taken when input core receives
++ *    and processes a new event for the device (in input_event()).
++ *    Code that accesses and/or modifies parameters of a device
++ *    (such as keymap or absmin, absmax, absfuzz, etc.) after device
++ *    has been registered with input core must take this lock.
++ * @mutex: serializes calls to open(), close() and flush() methods
++ * @users: stores number of users (input handlers) that opened this
++ *    device. It is used by input_open_device() and input_close_device()
++ *    to make sure that dev->open() is only called when the first
++ *    user opens device and dev->close() is called when the very
++ *    last user closes the device
++ * @going_away: marks devices that are in a middle of unregistering and
++ *    causes input_open_device*() fail with -ENODEV.
++ * @dev: driver model's view of this device
++ * @h_list: list of input handles associated with the device. When
++ *    accessing the list dev->mutex must be held
++ * @node: used to place the device onto input_dev_list
++ */
+ struct input_dev {
+-      void *private;
++      void *private;  /* do not use */
+       const char *name;
+       const char *phys;
+@@ -963,8 +1036,6 @@ struct input_dev {
+       unsigned int repeat_key;
+       struct timer_list timer;
+-      int state;
+-
+       int sync;
+       int abs[ABS_MAX + 1];
+@@ -987,8 +1058,11 @@ struct input_dev {
+       struct input_handle *grab;
+-      struct mutex mutex;     /* serializes open and close operations */
++      spinlock_t event_lock;
++      struct mutex mutex;
++
+       unsigned int users;
++      int going_away;
+       struct device dev;
+       union {                 /* temporarily so while we switching to struct device */
+@@ -1054,7 +1128,9 @@ struct input_handle;
+ /**
+  * struct input_handler - implements one of interfaces for input devices
+  * @private: driver-specific data
+- * @event: event handler
++ * @event: event handler. This method is being called by input core with
++ *    interrupts disabled and dev->event_lock spinlock held and so
++ *    it may not sleep
+  * @connect: called when attaching a handler to an input device
+  * @disconnect: disconnects a handler from input device
+  * @start: starts handler for given handle. This function is called by
+@@ -1066,10 +1142,18 @@ struct input_handle;
+  * @name: name of the handler, to be shown in /proc/bus/input/handlers
+  * @id_table: pointer to a table of input_device_ids this driver can
+  *    handle
+- * @blacklist: prointer to a table of input_device_ids this driver should
++ * @blacklist: pointer to a table of input_device_ids this driver should
+  *    ignore even if they match @id_table
+  * @h_list: list of input handles associated with the handler
+  * @node: for placing the driver onto input_handler_list
++ *
++ * Input handlers attach to input devices and create input handles. There
++ * are likely several handlers attached to any given input device at the
++ * same time. All of them will get their copy of input event generated by
++ * the device.
++ *
++ * Note that input core serializes calls to connect() and disconnect()
++ * methods.
+  */
+ struct input_handler {
+@@ -1091,6 +1175,18 @@ struct input_handler {
+       struct list_head        node;
+ };
++/**
++ * struct input_handle - links input device with an input handler
++ * @private: handler-specific data
++ * @open: counter showing whether the handle is 'open', i.e. should deliver
++ *    events from its device
++ * @name: name given to the handle by handler that created it
++ * @dev: input device the handle is attached to
++ * @handler: handler that works with the device through this handle
++ * @d_node: used to put the handle on device's list of attached handles
++ * @h_node: used to put the handle on handler's list of handles from which
++ *    it gets events
++ */
+ struct input_handle {
+       void *private;
+@@ -1213,7 +1309,7 @@ extern struct class input_class;
+  * @max_effects: maximum number of effects supported by device
+  * @effects: pointer to an array of effects currently loaded into device
+  * @effect_owners: array of effect owners; when file handle owning
+- *    an effect gets closed the effcet is automatically erased
++ *    an effect gets closed the effect is automatically erased
+  *
+  * Every force-feedback device must implement upload() and playback()
+  * methods; erase() is optional. set_gain() and set_autocenter() need
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:44 2008
+Message-Id: <20080206234444.583499251@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:51 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Dmitry Torokhov <dtor@mail.ru>,
+ Al Viro <viro@ZenIV.linux.org.uk>
+Subject: [patch 49/73] Input: evdev - implement proper locking
+Content-Disposition: inline; filename=input-evdev-implement-proper-locking.patch
+Content-Length: 28177
+Lines: 1025
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+patch 6addb1d6de1968b84852f54561cc9a999909b5a9 in mainline.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/evdev.c |  719 +++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 476 insertions(+), 243 deletions(-)
+
+--- a/drivers/input/evdev.c
++++ b/drivers/input/evdev.c
+@@ -30,6 +30,8 @@ struct evdev {
+       wait_queue_head_t wait;
+       struct evdev_client *grab;
+       struct list_head client_list;
++      spinlock_t client_lock; /* protects client_list */
++      struct mutex mutex;
+       struct device dev;
+ };
+@@ -37,39 +39,53 @@ struct evdev_client {
+       struct input_event buffer[EVDEV_BUFFER_SIZE];
+       int head;
+       int tail;
++      spinlock_t buffer_lock; /* protects access to buffer, head and tail */
+       struct fasync_struct *fasync;
+       struct evdev *evdev;
+       struct list_head node;
+ };
+ static struct evdev *evdev_table[EVDEV_MINORS];
++static DEFINE_MUTEX(evdev_table_mutex);
+-static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
++static void evdev_pass_event(struct evdev_client *client,
++                           struct input_event *event)
++{
++      /*
++       * Interrupts are disabled, just acquire the lock
++       */
++      spin_lock(&client->buffer_lock);
++      client->buffer[client->head++] = *event;
++      client->head &= EVDEV_BUFFER_SIZE - 1;
++      spin_unlock(&client->buffer_lock);
++
++      kill_fasync(&client->fasync, SIGIO, POLL_IN);
++}
++
++/*
++ * Pass incoming event to all connected clients. Note that we are
++ * caleld under a spinlock with interrupts off so we don't need
++ * to use rcu_read_lock() here. Writers will be using syncronize_sched()
++ * instead of synchrnoize_rcu().
++ */
++static void evdev_event(struct input_handle *handle,
++                      unsigned int type, unsigned int code, int value)
+ {
+       struct evdev *evdev = handle->private;
+       struct evdev_client *client;
++      struct input_event event;
+-      if (evdev->grab) {
+-              client = evdev->grab;
+-
+-              do_gettimeofday(&client->buffer[client->head].time);
+-              client->buffer[client->head].type = type;
+-              client->buffer[client->head].code = code;
+-              client->buffer[client->head].value = value;
+-              client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
+-
+-              kill_fasync(&client->fasync, SIGIO, POLL_IN);
+-      } else
+-              list_for_each_entry(client, &evdev->client_list, node) {
+-
+-                      do_gettimeofday(&client->buffer[client->head].time);
+-                      client->buffer[client->head].type = type;
+-                      client->buffer[client->head].code = code;
+-                      client->buffer[client->head].value = value;
+-                      client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
+-
+-                      kill_fasync(&client->fasync, SIGIO, POLL_IN);
+-              }
++      do_gettimeofday(&event.time);
++      event.type = type;
++      event.code = code;
++      event.value = value;
++
++      client = rcu_dereference(evdev->grab);
++      if (client)
++              evdev_pass_event(client, &event);
++      else
++              list_for_each_entry_rcu(client, &evdev->client_list, node)
++                      evdev_pass_event(client, &event);
+       wake_up_interruptible(&evdev->wait);
+ }
+@@ -88,38 +104,142 @@ static int evdev_flush(struct file *file
+ {
+       struct evdev_client *client = file->private_data;
+       struct evdev *evdev = client->evdev;
++      int retval;
++
++      retval = mutex_lock_interruptible(&evdev->mutex);
++      if (retval)
++              return retval;
+       if (!evdev->exist)
+-              return -ENODEV;
++              retval = -ENODEV;
++      else
++              retval = input_flush_device(&evdev->handle, file);
+-      return input_flush_device(&evdev->handle, file);
++      mutex_unlock(&evdev->mutex);
++      return retval;
+ }
+ static void evdev_free(struct device *dev)
+ {
+       struct evdev *evdev = container_of(dev, struct evdev, dev);
+-      evdev_table[evdev->minor] = NULL;
+       kfree(evdev);
+ }
++/*
++ * Grabs an event device (along with underlying input device).
++ * This function is called with evdev->mutex taken.
++ */
++static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
++{
++      int error;
++
++      if (evdev->grab)
++              return -EBUSY;
++
++      error = input_grab_device(&evdev->handle);
++      if (error)
++              return error;
++
++      rcu_assign_pointer(evdev->grab, client);
++      /*
++       * We don't use synchronize_rcu() here because read-side
++       * critical section is protected by a spinlock instead
++       * of rcu_read_lock().
++       */
++      synchronize_sched();
++
++      return 0;
++}
++
++static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
++{
++      if (evdev->grab != client)
++              return  -EINVAL;
++
++      rcu_assign_pointer(evdev->grab, NULL);
++      synchronize_sched();
++      input_release_device(&evdev->handle);
++
++      return 0;
++}
++
++static void evdev_attach_client(struct evdev *evdev,
++                              struct evdev_client *client)
++{
++      spin_lock(&evdev->client_lock);
++      list_add_tail_rcu(&client->node, &evdev->client_list);
++      spin_unlock(&evdev->client_lock);
++      synchronize_sched();
++}
++
++static void evdev_detach_client(struct evdev *evdev,
++                              struct evdev_client *client)
++{
++      spin_lock(&evdev->client_lock);
++      list_del_rcu(&client->node);
++      spin_unlock(&evdev->client_lock);
++      synchronize_sched();
++}
++
++static int evdev_open_device(struct evdev *evdev)
++{
++      int retval;
++
++      retval = mutex_lock_interruptible(&evdev->mutex);
++      if (retval)
++              return retval;
++
++      if (!evdev->exist)
++              retval = -ENODEV;
++      else if (!evdev->open++)
++              retval = input_open_device(&evdev->handle);
++
++      mutex_unlock(&evdev->mutex);
++      return retval;
++}
++
++static void evdev_close_device(struct evdev *evdev)
++{
++      mutex_lock(&evdev->mutex);
++
++      if (evdev->exist && !--evdev->open)
++              input_close_device(&evdev->handle);
++
++      mutex_unlock(&evdev->mutex);
++}
++
++/*
++ * Wake up users waiting for IO so they can disconnect from
++ * dead device.
++ */
++static void evdev_hangup(struct evdev *evdev)
++{
++      struct evdev_client *client;
++
++      spin_lock(&evdev->client_lock);
++      list_for_each_entry(client, &evdev->client_list, node)
++              kill_fasync(&client->fasync, SIGIO, POLL_HUP);
++      spin_unlock(&evdev->client_lock);
++
++      wake_up_interruptible(&evdev->wait);
++}
++
+ static int evdev_release(struct inode *inode, struct file *file)
+ {
+       struct evdev_client *client = file->private_data;
+       struct evdev *evdev = client->evdev;
+-      if (evdev->grab == client) {
+-              input_release_device(&evdev->handle);
+-              evdev->grab = NULL;
+-      }
++      mutex_lock(&evdev->mutex);
++      if (evdev->grab == client)
++              evdev_ungrab(evdev, client);
++      mutex_unlock(&evdev->mutex);
+       evdev_fasync(-1, file, 0);
+-      list_del(&client->node);
++      evdev_detach_client(evdev, client);
+       kfree(client);
+-      if (!--evdev->open && evdev->exist)
+-              input_close_device(&evdev->handle);
+-
++      evdev_close_device(evdev);
+       put_device(&evdev->dev);
+       return 0;
+@@ -127,41 +247,44 @@ static int evdev_release(struct inode *i
+ static int evdev_open(struct inode *inode, struct file *file)
+ {
+-      struct evdev_client *client;
+       struct evdev *evdev;
++      struct evdev_client *client;
+       int i = iminor(inode) - EVDEV_MINOR_BASE;
+       int error;
+       if (i >= EVDEV_MINORS)
+               return -ENODEV;
++      error = mutex_lock_interruptible(&evdev_table_mutex);
++      if (error)
++              return error;
+       evdev = evdev_table[i];
++      if (evdev)
++              get_device(&evdev->dev);
++      mutex_unlock(&evdev_table_mutex);
+-      if (!evdev || !evdev->exist)
++      if (!evdev)
+               return -ENODEV;
+-      get_device(&evdev->dev);
+-
+       client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
+       if (!client) {
+               error = -ENOMEM;
+               goto err_put_evdev;
+       }
++      spin_lock_init(&client->buffer_lock);
+       client->evdev = evdev;
+-      list_add_tail(&client->node, &evdev->client_list);
++      evdev_attach_client(evdev, client);
+-      if (!evdev->open++ && evdev->exist) {
+-              error = input_open_device(&evdev->handle);
+-              if (error)
+-                      goto err_free_client;
+-      }
++      error = evdev_open_device(evdev);
++      if (error)
++              goto err_free_client;
+       file->private_data = client;
+       return 0;
+  err_free_client:
+-      list_del(&client->node);
++      evdev_detach_client(evdev, client);
+       kfree(client);
+  err_put_evdev:
+       put_device(&evdev->dev);
+@@ -197,12 +320,14 @@ static inline size_t evdev_event_size(vo
+               sizeof(struct input_event_compat) : sizeof(struct input_event);
+ }
+-static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
++static int evdev_event_from_user(const char __user *buffer,
++                               struct input_event *event)
+ {
+       if (COMPAT_TEST) {
+               struct input_event_compat compat_event;
+-              if (copy_from_user(&compat_event, buffer, sizeof(struct input_event_compat)))
++              if (copy_from_user(&compat_event, buffer,
++                                 sizeof(struct input_event_compat)))
+                       return -EFAULT;
+               event->time.tv_sec = compat_event.time.tv_sec;
+@@ -219,7 +344,8 @@ static int evdev_event_from_user(const c
+       return 0;
+ }
+-static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
++static int evdev_event_to_user(char __user *buffer,
++                              const struct input_event *event)
+ {
+       if (COMPAT_TEST) {
+               struct input_event_compat compat_event;
+@@ -230,7 +356,8 @@ static int evdev_event_to_user(char __us
+               compat_event.code = event->code;
+               compat_event.value = event->value;
+-              if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat)))
++              if (copy_to_user(buffer, &compat_event,
++                               sizeof(struct input_event_compat)))
+                       return -EFAULT;
+       } else {
+@@ -248,7 +375,8 @@ static inline size_t evdev_event_size(vo
+       return sizeof(struct input_event);
+ }
+-static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
++static int evdev_event_from_user(const char __user *buffer,
++                               struct input_event *event)
+ {
+       if (copy_from_user(event, buffer, sizeof(struct input_event)))
+               return -EFAULT;
+@@ -256,7 +384,8 @@ static int evdev_event_from_user(const c
+       return 0;
+ }
+-static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
++static int evdev_event_to_user(char __user *buffer,
++                              const struct input_event *event)
+ {
+       if (copy_to_user(buffer, event, sizeof(struct input_event)))
+               return -EFAULT;
+@@ -266,37 +395,71 @@ static int evdev_event_to_user(char __us
+ #endif /* CONFIG_COMPAT */
+-static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
++static ssize_t evdev_write(struct file *file, const char __user *buffer,
++                         size_t count, loff_t *ppos)
+ {
+       struct evdev_client *client = file->private_data;
+       struct evdev *evdev = client->evdev;
+       struct input_event event;
+-      int retval = 0;
++      int retval;
+-      if (!evdev->exist)
+-              return -ENODEV;
++      retval = mutex_lock_interruptible(&evdev->mutex);
++      if (retval)
++              return retval;
++
++      if (!evdev->exist) {
++              retval = -ENODEV;
++              goto out;
++      }
+       while (retval < count) {
+-              if (evdev_event_from_user(buffer + retval, &event))
+-                      return -EFAULT;
+-              input_inject_event(&evdev->handle, event.type, event.code, event.value);
++              if (evdev_event_from_user(buffer + retval, &event)) {
++                      retval = -EFAULT;
++                      goto out;
++              }
++
++              input_inject_event(&evdev->handle,
++                                 event.type, event.code, event.value);
+               retval += evdev_event_size();
+       }
++ out:
++      mutex_unlock(&evdev->mutex);
+       return retval;
+ }
+-static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
++static int evdev_fetch_next_event(struct evdev_client *client,
++                                struct input_event *event)
++{
++      int have_event;
++
++      spin_lock_irq(&client->buffer_lock);
++
++      have_event = client->head != client->tail;
++      if (have_event) {
++              *event = client->buffer[client->tail++];
++              client->tail &= EVDEV_BUFFER_SIZE - 1;
++      }
++
++      spin_unlock_irq(&client->buffer_lock);
++
++      return have_event;
++}
++
++static ssize_t evdev_read(struct file *file, char __user *buffer,
++                        size_t count, loff_t *ppos)
+ {
+       struct evdev_client *client = file->private_data;
+       struct evdev *evdev = client->evdev;
++      struct input_event event;
+       int retval;
+       if (count < evdev_event_size())
+               return -EINVAL;
+-      if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
++      if (client->head == client->tail && evdev->exist &&
++          (file->f_flags & O_NONBLOCK))
+               return -EAGAIN;
+       retval = wait_event_interruptible(evdev->wait,
+@@ -307,14 +470,12 @@ static ssize_t evdev_read(struct file *f
+       if (!evdev->exist)
+               return -ENODEV;
+-      while (client->head != client->tail && retval + evdev_event_size() <= count) {
+-
+-              struct input_event *event = (struct input_event *) client->buffer + client->tail;
++      while (retval + evdev_event_size() <= count &&
++             evdev_fetch_next_event(client, &event)) {
+-              if (evdev_event_to_user(buffer + retval, event))
++              if (evdev_event_to_user(buffer + retval, &event))
+                       return -EFAULT;
+-              client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
+               retval += evdev_event_size();
+       }
+@@ -409,8 +570,8 @@ static int str_to_user(const char *str, 
+       return copy_to_user(p, str, len) ? -EFAULT : len;
+ }
+-static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
+-                              void __user *p, int compat_mode)
++static long evdev_do_ioctl(struct file *file, unsigned int cmd,
++                         void __user *p, int compat_mode)
+ {
+       struct evdev_client *client = file->private_data;
+       struct evdev *evdev = client->evdev;
+@@ -421,186 +582,208 @@ static long evdev_ioctl_handler(struct f
+       int i, t, u, v;
+       int error;
+-      if (!evdev->exist)
+-              return -ENODEV;
+-
+       switch (cmd) {
+-              case EVIOCGVERSION:
+-                      return put_user(EV_VERSION, ip);
++      case EVIOCGVERSION:
++              return put_user(EV_VERSION, ip);
+-              case EVIOCGID:
+-                      if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
+-                              return -EFAULT;
+-                      return 0;
++      case EVIOCGID:
++              if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
++                      return -EFAULT;
++              return 0;
+-              case EVIOCGREP:
+-                      if (!test_bit(EV_REP, dev->evbit))
+-                              return -ENOSYS;
+-                      if (put_user(dev->rep[REP_DELAY], ip))
+-                              return -EFAULT;
+-                      if (put_user(dev->rep[REP_PERIOD], ip + 1))
+-                              return -EFAULT;
+-                      return 0;
++      case EVIOCGREP:
++              if (!test_bit(EV_REP, dev->evbit))
++                      return -ENOSYS;
++              if (put_user(dev->rep[REP_DELAY], ip))
++                      return -EFAULT;
++              if (put_user(dev->rep[REP_PERIOD], ip + 1))
++                      return -EFAULT;
++              return 0;
+-              case EVIOCSREP:
+-                      if (!test_bit(EV_REP, dev->evbit))
+-                              return -ENOSYS;
+-                      if (get_user(u, ip))
+-                              return -EFAULT;
+-                      if (get_user(v, ip + 1))
+-                              return -EFAULT;
++      case EVIOCSREP:
++              if (!test_bit(EV_REP, dev->evbit))
++                      return -ENOSYS;
++              if (get_user(u, ip))
++                      return -EFAULT;
++              if (get_user(v, ip + 1))
++                      return -EFAULT;
+-                      input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
+-                      input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
++              input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
++              input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
+-                      return 0;
++              return 0;
+-              case EVIOCGKEYCODE:
+-                      if (get_user(t, ip))
+-                              return -EFAULT;
++      case EVIOCGKEYCODE:
++              if (get_user(t, ip))
++                      return -EFAULT;
+-                      error = dev->getkeycode(dev, t, &v);
+-                      if (error)
+-                              return error;
++              error = dev->getkeycode(dev, t, &v);
++              if (error)
++                      return error;
+-                      if (put_user(v, ip + 1))
+-                              return -EFAULT;
++              if (put_user(v, ip + 1))
++                      return -EFAULT;
+-                      return 0;
++              return 0;
+-              case EVIOCSKEYCODE:
+-                      if (get_user(t, ip) || get_user(v, ip + 1))
+-                              return -EFAULT;
++      case EVIOCSKEYCODE:
++              if (get_user(t, ip) || get_user(v, ip + 1))
++                      return -EFAULT;
+-                      return dev->setkeycode(dev, t, v);
++              return dev->setkeycode(dev, t, v);
+-              case EVIOCSFF:
+-                      if (copy_from_user(&effect, p, sizeof(effect)))
+-                              return -EFAULT;
++      case EVIOCSFF:
++              if (copy_from_user(&effect, p, sizeof(effect)))
++                      return -EFAULT;
+-                      error = input_ff_upload(dev, &effect, file);
++              error = input_ff_upload(dev, &effect, file);
+-                      if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
+-                              return -EFAULT;
++              if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
++                      return -EFAULT;
+-                      return error;
++              return error;
+-              case EVIOCRMFF:
+-                      return input_ff_erase(dev, (int)(unsigned long) p, file);
++      case EVIOCRMFF:
++              return input_ff_erase(dev, (int)(unsigned long) p, file);
+-              case EVIOCGEFFECTS:
+-                      i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0;
+-                      if (put_user(i, ip))
+-                              return -EFAULT;
+-                      return 0;
++      case EVIOCGEFFECTS:
++              i = test_bit(EV_FF, dev->evbit) ?
++                              dev->ff->max_effects : 0;
++              if (put_user(i, ip))
++                      return -EFAULT;
++              return 0;
+-              case EVIOCGRAB:
+-                      if (p) {
+-                              if (evdev->grab)
+-                                      return -EBUSY;
+-                              if (input_grab_device(&evdev->handle))
+-                                      return -EBUSY;
+-                              evdev->grab = client;
+-                              return 0;
+-                      } else {
+-                              if (evdev->grab != client)
+-                                      return -EINVAL;
+-                              input_release_device(&evdev->handle);
+-                              evdev->grab = NULL;
+-                              return 0;
++      case EVIOCGRAB:
++              if (p)
++                      return evdev_grab(evdev, client);
++              else
++                      return evdev_ungrab(evdev, client);
++
++      default:
++
++              if (_IOC_TYPE(cmd) != 'E')
++                      return -EINVAL;
++
++              if (_IOC_DIR(cmd) == _IOC_READ) {
++
++                      if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) {
++
++                              unsigned long *bits;
++                              int len;
++
++                              switch (_IOC_NR(cmd) & EV_MAX) {
++
++                              case      0: bits = dev->evbit;  len = EV_MAX;  break;
++                              case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
++                              case EV_REL: bits = dev->relbit; len = REL_MAX; break;
++                              case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
++                              case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
++                              case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
++                              case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
++                              case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;
++                              case EV_SW:  bits = dev->swbit;  len = SW_MAX;  break;
++                              default: return -EINVAL;
++                      }
++                              return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
+                       }
+-              default:
++                      if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
++                              return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
++                                                  p, compat_mode);
+-                      if (_IOC_TYPE(cmd) != 'E')
+-                              return -EINVAL;
++                      if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
++                              return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
++                                                  p, compat_mode);
+-                      if (_IOC_DIR(cmd) == _IOC_READ) {
++                      if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
++                              return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
++                                                  p, compat_mode);
+-                              if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
++                      if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
++                              return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
++                                                  p, compat_mode);
+-                                      unsigned long *bits;
+-                                      int len;
++                      if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
++                              return str_to_user(dev->name, _IOC_SIZE(cmd), p);
+-                                      switch (_IOC_NR(cmd) & EV_MAX) {
+-                                              case      0: bits = dev->evbit;  len = EV_MAX;  break;
+-                                              case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
+-                                              case EV_REL: bits = dev->relbit; len = REL_MAX; break;
+-                                              case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+-                                              case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
+-                                              case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
+-                                              case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+-                                              case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;
+-                                              case EV_SW:  bits = dev->swbit;  len = SW_MAX;  break;
+-                                              default: return -EINVAL;
+-                                      }
+-                                      return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
+-                              }
++                      if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
++                              return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
+-                              if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
+-                                      return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
+-                                                          p, compat_mode);
++                      if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
++                              return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
+-                              if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
+-                                      return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
+-                                                          p, compat_mode);
++                      if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+-                              if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
+-                                      return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
+-                                                          p, compat_mode);
++                              t = _IOC_NR(cmd) & ABS_MAX;
+-                              if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
+-                                      return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
+-                                                          p, compat_mode);
++                              abs.value = dev->abs[t];
++                              abs.minimum = dev->absmin[t];
++                              abs.maximum = dev->absmax[t];
++                              abs.fuzz = dev->absfuzz[t];
++                              abs.flat = dev->absflat[t];
+-                              if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
+-                                      return str_to_user(dev->name, _IOC_SIZE(cmd), p);
++                              if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
++                                      return -EFAULT;
+-                              if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
+-                                      return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
++                              return 0;
++                      }
+-                              if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
+-                                      return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
++              }
+-                              if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
++              if (_IOC_DIR(cmd) == _IOC_WRITE) {
+-                                      t = _IOC_NR(cmd) & ABS_MAX;
++                      if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+-                                      abs.value = dev->abs[t];
+-                                      abs.minimum = dev->absmin[t];
+-                                      abs.maximum = dev->absmax[t];
+-                                      abs.fuzz = dev->absfuzz[t];
+-                                      abs.flat = dev->absflat[t];
++                              t = _IOC_NR(cmd) & ABS_MAX;
+-                                      if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
+-                                              return -EFAULT;
++                              if (copy_from_user(&abs, p,
++                                              sizeof(struct input_absinfo)))
++                                      return -EFAULT;
++
++                              /*
++                               * Take event lock to ensure that we are not
++                               * changing device parameters in the middle
++                               * of event.
++                               */
++                              spin_lock_irq(&dev->event_lock);
++
++                              dev->abs[t] = abs.value;
++                              dev->absmin[t] = abs.minimum;
++                              dev->absmax[t] = abs.maximum;
++                              dev->absfuzz[t] = abs.fuzz;
++                              dev->absflat[t] = abs.flat;
+-                                      return 0;
+-                              }
++                              spin_unlock_irq(&dev->event_lock);
++                              return 0;
+                       }
++              }
++      }
++      return -EINVAL;
++}
+-                      if (_IOC_DIR(cmd) == _IOC_WRITE) {
+-
+-                              if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
++static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
++                              void __user *p, int compat_mode)
++{
++      struct evdev_client *client = file->private_data;
++      struct evdev *evdev = client->evdev;
++      int retval;
+-                                      t = _IOC_NR(cmd) & ABS_MAX;
++      retval = mutex_lock_interruptible(&evdev->mutex);
++      if (retval)
++              return retval;
+-                                      if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
+-                                              return -EFAULT;
++      if (!evdev->exist) {
++              retval = -ENODEV;
++              goto out;
++      }
+-                                      dev->abs[t] = abs.value;
+-                                      dev->absmin[t] = abs.minimum;
+-                                      dev->absmax[t] = abs.maximum;
+-                                      dev->absfuzz[t] = abs.fuzz;
+-                                      dev->absflat[t] = abs.flat;
++      retval = evdev_do_ioctl(file, cmd, p, compat_mode);
+-                                      return 0;
+-                              }
+-                      }
+-      }
+-      return -EINVAL;
++ out:
++      mutex_unlock(&evdev->mutex);
++      return retval;
+ }
+ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+@@ -609,27 +792,79 @@ static long evdev_ioctl(struct file *fil
+ }
+ #ifdef CONFIG_COMPAT
+-static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
++static long evdev_ioctl_compat(struct file *file,
++                              unsigned int cmd, unsigned long arg)
+ {
+       return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1);
+ }
+ #endif
+ static const struct file_operations evdev_fops = {
+-      .owner =        THIS_MODULE,
+-      .read =         evdev_read,
+-      .write =        evdev_write,
+-      .poll =         evdev_poll,
+-      .open =         evdev_open,
+-      .release =      evdev_release,
+-      .unlocked_ioctl = evdev_ioctl,
++      .owner          = THIS_MODULE,
++      .read           = evdev_read,
++      .write          = evdev_write,
++      .poll           = evdev_poll,
++      .open           = evdev_open,
++      .release        = evdev_release,
++      .unlocked_ioctl = evdev_ioctl,
+ #ifdef CONFIG_COMPAT
+-      .compat_ioctl = evdev_ioctl_compat,
++      .compat_ioctl   = evdev_ioctl_compat,
+ #endif
+-      .fasync =       evdev_fasync,
+-      .flush =        evdev_flush
++      .fasync         = evdev_fasync,
++      .flush          = evdev_flush
+ };
++static int evdev_install_chrdev(struct evdev *evdev)
++{
++      /*
++       * No need to do any locking here as calls to connect and
++       * disconnect are serialized by the input core
++       */
++      evdev_table[evdev->minor] = evdev;
++      return 0;
++}
++
++static void evdev_remove_chrdev(struct evdev *evdev)
++{
++      /*
++       * Lock evdev table to prevent race with evdev_open()
++       */
++      mutex_lock(&evdev_table_mutex);
++      evdev_table[evdev->minor] = NULL;
++      mutex_unlock(&evdev_table_mutex);
++}
++
++/*
++ * Mark device non-existent. This disables writes, ioctls and
++ * prevents new users from opening the device. Already posted
++ * blocking reads will stay, however new ones will fail.
++ */
++static void evdev_mark_dead(struct evdev *evdev)
++{
++      mutex_lock(&evdev->mutex);
++      evdev->exist = 0;
++      mutex_unlock(&evdev->mutex);
++}
++
++static void evdev_cleanup(struct evdev *evdev)
++{
++      struct input_handle *handle = &evdev->handle;
++
++      evdev_mark_dead(evdev);
++      evdev_hangup(evdev);
++      evdev_remove_chrdev(evdev);
++
++      /* evdev is marked dead so no one else accesses evdev->open */
++      if (evdev->open) {
++              input_flush_device(handle, NULL);
++              input_close_device(handle);
++      }
++}
++
++/*
++ * Create new evdev device. Note that input core serializes calls
++ * to connect and disconnect so we don't need to lock evdev_table here.
++ */
+ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
+                        const struct input_device_id *id)
+ {
+@@ -637,7 +872,10 @@ static int evdev_connect(struct input_ha
+       int minor;
+       int error;
+-      for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
++      for (minor = 0; minor < EVDEV_MINORS; minor++)
++              if (!evdev_table[minor])
++                      break;
++
+       if (minor == EVDEV_MINORS) {
+               printk(KERN_ERR "evdev: no more free evdev devices\n");
+               return -ENFILE;
+@@ -648,38 +886,44 @@ static int evdev_connect(struct input_ha
+               return -ENOMEM;
+       INIT_LIST_HEAD(&evdev->client_list);
++      spin_lock_init(&evdev->client_lock);
++      mutex_init(&evdev->mutex);
+       init_waitqueue_head(&evdev->wait);
++      snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
+       evdev->exist = 1;
+       evdev->minor = minor;
++
+       evdev->handle.dev = dev;
+       evdev->handle.name = evdev->name;
+       evdev->handle.handler = handler;
+       evdev->handle.private = evdev;
+-      snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
+-      snprintf(evdev->dev.bus_id, sizeof(evdev->dev.bus_id),
+-               "event%d", minor);
++      strlcpy(evdev->dev.bus_id, evdev->name, sizeof(evdev->dev.bus_id));
++      evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
+       evdev->dev.class = &input_class;
+       evdev->dev.parent = &dev->dev;
+-      evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
+       evdev->dev.release = evdev_free;
+       device_initialize(&evdev->dev);
+-      evdev_table[minor] = evdev;
+-
+-      error = device_add(&evdev->dev);
++      error = input_register_handle(&evdev->handle);
+       if (error)
+               goto err_free_evdev;
+-      error = input_register_handle(&evdev->handle);
++      error = evdev_install_chrdev(evdev);
++      if (error)
++              goto err_unregister_handle;
++
++      error = device_add(&evdev->dev);
+       if (error)
+-              goto err_delete_evdev;
++              goto err_cleanup_evdev;
+       return 0;
+- err_delete_evdev:
+-      device_del(&evdev->dev);
++ err_cleanup_evdev:
++      evdev_cleanup(evdev);
++ err_unregister_handle:
++      input_unregister_handle(&evdev->handle);
+  err_free_evdev:
+       put_device(&evdev->dev);
+       return error;
+@@ -688,21 +932,10 @@ static int evdev_connect(struct input_ha
+ static void evdev_disconnect(struct input_handle *handle)
+ {
+       struct evdev *evdev = handle->private;
+-      struct evdev_client *client;
+-      input_unregister_handle(handle);
+       device_del(&evdev->dev);
+-
+-      evdev->exist = 0;
+-
+-      if (evdev->open) {
+-              input_flush_device(handle, NULL);
+-              input_close_device(handle);
+-              list_for_each_entry(client, &evdev->client_list, node)
+-                      kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+-              wake_up_interruptible(&evdev->wait);
+-      }
+-
++      evdev_cleanup(evdev);
++      input_unregister_handle(handle);
+       put_device(&evdev->dev);
+ }
+@@ -714,13 +947,13 @@ static const struct input_device_id evde
+ MODULE_DEVICE_TABLE(input, evdev_ids);
+ static struct input_handler evdev_handler = {
+-      .event =        evdev_event,
+-      .connect =      evdev_connect,
+-      .disconnect =   evdev_disconnect,
+-      .fops =         &evdev_fops,
+-      .minor =        EVDEV_MINOR_BASE,
+-      .name =         "evdev",
+-      .id_table =     evdev_ids,
++      .event          = evdev_event,
++      .connect        = evdev_connect,
++      .disconnect     = evdev_disconnect,
++      .fops           = &evdev_fops,
++      .minor          = EVDEV_MINOR_BASE,
++      .name           = "evdev",
++      .id_table       = evdev_ids,
+ };
+ static int __init evdev_init(void)
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:45 2008
+Message-Id: <20080206234444.806875134@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:52 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Dmitry Torokhov <dtor@mail.ru>,
+ Al Viro <viro@ZenIV.linux.org.uk>
+Subject: [patch 50/73] Input: mousedev - implement proper locking
+Content-Disposition: inline; filename=input-mousedev-implement-proper-locking.patch
+Content-Length: 31513
+Lines: 1100
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+patch 464b241575f3700e14492e34f26bcd1794280f55 in mainline.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/mousedev.c |  742 +++++++++++++++++++++++++++++------------------
+ 1 file changed, 470 insertions(+), 272 deletions(-)
+
+--- a/drivers/input/mousedev.c
++++ b/drivers/input/mousedev.c
+@@ -61,9 +61,11 @@ struct mousedev {
+       int open;
+       int minor;
+       char name[16];
++      struct input_handle handle;
+       wait_queue_head_t wait;
+       struct list_head client_list;
+-      struct input_handle handle;
++      spinlock_t client_lock; /* protects client_list */
++      struct mutex mutex;
+       struct device dev;
+       struct list_head mixdev_node;
+@@ -113,108 +115,137 @@ static unsigned char mousedev_imex_seq[]
+ static struct input_handler mousedev_handler;
+ static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
++static DEFINE_MUTEX(mousedev_table_mutex);
+ static struct mousedev *mousedev_mix;
+ static LIST_HEAD(mousedev_mix_list);
++static void mixdev_open_devices(void);
++static void mixdev_close_devices(void);
++
+ #define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
+ #define fy(i)  (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
+-static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
++static void mousedev_touchpad_event(struct input_dev *dev,
++                                  struct mousedev *mousedev,
++                                  unsigned int code, int value)
+ {
+       int size, tmp;
+       enum { FRACTION_DENOM = 128 };
+       switch (code) {
+-              case ABS_X:
+-                      fx(0) = value;
+-                      if (mousedev->touch && mousedev->pkt_count >= 2) {
+-                              size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+-                              if (size == 0)
+-                                      size = 256 * 2;
+-                              tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
+-                              tmp += mousedev->frac_dx;
+-                              mousedev->packet.dx = tmp / FRACTION_DENOM;
+-                              mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM;
+-                      }
+-                      break;
+-              case ABS_Y:
+-                      fy(0) = value;
+-                      if (mousedev->touch && mousedev->pkt_count >= 2) {
+-                              /* use X size to keep the same scale */
+-                              size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+-                              if (size == 0)
+-                                      size = 256 * 2;
+-                              tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
+-                              tmp += mousedev->frac_dy;
+-                              mousedev->packet.dy = tmp / FRACTION_DENOM;
+-                              mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM;
+-                      }
+-                      break;
++      case ABS_X:
++              fx(0) = value;
++              if (mousedev->touch && mousedev->pkt_count >= 2) {
++                      size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
++                      if (size == 0)
++                              size = 256 * 2;
++                      tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size;
++                      tmp += mousedev->frac_dx;
++                      mousedev->packet.dx = tmp / FRACTION_DENOM;
++                      mousedev->frac_dx =
++                              tmp - mousedev->packet.dx * FRACTION_DENOM;
++              }
++              break;
++
++      case ABS_Y:
++              fy(0) = value;
++              if (mousedev->touch && mousedev->pkt_count >= 2) {
++                      /* use X size to keep the same scale */
++                      size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
++                      if (size == 0)
++                              size = 256 * 2;
++                      tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size;
++                      tmp += mousedev->frac_dy;
++                      mousedev->packet.dy = tmp / FRACTION_DENOM;
++                      mousedev->frac_dy = tmp -
++                              mousedev->packet.dy * FRACTION_DENOM;
++              }
++              break;
+       }
+ }
+-static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
++static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
++                              unsigned int code, int value)
+ {
+       int size;
+       switch (code) {
+-              case ABS_X:
+-                      size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+-                      if (size == 0)
+-                              size = xres ? : 1;
+-                      if (value > dev->absmax[ABS_X])
+-                              value = dev->absmax[ABS_X];
+-                      if (value < dev->absmin[ABS_X])
+-                              value = dev->absmin[ABS_X];
+-                      mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size;
+-                      mousedev->packet.abs_event = 1;
+-                      break;
+-              case ABS_Y:
+-                      size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
+-                      if (size == 0)
+-                              size = yres ? : 1;
+-                      if (value > dev->absmax[ABS_Y])
+-                              value = dev->absmax[ABS_Y];
+-                      if (value < dev->absmin[ABS_Y])
+-                              value = dev->absmin[ABS_Y];
+-                      mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size;
+-                      mousedev->packet.abs_event = 1;
+-                      break;
++      case ABS_X:
++              size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
++              if (size == 0)
++                      size = xres ? : 1;
++              if (value > dev->absmax[ABS_X])
++                      value = dev->absmax[ABS_X];
++              if (value < dev->absmin[ABS_X])
++                      value = dev->absmin[ABS_X];
++              mousedev->packet.x =
++                      ((value - dev->absmin[ABS_X]) * xres) / size;
++              mousedev->packet.abs_event = 1;
++              break;
++
++      case ABS_Y:
++              size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
++              if (size == 0)
++                      size = yres ? : 1;
++              if (value > dev->absmax[ABS_Y])
++                      value = dev->absmax[ABS_Y];
++              if (value < dev->absmin[ABS_Y])
++                      value = dev->absmin[ABS_Y];
++              mousedev->packet.y = yres -
++                      ((value - dev->absmin[ABS_Y]) * yres) / size;
++              mousedev->packet.abs_event = 1;
++              break;
+       }
+ }
+-static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value)
++static void mousedev_rel_event(struct mousedev *mousedev,
++                              unsigned int code, int value)
+ {
+       switch (code) {
+-              case REL_X:     mousedev->packet.dx += value; break;
+-              case REL_Y:     mousedev->packet.dy -= value; break;
+-              case REL_WHEEL: mousedev->packet.dz -= value; break;
++      case REL_X:
++              mousedev->packet.dx += value;
++              break;
++
++      case REL_Y:
++              mousedev->packet.dy -= value;
++              break;
++
++      case REL_WHEEL:
++              mousedev->packet.dz -= value;
++              break;
+       }
+ }
+-static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value)
++static void mousedev_key_event(struct mousedev *mousedev,
++                              unsigned int code, int value)
+ {
+       int index;
+       switch (code) {
+-              case BTN_TOUCH:
+-              case BTN_0:
+-              case BTN_LEFT:          index = 0; break;
+-              case BTN_STYLUS:
+-              case BTN_1:
+-              case BTN_RIGHT:         index = 1; break;
+-              case BTN_2:
+-              case BTN_FORWARD:
+-              case BTN_STYLUS2:
+-              case BTN_MIDDLE:        index = 2; break;
+-              case BTN_3:
+-              case BTN_BACK:
+-              case BTN_SIDE:          index = 3; break;
+-              case BTN_4:
+-              case BTN_EXTRA:         index = 4; break;
+-              default:                return;
++
++      case BTN_TOUCH:
++      case BTN_0:
++      case BTN_LEFT:          index = 0; break;
++
++      case BTN_STYLUS:
++      case BTN_1:
++      case BTN_RIGHT:         index = 1; break;
++
++      case BTN_2:
++      case BTN_FORWARD:
++      case BTN_STYLUS2:
++      case BTN_MIDDLE:        index = 2; break;
++
++      case BTN_3:
++      case BTN_BACK:
++      case BTN_SIDE:          index = 3; break;
++
++      case BTN_4:
++      case BTN_EXTRA:         index = 4; break;
++
++      default:                return;
+       }
+       if (value) {
+@@ -226,19 +257,22 @@ static void mousedev_key_event(struct mo
+       }
+ }
+-static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet)
++static void mousedev_notify_readers(struct mousedev *mousedev,
++                                  struct mousedev_hw_data *packet)
+ {
+       struct mousedev_client *client;
+       struct mousedev_motion *p;
+-      unsigned long flags;
++      unsigned int new_head;
+       int wake_readers = 0;
+-      list_for_each_entry(client, &mousedev->client_list, node) {
+-              spin_lock_irqsave(&client->packet_lock, flags);
++      list_for_each_entry_rcu(client, &mousedev->client_list, node) {
++
++              /* Just acquire the lock, interrupts already disabled */
++              spin_lock(&client->packet_lock);
+               p = &client->packets[client->head];
+               if (client->ready && p->buttons != mousedev->packet.buttons) {
+-                      unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN;
++                      new_head = (client->head + 1) % PACKET_QUEUE_LEN;
+                       if (new_head != client->tail) {
+                               p = &client->packets[client->head = new_head];
+                               memset(p, 0, sizeof(struct mousedev_motion));
+@@ -253,19 +287,22 @@ static void mousedev_notify_readers(stru
+               }
+               client->pos_x += packet->dx;
+-              client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x);
++              client->pos_x = client->pos_x < 0 ?
++                      0 : (client->pos_x >= xres ? xres : client->pos_x);
+               client->pos_y += packet->dy;
+-              client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y);
++              client->pos_y = client->pos_y < 0 ?
++                      0 : (client->pos_y >= yres ? yres : client->pos_y);
+               p->dx += packet->dx;
+               p->dy += packet->dy;
+               p->dz += packet->dz;
+               p->buttons = mousedev->packet.buttons;
+-              if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons)
++              if (p->dx || p->dy || p->dz ||
++                  p->buttons != client->last_buttons)
+                       client->ready = 1;
+-              spin_unlock_irqrestore(&client->packet_lock, flags);
++              spin_unlock(&client->packet_lock);
+               if (client->ready) {
+                       kill_fasync(&client->fasync, SIGIO, POLL_IN);
+@@ -281,7 +318,8 @@ static void mousedev_touchpad_touch(stru
+ {
+       if (!value) {
+               if (mousedev->touch &&
+-                  time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) {
++                  time_before(jiffies,
++                              mousedev->touch + msecs_to_jiffies(tap_time))) {
+                       /*
+                        * Toggle left button to emulate tap.
+                        * We rely on the fact that mousedev_mix always has 0
+@@ -290,7 +328,8 @@ static void mousedev_touchpad_touch(stru
+                       set_bit(0, &mousedev->packet.buttons);
+                       set_bit(0, &mousedev_mix->packet.buttons);
+                       mousedev_notify_readers(mousedev, &mousedev_mix->packet);
+-                      mousedev_notify_readers(mousedev_mix, &mousedev_mix->packet);
++                      mousedev_notify_readers(mousedev_mix,
++                                              &mousedev_mix->packet);
+                       clear_bit(0, &mousedev->packet.buttons);
+                       clear_bit(0, &mousedev_mix->packet.buttons);
+               }
+@@ -302,54 +341,61 @@ static void mousedev_touchpad_touch(stru
+               mousedev->touch = jiffies;
+ }
+-static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
++static void mousedev_event(struct input_handle *handle,
++                         unsigned int type, unsigned int code, int value)
+ {
+       struct mousedev *mousedev = handle->private;
+       switch (type) {
+-              case EV_ABS:
+-                      /* Ignore joysticks */
+-                      if (test_bit(BTN_TRIGGER, handle->dev->keybit))
+-                              return;
+-                      if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
+-                              mousedev_touchpad_event(handle->dev, mousedev, code, value);
++      case EV_ABS:
++              /* Ignore joysticks */
++              if (test_bit(BTN_TRIGGER, handle->dev->keybit))
++                      return;
++
++              if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
++                      mousedev_touchpad_event(handle->dev,
++                                              mousedev, code, value);
++              else
++                      mousedev_abs_event(handle->dev, mousedev, code, value);
++
++              break;
++
++      case EV_REL:
++              mousedev_rel_event(mousedev, code, value);
++              break;
++
++      case EV_KEY:
++              if (value != 2) {
++                      if (code == BTN_TOUCH &&
++                          test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
++                              mousedev_touchpad_touch(mousedev, value);
+                       else
+-                              mousedev_abs_event(handle->dev, mousedev, code, value);
+-
+-                      break;
+-
+-              case EV_REL:
+-                      mousedev_rel_event(mousedev, code, value);
+-                      break;
++                              mousedev_key_event(mousedev, code, value);
++              }
++              break;
+-              case EV_KEY:
+-                      if (value != 2) {
+-                              if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
+-                                      mousedev_touchpad_touch(mousedev, value);
+-                              else
+-                                      mousedev_key_event(mousedev, code, value);
++      case EV_SYN:
++              if (code == SYN_REPORT) {
++                      if (mousedev->touch) {
++                              mousedev->pkt_count++;
++                              /*
++                               * Input system eats duplicate events,
++                               * but we need all of them to do correct
++                               * averaging so apply present one forward
++                               */
++                              fx(0) = fx(1);
++                              fy(0) = fy(1);
+                       }
+-                      break;
+-
+-              case EV_SYN:
+-                      if (code == SYN_REPORT) {
+-                              if (mousedev->touch) {
+-                                      mousedev->pkt_count++;
+-                                      /* Input system eats duplicate events, but we need all of them
+-                                       * to do correct averaging so apply present one forward
+-                                       */
+-                                      fx(0) = fx(1);
+-                                      fy(0) = fy(1);
+-                              }
+-                              mousedev_notify_readers(mousedev, &mousedev->packet);
+-                              mousedev_notify_readers(mousedev_mix, &mousedev->packet);
++                      mousedev_notify_readers(mousedev, &mousedev->packet);
++                      mousedev_notify_readers(mousedev_mix, &mousedev->packet);
+-                              mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
+-                              mousedev->packet.abs_event = 0;
+-                      }
+-                      break;
++                      mousedev->packet.dx = mousedev->packet.dy =
++                              mousedev->packet.dz = 0;
++                      mousedev->packet.abs_event = 0;
++              }
++              break;
+       }
+ }
+@@ -367,41 +413,45 @@ static void mousedev_free(struct device 
+ {
+       struct mousedev *mousedev = container_of(dev, struct mousedev, dev);
+-      mousedev_table[mousedev->minor] = NULL;
+       kfree(mousedev);
+ }
+-static int mixdev_add_device(struct mousedev *mousedev)
++static int mousedev_open_device(struct mousedev *mousedev)
+ {
+-      int error;
+-
+-      if (mousedev_mix->open) {
+-              error = input_open_device(&mousedev->handle);
+-              if (error)
+-                      return error;
++      int retval;
+-              mousedev->open++;
+-              mousedev->mixdev_open = 1;
+-      }
++      retval = mutex_lock_interruptible(&mousedev->mutex);
++      if (retval)
++              return retval;
+-      get_device(&mousedev->dev);
+-      list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
++      if (mousedev->minor == MOUSEDEV_MIX)
++              mixdev_open_devices();
++      else if (!mousedev->exist)
++              retval = -ENODEV;
++      else if (!mousedev->open++)
++              retval = input_open_device(&mousedev->handle);
+-      return 0;
++      mutex_unlock(&mousedev->mutex);
++      return retval;
+ }
+-static void mixdev_remove_device(struct mousedev *mousedev)
++static void mousedev_close_device(struct mousedev *mousedev)
+ {
+-      if (mousedev->mixdev_open) {
+-              mousedev->mixdev_open = 0;
+-              if (!--mousedev->open && mousedev->exist)
+-                      input_close_device(&mousedev->handle);
+-      }
++      mutex_lock(&mousedev->mutex);
+-      list_del_init(&mousedev->mixdev_node);
+-      put_device(&mousedev->dev);
++      if (mousedev->minor == MOUSEDEV_MIX)
++              mixdev_close_devices();
++      else if (mousedev->exist && !--mousedev->open)
++              input_close_device(&mousedev->handle);
++
++      mutex_unlock(&mousedev->mutex);
+ }
++/*
++ * Open all available devices so they can all be multiplexed in one.
++ * stream. Note that this function is called with mousedev_mix->mutex
++ * held.
++ */
+ static void mixdev_open_devices(void)
+ {
+       struct mousedev *mousedev;
+@@ -411,16 +461,19 @@ static void mixdev_open_devices(void)
+       list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+               if (!mousedev->mixdev_open) {
+-                      if (!mousedev->open && mousedev->exist)
+-                              if (input_open_device(&mousedev->handle))
+-                                      continue;
++                      if (mousedev_open_device(mousedev))
++                              continue;
+-                      mousedev->open++;
+                       mousedev->mixdev_open = 1;
+               }
+       }
+ }
++/*
++ * Close all devices that were opened as part of multiplexed
++ * device. Note that this function is called with mousedev_mix->mutex
++ * held.
++ */
+ static void mixdev_close_devices(void)
+ {
+       struct mousedev *mousedev;
+@@ -431,33 +484,50 @@ static void mixdev_close_devices(void)
+       list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+               if (mousedev->mixdev_open) {
+                       mousedev->mixdev_open = 0;
+-                      if (!--mousedev->open && mousedev->exist)
+-                              input_close_device(&mousedev->handle);
++                      mousedev_close_device(mousedev);
+               }
+       }
+ }
++
++static void mousedev_attach_client(struct mousedev *mousedev,
++                                 struct mousedev_client *client)
++{
++      spin_lock(&mousedev->client_lock);
++      list_add_tail_rcu(&client->node, &mousedev->client_list);
++      spin_unlock(&mousedev->client_lock);
++      /*
++       * We don't use synchronize_rcu() here because read-side
++       * critical section is protected by a spinlock (dev->event_lock)
++       * instead of rcu_read_lock().
++       */
++      synchronize_sched();
++}
++
++static void mousedev_detach_client(struct mousedev *mousedev,
++                                 struct mousedev_client *client)
++{
++      spin_lock(&mousedev->client_lock);
++      list_del_rcu(&client->node);
++      spin_unlock(&mousedev->client_lock);
++      synchronize_sched();
++}
++
+ static int mousedev_release(struct inode *inode, struct file *file)
+ {
+       struct mousedev_client *client = file->private_data;
+       struct mousedev *mousedev = client->mousedev;
+       mousedev_fasync(-1, file, 0);
+-
+-      list_del(&client->node);
++      mousedev_detach_client(mousedev, client);
+       kfree(client);
+-      if (mousedev->minor == MOUSEDEV_MIX)
+-              mixdev_close_devices();
+-      else if (!--mousedev->open && mousedev->exist)
+-              input_close_device(&mousedev->handle);
+-
++      mousedev_close_device(mousedev);
+       put_device(&mousedev->dev);
+       return 0;
+ }
+-
+ static int mousedev_open(struct inode *inode, struct file *file)
+ {
+       struct mousedev_client *client;
+@@ -475,12 +545,17 @@ static int mousedev_open(struct inode *i
+       if (i >= MOUSEDEV_MINORS)
+               return -ENODEV;
++      error = mutex_lock_interruptible(&mousedev_table_mutex);
++      if (error)
++              return error;
+       mousedev = mousedev_table[i];
++      if (mousedev)
++              get_device(&mousedev->dev);
++      mutex_unlock(&mousedev_table_mutex);
++
+       if (!mousedev)
+               return -ENODEV;
+-      get_device(&mousedev->dev);
+-
+       client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
+       if (!client) {
+               error = -ENOMEM;
+@@ -491,21 +566,17 @@ static int mousedev_open(struct inode *i
+       client->pos_x = xres / 2;
+       client->pos_y = yres / 2;
+       client->mousedev = mousedev;
+-      list_add_tail(&client->node, &mousedev->client_list);
++      mousedev_attach_client(mousedev, client);
+-      if (mousedev->minor == MOUSEDEV_MIX)
+-              mixdev_open_devices();
+-      else if (!mousedev->open++ && mousedev->exist) {
+-              error = input_open_device(&mousedev->handle);
+-              if (error)
+-                      goto err_free_client;
+-      }
++      error = mousedev_open_device(mousedev);
++      if (error)
++              goto err_free_client;
+       file->private_data = client;
+       return 0;
+  err_free_client:
+-      list_del(&client->node);
++      mousedev_detach_client(mousedev, client);
+       kfree(client);
+  err_put_mousedev:
+       put_device(&mousedev->dev);
+@@ -517,41 +588,41 @@ static inline int mousedev_limit_delta(i
+       return delta > limit ? limit : (delta < -limit ? -limit : delta);
+ }
+-static void mousedev_packet(struct mousedev_client *client, signed char *ps2_data)
++static void mousedev_packet(struct mousedev_client *client,
++                          signed char *ps2_data)
+ {
+-      struct mousedev_motion *p;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&client->packet_lock, flags);
+-      p = &client->packets[client->tail];
++      struct mousedev_motion *p = &client->packets[client->tail];
+-      ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
++      ps2_data[0] = 0x08 |
++              ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
+       ps2_data[1] = mousedev_limit_delta(p->dx, 127);
+       ps2_data[2] = mousedev_limit_delta(p->dy, 127);
+       p->dx -= ps2_data[1];
+       p->dy -= ps2_data[2];
+       switch (client->mode) {
+-              case MOUSEDEV_EMUL_EXPS:
+-                      ps2_data[3] = mousedev_limit_delta(p->dz, 7);
+-                      p->dz -= ps2_data[3];
+-                      ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
+-                      client->bufsiz = 4;
+-                      break;
+-
+-              case MOUSEDEV_EMUL_IMPS:
+-                      ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
+-                      ps2_data[3] = mousedev_limit_delta(p->dz, 127);
+-                      p->dz -= ps2_data[3];
+-                      client->bufsiz = 4;
+-                      break;
+-
+-              case MOUSEDEV_EMUL_PS2:
+-              default:
+-                      ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
+-                      p->dz = 0;
+-                      client->bufsiz = 3;
+-                      break;
++      case MOUSEDEV_EMUL_EXPS:
++              ps2_data[3] = mousedev_limit_delta(p->dz, 7);
++              p->dz -= ps2_data[3];
++              ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
++              client->bufsiz = 4;
++              break;
++
++      case MOUSEDEV_EMUL_IMPS:
++              ps2_data[0] |=
++                      ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
++              ps2_data[3] = mousedev_limit_delta(p->dz, 127);
++              p->dz -= ps2_data[3];
++              client->bufsiz = 4;
++              break;
++
++      case MOUSEDEV_EMUL_PS2:
++      default:
++              ps2_data[0] |=
++                      ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
++              p->dz = 0;
++              client->bufsiz = 3;
++              break;
+       }
+       if (!p->dx && !p->dy && !p->dz) {
+@@ -561,12 +632,56 @@ static void mousedev_packet(struct mouse
+               } else
+                       client->tail = (client->tail + 1) % PACKET_QUEUE_LEN;
+       }
+-
+-      spin_unlock_irqrestore(&client->packet_lock, flags);
+ }
++static void mousedev_generate_response(struct mousedev_client *client,
++                                      int command)
++{
++      client->ps2[0] = 0xfa; /* ACK */
++
++      switch (command) {
+-static ssize_t mousedev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
++      case 0xeb: /* Poll */
++              mousedev_packet(client, &client->ps2[1]);
++              client->bufsiz++; /* account for leading ACK */
++              break;
++
++      case 0xf2: /* Get ID */
++              switch (client->mode) {
++              case MOUSEDEV_EMUL_PS2:
++                      client->ps2[1] = 0;
++                      break;
++              case MOUSEDEV_EMUL_IMPS:
++                      client->ps2[1] = 3;
++                      break;
++              case MOUSEDEV_EMUL_EXPS:
++                      client->ps2[1] = 4;
++                      break;
++              }
++              client->bufsiz = 2;
++              break;
++
++      case 0xe9: /* Get info */
++              client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
++              client->bufsiz = 4;
++              break;
++
++      case 0xff: /* Reset */
++              client->impsseq = client->imexseq = 0;
++              client->mode = MOUSEDEV_EMUL_PS2;
++              client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
++              client->bufsiz = 3;
++              break;
++
++      default:
++              client->bufsiz = 1;
++              break;
++      }
++      client->buffer = client->bufsiz;
++}
++
++static ssize_t mousedev_write(struct file *file, const char __user *buffer,
++                              size_t count, loff_t *ppos)
+ {
+       struct mousedev_client *client = file->private_data;
+       unsigned char c;
+@@ -577,6 +692,8 @@ static ssize_t mousedev_write(struct fil
+               if (get_user(c, buffer + i))
+                       return -EFAULT;
++              spin_lock_irq(&client->packet_lock);
++
+               if (c == mousedev_imex_seq[client->imexseq]) {
+                       if (++client->imexseq == MOUSEDEV_SEQ_LEN) {
+                               client->imexseq = 0;
+@@ -593,68 +710,39 @@ static ssize_t mousedev_write(struct fil
+               } else
+                       client->impsseq = 0;
+-              client->ps2[0] = 0xfa;
+-
+-              switch (c) {
+-
+-                      case 0xeb: /* Poll */
+-                              mousedev_packet(client, &client->ps2[1]);
+-                              client->bufsiz++; /* account for leading ACK */
+-                              break;
+-
+-                      case 0xf2: /* Get ID */
+-                              switch (client->mode) {
+-                                      case MOUSEDEV_EMUL_PS2:  client->ps2[1] = 0; break;
+-                                      case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break;
+-                                      case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break;
+-                              }
+-                              client->bufsiz = 2;
+-                              break;
+-
+-                      case 0xe9: /* Get info */
+-                              client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
+-                              client->bufsiz = 4;
+-                              break;
+-
+-                      case 0xff: /* Reset */
+-                              client->impsseq = client->imexseq = 0;
+-                              client->mode = MOUSEDEV_EMUL_PS2;
+-                              client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
+-                              client->bufsiz = 3;
+-                              break;
+-
+-                      default:
+-                              client->bufsiz = 1;
+-                              break;
+-              }
++              mousedev_generate_response(client, c);
+-              client->buffer = client->bufsiz;
++              spin_unlock_irq(&client->packet_lock);
+       }
+       kill_fasync(&client->fasync, SIGIO, POLL_IN);
+-
+       wake_up_interruptible(&client->mousedev->wait);
+       return count;
+ }
+-static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
++static ssize_t mousedev_read(struct file *file, char __user *buffer,
++                           size_t count, loff_t *ppos)
+ {
+       struct mousedev_client *client = file->private_data;
++      struct mousedev *mousedev = client->mousedev;
++      signed char data[sizeof(client->ps2)];
+       int retval = 0;
+-      if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK))
++      if (!client->ready && !client->buffer && mousedev->exist &&
++          (file->f_flags & O_NONBLOCK))
+               return -EAGAIN;
+-      retval = wait_event_interruptible(client->mousedev->wait,
+-                                        !client->mousedev->exist || client->ready || client->buffer);
+-
++      retval = wait_event_interruptible(mousedev->wait,
++                      !mousedev->exist || client->ready || client->buffer);
+       if (retval)
+               return retval;
+-      if (!client->mousedev->exist)
++      if (!mousedev->exist)
+               return -ENODEV;
++      spin_lock_irq(&client->packet_lock);
++
+       if (!client->buffer && client->ready) {
+               mousedev_packet(client, client->ps2);
+               client->buffer = client->bufsiz;
+@@ -663,9 +751,12 @@ static ssize_t mousedev_read(struct file
+       if (count > client->buffer)
+               count = client->buffer;
++      memcpy(data, client->ps2 + client->bufsiz - client->buffer, count);
+       client->buffer -= count;
+-      if (copy_to_user(buffer, client->ps2 + client->bufsiz - client->buffer - count, count))
++      spin_unlock_irq(&client->packet_lock);
++
++      if (copy_to_user(buffer, data, count))
+               return -EFAULT;
+       return count;
+@@ -692,6 +783,60 @@ static const struct file_operations mous
+       .fasync =       mousedev_fasync,
+ };
++static int mousedev_install_chrdev(struct mousedev *mousedev)
++{
++      mousedev_table[mousedev->minor] = mousedev;
++      return 0;
++}
++
++static void mousedev_remove_chrdev(struct mousedev *mousedev)
++{
++      mutex_lock(&mousedev_table_mutex);
++      mousedev_table[mousedev->minor] = NULL;
++      mutex_unlock(&mousedev_table_mutex);
++}
++
++/*
++ * Mark device non-existent. This disables writes, ioctls and
++ * prevents new users from opening the device. Already posted
++ * blocking reads will stay, however new ones will fail.
++ */
++static void mousedev_mark_dead(struct mousedev *mousedev)
++{
++      mutex_lock(&mousedev->mutex);
++      mousedev->exist = 0;
++      mutex_unlock(&mousedev->mutex);
++}
++
++/*
++ * Wake up users waiting for IO so they can disconnect from
++ * dead device.
++ */
++static void mousedev_hangup(struct mousedev *mousedev)
++{
++      struct mousedev_client *client;
++
++      spin_lock(&mousedev->client_lock);
++      list_for_each_entry(client, &mousedev->client_list, node)
++              kill_fasync(&client->fasync, SIGIO, POLL_HUP);
++      spin_unlock(&mousedev->client_lock);
++
++      wake_up_interruptible(&mousedev->wait);
++}
++
++static void mousedev_cleanup(struct mousedev *mousedev)
++{
++      struct input_handle *handle = &mousedev->handle;
++
++      mousedev_mark_dead(mousedev);
++      mousedev_hangup(mousedev);
++      mousedev_remove_chrdev(mousedev);
++
++      /* mousedev is marked dead so no one else accesses mousedev->open */
++      if (mousedev->open)
++              input_close_device(handle);
++}
++
+ static struct mousedev *mousedev_create(struct input_dev *dev,
+                                       struct input_handler *handler,
+                                       int minor)
+@@ -707,6 +852,10 @@ static struct mousedev *mousedev_create(
+       INIT_LIST_HEAD(&mousedev->client_list);
+       INIT_LIST_HEAD(&mousedev->mixdev_node);
++      spin_lock_init(&mousedev->client_lock);
++      mutex_init(&mousedev->mutex);
++      lockdep_set_subclass(&mousedev->mutex,
++                           minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0);
+       init_waitqueue_head(&mousedev->wait);
+       if (minor == MOUSEDEV_MIX)
+@@ -731,14 +880,27 @@ static struct mousedev *mousedev_create(
+       mousedev->dev.release = mousedev_free;
+       device_initialize(&mousedev->dev);
+-      mousedev_table[minor] = mousedev;
++      if (minor != MOUSEDEV_MIX) {
++              error = input_register_handle(&mousedev->handle);
++              if (error)
++                      goto err_free_mousedev;
++      }
++
++      error = mousedev_install_chrdev(mousedev);
++      if (error)
++              goto err_unregister_handle;
+       error = device_add(&mousedev->dev);
+       if (error)
+-              goto err_free_mousedev;
++              goto err_cleanup_mousedev;
+       return mousedev;
++ err_cleanup_mousedev:
++      mousedev_cleanup(mousedev);
++ err_unregister_handle:
++      if (minor != MOUSEDEV_MIX)
++              input_unregister_handle(&mousedev->handle);
+  err_free_mousedev:
+       put_device(&mousedev->dev);
+  err_out:
+@@ -747,29 +909,64 @@ static struct mousedev *mousedev_create(
+ static void mousedev_destroy(struct mousedev *mousedev)
+ {
+-      struct mousedev_client *client;
+-
+       device_del(&mousedev->dev);
+-      mousedev->exist = 0;
++      mousedev_cleanup(mousedev);
++      if (mousedev->minor != MOUSEDEV_MIX)
++              input_unregister_handle(&mousedev->handle);
++      put_device(&mousedev->dev);
++}
+-      if (mousedev->open) {
+-              input_close_device(&mousedev->handle);
+-              list_for_each_entry(client, &mousedev->client_list, node)
+-                      kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+-              wake_up_interruptible(&mousedev->wait);
++static int mixdev_add_device(struct mousedev *mousedev)
++{
++      int retval;
++
++      retval = mutex_lock_interruptible(&mousedev_mix->mutex);
++      if (retval)
++              return retval;
++
++      if (mousedev_mix->open) {
++              retval = mousedev_open_device(mousedev);
++              if (retval)
++                      goto out;
++
++              mousedev->mixdev_open = 1;
+       }
++      get_device(&mousedev->dev);
++      list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
++
++ out:
++      mutex_unlock(&mousedev_mix->mutex);
++      return retval;
++}
++
++static void mixdev_remove_device(struct mousedev *mousedev)
++{
++      mutex_lock(&mousedev_mix->mutex);
++
++      if (mousedev->mixdev_open) {
++              mousedev->mixdev_open = 0;
++              mousedev_close_device(mousedev);
++      }
++
++      list_del_init(&mousedev->mixdev_node);
++      mutex_unlock(&mousedev_mix->mutex);
++
+       put_device(&mousedev->dev);
+ }
+-static int mousedev_connect(struct input_handler *handler, struct input_dev *dev,
++static int mousedev_connect(struct input_handler *handler,
++                          struct input_dev *dev,
+                           const struct input_device_id *id)
+ {
+       struct mousedev *mousedev;
+       int minor;
+       int error;
+-      for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
++      for (minor = 0; minor < MOUSEDEV_MINORS; minor++)
++              if (!mousedev_table[minor])
++                      break;
++
+       if (minor == MOUSEDEV_MINORS) {
+               printk(KERN_ERR "mousedev: no more free mousedev devices\n");
+               return -ENFILE;
+@@ -779,21 +976,13 @@ static int mousedev_connect(struct input
+       if (IS_ERR(mousedev))
+               return PTR_ERR(mousedev);
+-      error = input_register_handle(&mousedev->handle);
+-      if (error)
+-              goto err_delete_mousedev;
+-
+       error = mixdev_add_device(mousedev);
+-      if (error)
+-              goto err_unregister_handle;
++      if (error) {
++              mousedev_destroy(mousedev);
++              return error;
++      }
+       return 0;
+-
+- err_unregister_handle:
+-      input_unregister_handle(&mousedev->handle);
+- err_delete_mousedev:
+-      device_unregister(&mousedev->dev);
+-      return error;
+ }
+ static void mousedev_disconnect(struct input_handle *handle)
+@@ -801,33 +990,42 @@ static void mousedev_disconnect(struct i
+       struct mousedev *mousedev = handle->private;
+       mixdev_remove_device(mousedev);
+-      input_unregister_handle(handle);
+       mousedev_destroy(mousedev);
+ }
+ static const struct input_device_id mousedev_ids[] = {
+       {
+-              .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
++              .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++                              INPUT_DEVICE_ID_MATCH_KEYBIT |
++                              INPUT_DEVICE_ID_MATCH_RELBIT,
+               .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
+               .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
+               .relbit = { BIT(REL_X) | BIT(REL_Y) },
+-      },      /* A mouse like device, at least one button, two relative axes */
++      },      /* A mouse like device, at least one button,
++                 two relative axes */
+       {
+-              .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
++              .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++                              INPUT_DEVICE_ID_MATCH_RELBIT,
+               .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
+               .relbit = { BIT(REL_WHEEL) },
+       },      /* A separate scrollwheel */
+       {
+-              .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
++              .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++                              INPUT_DEVICE_ID_MATCH_KEYBIT |
++                              INPUT_DEVICE_ID_MATCH_ABSBIT,
+               .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
+               .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
+               .absbit = { BIT(ABS_X) | BIT(ABS_Y) },
+-      },      /* A tablet like device, at least touch detection, two absolute axes */
++      },      /* A tablet like device, at least touch detection,
++                 two absolute axes */
+       {
+-              .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
++              .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++                              INPUT_DEVICE_ID_MATCH_KEYBIT |
++                              INPUT_DEVICE_ID_MATCH_ABSBIT,
+               .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
+               .keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) },
+-              .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) },
++              .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) |
++                              BIT(ABS_TOOL_WIDTH) },
+       },      /* A touchpad */
+       { },    /* Terminating entry */
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:45 2008
+Message-Id: <20080206234445.034484097@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:53 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Dmitry Torokhov <dtor@mail.ru>,
+ Al Viro <viro@ZenIV.linux.org.uk>
+Subject: [patch 51/73] Input: joydev - implement proper locking
+Content-Disposition: inline; filename=input-joydev-implement-proper-locking.patch
+Content-Length: 28929
+Lines: 1039
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+patch b126207ccdfe492fbc339c18d4898b1b5353fc6b in mainline.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/joydev.c |  745 ++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 493 insertions(+), 252 deletions(-)
+
+--- a/drivers/input/joydev.c
++++ b/drivers/input/joydev.c
+@@ -43,6 +43,8 @@ struct joydev {
+       struct input_handle handle;
+       wait_queue_head_t wait;
+       struct list_head client_list;
++      spinlock_t client_lock; /* protects client_list */
++      struct mutex mutex;
+       struct device dev;
+       struct js_corr corr[ABS_MAX + 1];
+@@ -61,31 +63,61 @@ struct joydev_client {
+       int head;
+       int tail;
+       int startup;
++      spinlock_t buffer_lock; /* protects access to buffer, head and tail */
+       struct fasync_struct *fasync;
+       struct joydev *joydev;
+       struct list_head node;
+ };
+ static struct joydev *joydev_table[JOYDEV_MINORS];
++static DEFINE_MUTEX(joydev_table_mutex);
+ static int joydev_correct(int value, struct js_corr *corr)
+ {
+       switch (corr->type) {
+-              case JS_CORR_NONE:
+-                      break;
+-              case JS_CORR_BROKEN:
+-                      value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
+-                              ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
+-                              ((corr->coef[2] * (value - corr->coef[0])) >> 14);
+-                      break;
+-              default:
+-                      return 0;
++
++      case JS_CORR_NONE:
++              break;
++
++      case JS_CORR_BROKEN:
++              value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
++                      ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
++                      ((corr->coef[2] * (value - corr->coef[0])) >> 14);
++              break;
++
++      default:
++              return 0;
+       }
+       return value < -32767 ? -32767 : (value > 32767 ? 32767 : value);
+ }
+-static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
++static void joydev_pass_event(struct joydev_client *client,
++                            struct js_event *event)
++{
++      struct joydev *joydev = client->joydev;
++
++      /*
++       * IRQs already disabled, just acquire the lock
++       */
++      spin_lock(&client->buffer_lock);
++
++      client->buffer[client->head] = *event;
++
++      if (client->startup == joydev->nabs + joydev->nkey) {
++              client->head++;
++              client->head &= JOYDEV_BUFFER_SIZE - 1;
++              if (client->tail == client->head)
++                      client->startup = 0;
++      }
++
++      spin_unlock(&client->buffer_lock);
++
++      kill_fasync(&client->fasync, SIGIO, POLL_IN);
++}
++
++static void joydev_event(struct input_handle *handle,
++                       unsigned int type, unsigned int code, int value)
+ {
+       struct joydev *joydev = handle->private;
+       struct joydev_client *client;
+@@ -93,39 +125,32 @@ static void joydev_event(struct input_ha
+       switch (type) {
+-              case EV_KEY:
+-                      if (code < BTN_MISC || value == 2)
+-                              return;
+-                      event.type = JS_EVENT_BUTTON;
+-                      event.number = joydev->keymap[code - BTN_MISC];
+-                      event.value = value;
+-                      break;
+-
+-              case EV_ABS:
+-                      event.type = JS_EVENT_AXIS;
+-                      event.number = joydev->absmap[code];
+-                      event.value = joydev_correct(value, joydev->corr + event.number);
+-                      if (event.value == joydev->abs[event.number])
+-                              return;
+-                      joydev->abs[event.number] = event.value;
+-                      break;
++      case EV_KEY:
++              if (code < BTN_MISC || value == 2)
++                      return;
++              event.type = JS_EVENT_BUTTON;
++              event.number = joydev->keymap[code - BTN_MISC];
++              event.value = value;
++              break;
+-              default:
++      case EV_ABS:
++              event.type = JS_EVENT_AXIS;
++              event.number = joydev->absmap[code];
++              event.value = joydev_correct(value,
++                                      &joydev->corr[event.number]);
++              if (event.value == joydev->abs[event.number])
+                       return;
++              joydev->abs[event.number] = event.value;
++              break;
++
++      default:
++              return;
+       }
+       event.time = jiffies_to_msecs(jiffies);
+-      list_for_each_entry(client, &joydev->client_list, node) {
+-
+-              memcpy(client->buffer + client->head, &event, sizeof(struct js_event));
+-
+-              if (client->startup == joydev->nabs + joydev->nkey)
+-                      if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
+-                              client->startup = 0;
+-
+-              kill_fasync(&client->fasync, SIGIO, POLL_IN);
+-      }
++      list_for_each_entry_rcu(client, &joydev->client_list, node)
++              joydev_pass_event(client, &event);
+       wake_up_interruptible(&joydev->wait);
+ }
+@@ -144,23 +169,85 @@ static void joydev_free(struct device *d
+ {
+       struct joydev *joydev = container_of(dev, struct joydev, dev);
+-      joydev_table[joydev->minor] = NULL;
+       kfree(joydev);
+ }
++static void joydev_attach_client(struct joydev *joydev,
++                               struct joydev_client *client)
++{
++      spin_lock(&joydev->client_lock);
++      list_add_tail_rcu(&client->node, &joydev->client_list);
++      spin_unlock(&joydev->client_lock);
++      /*
++       * We don't use synchronize_rcu() here because read-side
++       * critical section is protected by a spinlock (dev->event_lock)
++       * instead of rcu_read_lock().
++       */
++      synchronize_sched();
++}
++
++static void joydev_detach_client(struct joydev *joydev,
++                               struct joydev_client *client)
++{
++      spin_lock(&joydev->client_lock);
++      list_del_rcu(&client->node);
++      spin_unlock(&joydev->client_lock);
++      synchronize_sched();
++}
++
++static int joydev_open_device(struct joydev *joydev)
++{
++      int retval;
++
++      retval = mutex_lock_interruptible(&joydev->mutex);
++      if (retval)
++              return retval;
++
++      if (!joydev->exist)
++              retval = -ENODEV;
++      else if (!joydev->open++)
++              retval = input_open_device(&joydev->handle);
++
++      mutex_unlock(&joydev->mutex);
++      return retval;
++}
++
++static void joydev_close_device(struct joydev *joydev)
++{
++      mutex_lock(&joydev->mutex);
++
++      if (joydev->exist && !--joydev->open)
++              input_close_device(&joydev->handle);
++
++      mutex_unlock(&joydev->mutex);
++}
++
++/*
++ * Wake up users waiting for IO so they can disconnect from
++ * dead device.
++ */
++static void joydev_hangup(struct joydev *joydev)
++{
++      struct joydev_client *client;
++
++      spin_lock(&joydev->client_lock);
++      list_for_each_entry(client, &joydev->client_list, node)
++              kill_fasync(&client->fasync, SIGIO, POLL_HUP);
++      spin_unlock(&joydev->client_lock);
++
++      wake_up_interruptible(&joydev->wait);
++}
++
+ static int joydev_release(struct inode *inode, struct file *file)
+ {
+       struct joydev_client *client = file->private_data;
+       struct joydev *joydev = client->joydev;
+       joydev_fasync(-1, file, 0);
+-
+-      list_del(&client->node);
++      joydev_detach_client(joydev, client);
+       kfree(client);
+-      if (!--joydev->open && joydev->exist)
+-              input_close_device(&joydev->handle);
+-
++      joydev_close_device(joydev);
+       put_device(&joydev->dev);
+       return 0;
+@@ -176,11 +263,16 @@ static int joydev_open(struct inode *ino
+       if (i >= JOYDEV_MINORS)
+               return -ENODEV;
++      error = mutex_lock_interruptible(&joydev_table_mutex);
++      if (error)
++              return error;
+       joydev = joydev_table[i];
+-      if (!joydev || !joydev->exist)
+-              return -ENODEV;
++      if (joydev)
++              get_device(&joydev->dev);
++      mutex_unlock(&joydev_table_mutex);
+-      get_device(&joydev->dev);
++      if (!joydev)
++              return -ENODEV;
+       client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
+       if (!client) {
+@@ -188,37 +280,129 @@ static int joydev_open(struct inode *ino
+               goto err_put_joydev;
+       }
++      spin_lock_init(&client->buffer_lock);
+       client->joydev = joydev;
+-      list_add_tail(&client->node, &joydev->client_list);
++      joydev_attach_client(joydev, client);
+-      if (!joydev->open++ && joydev->exist) {
+-              error = input_open_device(&joydev->handle);
+-              if (error)
+-                      goto err_free_client;
+-      }
++      error = joydev_open_device(joydev);
++      if (error)
++              goto err_free_client;
+       file->private_data = client;
+       return 0;
+  err_free_client:
+-      list_del(&client->node);
++      joydev_detach_client(joydev, client);
+       kfree(client);
+  err_put_joydev:
+       put_device(&joydev->dev);
+       return error;
+ }
+-static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
++static int joydev_generate_startup_event(struct joydev_client *client,
++                                       struct input_dev *input,
++                                       struct js_event *event)
+ {
+-      return -EINVAL;
++      struct joydev *joydev = client->joydev;
++      int have_event;
++
++      spin_lock_irq(&client->buffer_lock);
++
++      have_event = client->startup < joydev->nabs + joydev->nkey;
++
++      if (have_event) {
++
++              event->time = jiffies_to_msecs(jiffies);
++              if (client->startup < joydev->nkey) {
++                      event->type = JS_EVENT_BUTTON | JS_EVENT_INIT;
++                      event->number = client->startup;
++                      event->value = !!test_bit(joydev->keypam[event->number],
++                                                input->key);
++              } else {
++                      event->type = JS_EVENT_AXIS | JS_EVENT_INIT;
++                      event->number = client->startup - joydev->nkey;
++                      event->value = joydev->abs[event->number];
++              }
++              client->startup++;
++      }
++
++      spin_unlock_irq(&client->buffer_lock);
++
++      return have_event;
++}
++
++static int joydev_fetch_next_event(struct joydev_client *client,
++                                 struct js_event *event)
++{
++      int have_event;
++
++      spin_lock_irq(&client->buffer_lock);
++
++      have_event = client->head != client->tail;
++      if (have_event) {
++              *event = client->buffer[client->tail++];
++              client->tail &= JOYDEV_BUFFER_SIZE - 1;
++      }
++
++      spin_unlock_irq(&client->buffer_lock);
++
++      return have_event;
+ }
+-static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
++/*
++ * Old joystick interface
++ */
++static ssize_t joydev_0x_read(struct joydev_client *client,
++                            struct input_dev *input,
++                            char __user *buf)
++{
++      struct joydev *joydev = client->joydev;
++      struct JS_DATA_TYPE data;
++      int i;
++
++      spin_lock_irq(&input->event_lock);
++
++      /*
++       * Get device state
++       */
++      for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
++              data.buttons |=
++                      test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
++      data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
++      data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
++
++      /*
++       * Reset reader's event queue
++       */
++      spin_lock(&client->buffer_lock);
++      client->startup = 0;
++      client->tail = client->head;
++      spin_unlock(&client->buffer_lock);
++
++      spin_unlock_irq(&input->event_lock);
++
++      if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
++              return -EFAULT;
++
++      return sizeof(struct JS_DATA_TYPE);
++}
++
++static inline int joydev_data_pending(struct joydev_client *client)
++{
++      struct joydev *joydev = client->joydev;
++
++      return client->startup < joydev->nabs + joydev->nkey ||
++              client->head != client->tail;
++}
++
++static ssize_t joydev_read(struct file *file, char __user *buf,
++                         size_t count, loff_t *ppos)
+ {
+       struct joydev_client *client = file->private_data;
+       struct joydev *joydev = client->joydev;
+       struct input_dev *input = joydev->handle.dev;
+-      int retval = 0;
++      struct js_event event;
++      int retval;
+       if (!joydev->exist)
+               return -ENODEV;
+@@ -226,68 +410,35 @@ static ssize_t joydev_read(struct file *
+       if (count < sizeof(struct js_event))
+               return -EINVAL;
+-      if (count == sizeof(struct JS_DATA_TYPE)) {
+-
+-              struct JS_DATA_TYPE data;
+-              int i;
+-
+-              for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
+-                      data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
+-              data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
+-              data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
+-
+-              if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
+-                      return -EFAULT;
+-
+-              client->startup = 0;
+-              client->tail = client->head;
+-
+-              return sizeof(struct JS_DATA_TYPE);
+-      }
++      if (count == sizeof(struct JS_DATA_TYPE))
++              return joydev_0x_read(client, input, buf);
+-      if (client->startup == joydev->nabs + joydev->nkey &&
+-          client->head == client->tail && (file->f_flags & O_NONBLOCK))
++      if (!joydev_data_pending(client) && (file->f_flags & O_NONBLOCK))
+               return -EAGAIN;
+       retval = wait_event_interruptible(joydev->wait,
+-                                        !joydev->exist ||
+-                                        client->startup < joydev->nabs + joydev->nkey ||
+-                                        client->head != client->tail);
++                      !joydev->exist || joydev_data_pending(client));
+       if (retval)
+               return retval;
+       if (!joydev->exist)
+               return -ENODEV;
+-      while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
+-
+-              struct js_event event;
+-
+-              event.time = jiffies_to_msecs(jiffies);
+-
+-              if (client->startup < joydev->nkey) {
+-                      event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
+-                      event.number = client->startup;
+-                      event.value = !!test_bit(joydev->keypam[event.number], input->key);
+-              } else {
+-                      event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
+-                      event.number = client->startup - joydev->nkey;
+-                      event.value = joydev->abs[event.number];
+-              }
++      while (retval + sizeof(struct js_event) <= count &&
++             joydev_generate_startup_event(client, input, &event)) {
+               if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
+                       return -EFAULT;
+-              client->startup++;
+               retval += sizeof(struct js_event);
+       }
+-      while (client->head != client->tail && retval + sizeof(struct js_event) <= count) {
++      while (retval + sizeof(struct js_event) <= count &&
++             joydev_fetch_next_event(client, &event)) {
+-              if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event)))
++              if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
+                       return -EFAULT;
+-              client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
+               retval += sizeof(struct js_event);
+       }
+@@ -301,126 +452,144 @@ static unsigned int joydev_poll(struct f
+       struct joydev *joydev = client->joydev;
+       poll_wait(file, &joydev->wait, wait);
+-      return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ?
+-              (POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR));
++      return (joydev_data_pending(client) ? (POLLIN | POLLRDNORM) : 0) |
++              (joydev->exist ?  0 : (POLLHUP | POLLERR));
+ }
+-static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
++static int joydev_ioctl_common(struct joydev *joydev,
++                              unsigned int cmd, void __user *argp)
+ {
+       struct input_dev *dev = joydev->handle.dev;
+       int i, j;
+       switch (cmd) {
+-              case JS_SET_CAL:
+-                      return copy_from_user(&joydev->glue.JS_CORR, argp,
++      case JS_SET_CAL:
++              return copy_from_user(&joydev->glue.JS_CORR, argp,
+                               sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
+-              case JS_GET_CAL:
+-                      return copy_to_user(argp, &joydev->glue.JS_CORR,
++      case JS_GET_CAL:
++              return copy_to_user(argp, &joydev->glue.JS_CORR,
+                               sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
+-              case JS_SET_TIMEOUT:
+-                      return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
++      case JS_SET_TIMEOUT:
++              return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
+-              case JS_GET_TIMEOUT:
+-                      return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
++      case JS_GET_TIMEOUT:
++              return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
+-              case JSIOCGVERSION:
+-                      return put_user(JS_VERSION, (__u32 __user *) argp);
++      case JSIOCGVERSION:
++              return put_user(JS_VERSION, (__u32 __user *) argp);
+-              case JSIOCGAXES:
+-                      return put_user(joydev->nabs, (__u8 __user *) argp);
+-
+-              case JSIOCGBUTTONS:
+-                      return put_user(joydev->nkey, (__u8 __user *) argp);
+-
+-              case JSIOCSCORR:
+-                      if (copy_from_user(joydev->corr, argp,
+-                                    sizeof(joydev->corr[0]) * joydev->nabs))
+-                          return -EFAULT;
+-                      for (i = 0; i < joydev->nabs; i++) {
+-                              j = joydev->abspam[i];
+-                              joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
+-                      }
+-                      return 0;
+-
+-              case JSIOCGCORR:
+-                      return copy_to_user(argp, joydev->corr,
+-                                              sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
++      case JSIOCGAXES:
++              return put_user(joydev->nabs, (__u8 __user *) argp);
++
++      case JSIOCGBUTTONS:
++              return put_user(joydev->nkey, (__u8 __user *) argp);
++
++      case JSIOCSCORR:
++              if (copy_from_user(joydev->corr, argp,
++                            sizeof(joydev->corr[0]) * joydev->nabs))
++                  return -EFAULT;
++
++              for (i = 0; i < joydev->nabs; i++) {
++                      j = joydev->abspam[i];
++                      joydev->abs[i] = joydev_correct(dev->abs[j],
++                                                      &joydev->corr[i]);
++              }
++              return 0;
+-              case JSIOCSAXMAP:
+-                      if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
+-                              return -EFAULT;
+-                      for (i = 0; i < joydev->nabs; i++) {
+-                              if (joydev->abspam[i] > ABS_MAX)
+-                                      return -EINVAL;
+-                              joydev->absmap[joydev->abspam[i]] = i;
+-                      }
+-                      return 0;
+-
+-              case JSIOCGAXMAP:
+-                      return copy_to_user(argp, joydev->abspam,
+-                                              sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
++      case JSIOCGCORR:
++              return copy_to_user(argp, joydev->corr,
++                      sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
++
++      case JSIOCSAXMAP:
++              if (copy_from_user(joydev->abspam, argp,
++                                 sizeof(__u8) * (ABS_MAX + 1)))
++                      return -EFAULT;
++
++              for (i = 0; i < joydev->nabs; i++) {
++                      if (joydev->abspam[i] > ABS_MAX)
++                              return -EINVAL;
++                      joydev->absmap[joydev->abspam[i]] = i;
++              }
++              return 0;
++
++      case JSIOCGAXMAP:
++              return copy_to_user(argp, joydev->abspam,
++                      sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
++
++      case JSIOCSBTNMAP:
++              if (copy_from_user(joydev->keypam, argp,
++                                 sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
++                      return -EFAULT;
++
++              for (i = 0; i < joydev->nkey; i++) {
++                      if (joydev->keypam[i] > KEY_MAX ||
++                          joydev->keypam[i] < BTN_MISC)
++                              return -EINVAL;
++                      joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
++              }
+-              case JSIOCSBTNMAP:
+-                      if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
++              return 0;
++
++      case JSIOCGBTNMAP:
++              return copy_to_user(argp, joydev->keypam,
++                      sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
++
++      default:
++              if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) {
++                      int len;
++                      if (!dev->name)
++                              return 0;
++                      len = strlen(dev->name) + 1;
++                      if (len > _IOC_SIZE(cmd))
++                              len = _IOC_SIZE(cmd);
++                      if (copy_to_user(argp, dev->name, len))
+                               return -EFAULT;
+-                      for (i = 0; i < joydev->nkey; i++) {
+-                              if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC)
+-                                      return -EINVAL;
+-                              joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
+-                      }
+-                      return 0;
+-
+-              case JSIOCGBTNMAP:
+-                      return copy_to_user(argp, joydev->keypam,
+-                                              sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
+-
+-              default:
+-                      if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
+-                              int len;
+-                              if (!dev->name)
+-                                      return 0;
+-                              len = strlen(dev->name) + 1;
+-                              if (len > _IOC_SIZE(cmd))
+-                                      len = _IOC_SIZE(cmd);
+-                              if (copy_to_user(argp, dev->name, len))
+-                                      return -EFAULT;
+-                              return len;
+-                      }
++                      return len;
++              }
+       }
+       return -EINVAL;
+ }
+ #ifdef CONFIG_COMPAT
+-static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++static long joydev_compat_ioctl(struct file *file,
++                              unsigned int cmd, unsigned long arg)
+ {
+       struct joydev_client *client = file->private_data;
+       struct joydev *joydev = client->joydev;
+       void __user *argp = (void __user *)arg;
+       s32 tmp32;
+       struct JS_DATA_SAVE_TYPE_32 ds32;
+-      int err;
++      int retval;
+-      if (!joydev->exist)
+-              return -ENODEV;
++      retval = mutex_lock_interruptible(&joydev->mutex);
++      if (retval)
++              return retval;
++
++      if (!joydev->exist) {
++              retval = -ENODEV;
++              goto out;
++      }
++
++      switch (cmd) {
+-      switch(cmd) {
+       case JS_SET_TIMELIMIT:
+-              err = get_user(tmp32, (s32 __user *) arg);
+-              if (err == 0)
++              retval = get_user(tmp32, (s32 __user *) arg);
++              if (retval == 0)
+                       joydev->glue.JS_TIMELIMIT = tmp32;
+               break;
++
+       case JS_GET_TIMELIMIT:
+               tmp32 = joydev->glue.JS_TIMELIMIT;
+-              err = put_user(tmp32, (s32 __user *) arg);
++              retval = put_user(tmp32, (s32 __user *) arg);
+               break;
+       case JS_SET_ALL:
+-              err = copy_from_user(&ds32, argp,
+-                                   sizeof(ds32)) ? -EFAULT : 0;
+-              if (err == 0) {
++              retval = copy_from_user(&ds32, argp,
++                                      sizeof(ds32)) ? -EFAULT : 0;
++              if (retval == 0) {
+                       joydev->glue.JS_TIMEOUT    = ds32.JS_TIMEOUT;
+                       joydev->glue.BUSY          = ds32.BUSY;
+                       joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
+@@ -438,55 +607,119 @@ static long joydev_compat_ioctl(struct f
+               ds32.JS_SAVE       = joydev->glue.JS_SAVE;
+               ds32.JS_CORR       = joydev->glue.JS_CORR;
+-              err = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
++              retval = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
+               break;
+       default:
+-              err = joydev_ioctl_common(joydev, cmd, argp);
++              retval = joydev_ioctl_common(joydev, cmd, argp);
++              break;
+       }
+-      return err;
++
++ out:
++      mutex_unlock(&joydev->mutex);
++      return retval;
+ }
+ #endif /* CONFIG_COMPAT */
+-static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++static long joydev_ioctl(struct file *file,
++                       unsigned int cmd, unsigned long arg)
+ {
+       struct joydev_client *client = file->private_data;
+       struct joydev *joydev = client->joydev;
+       void __user *argp = (void __user *)arg;
++      int retval;
+-      if (!joydev->exist)
+-              return -ENODEV;
++      retval = mutex_lock_interruptible(&joydev->mutex);
++      if (retval)
++              return retval;
++
++      if (!joydev->exist) {
++              retval = -ENODEV;
++              goto out;
++      }
++
++      switch (cmd) {
++
++      case JS_SET_TIMELIMIT:
++              retval = get_user(joydev->glue.JS_TIMELIMIT,
++                                (long __user *) arg);
++              break;
++
++      case JS_GET_TIMELIMIT:
++              retval = put_user(joydev->glue.JS_TIMELIMIT,
++                                (long __user *) arg);
++              break;
++
++      case JS_SET_ALL:
++              retval = copy_from_user(&joydev->glue, argp,
++                                      sizeof(joydev->glue)) ? -EFAULT: 0;
++              break;
+-      switch(cmd) {
+-              case JS_SET_TIMELIMIT:
+-                      return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+-              case JS_GET_TIMELIMIT:
+-                      return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+-              case JS_SET_ALL:
+-                      return copy_from_user(&joydev->glue, argp,
+-                                              sizeof(joydev->glue)) ? -EFAULT : 0;
+-              case JS_GET_ALL:
+-                      return copy_to_user(argp, &joydev->glue,
+-                                              sizeof(joydev->glue)) ? -EFAULT : 0;
+-              default:
+-                      return joydev_ioctl_common(joydev, cmd, argp);
++      case JS_GET_ALL:
++              retval = copy_to_user(argp, &joydev->glue,
++                                    sizeof(joydev->glue)) ? -EFAULT : 0;
++              break;
++
++      default:
++              retval = joydev_ioctl_common(joydev, cmd, argp);
++              break;
+       }
++ out:
++      mutex_unlock(&joydev->mutex);
++      return retval;
+ }
+ static const struct file_operations joydev_fops = {
+-      .owner =        THIS_MODULE,
+-      .read =         joydev_read,
+-      .write =        joydev_write,
+-      .poll =         joydev_poll,
+-      .open =         joydev_open,
+-      .release =      joydev_release,
+-      .ioctl =        joydev_ioctl,
++      .owner          = THIS_MODULE,
++      .read           = joydev_read,
++      .poll           = joydev_poll,
++      .open           = joydev_open,
++      .release        = joydev_release,
++      .unlocked_ioctl = joydev_ioctl,
+ #ifdef CONFIG_COMPAT
+-      .compat_ioctl = joydev_compat_ioctl,
++      .compat_ioctl   = joydev_compat_ioctl,
+ #endif
+-      .fasync =       joydev_fasync,
++      .fasync         = joydev_fasync,
+ };
++static int joydev_install_chrdev(struct joydev *joydev)
++{
++      joydev_table[joydev->minor] = joydev;
++      return 0;
++}
++
++static void joydev_remove_chrdev(struct joydev *joydev)
++{
++      mutex_lock(&joydev_table_mutex);
++      joydev_table[joydev->minor] = NULL;
++      mutex_unlock(&joydev_table_mutex);
++}
++
++/*
++ * Mark device non-existant. This disables writes, ioctls and
++ * prevents new users from opening the device. Already posted
++ * blocking reads will stay, however new ones will fail.
++ */
++static void joydev_mark_dead(struct joydev *joydev)
++{
++      mutex_lock(&joydev->mutex);
++      joydev->exist = 0;
++      mutex_unlock(&joydev->mutex);
++}
++
++static void joydev_cleanup(struct joydev *joydev)
++{
++      struct input_handle *handle = &joydev->handle;
++
++      joydev_mark_dead(joydev);
++      joydev_hangup(joydev);
++      joydev_remove_chrdev(joydev);
++
++      /* joydev is marked dead so noone else accesses joydev->open */
++      if (joydev->open)
++              input_close_device(handle);
++}
++
+ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
+                         const struct input_device_id *id)
+ {
+@@ -494,7 +727,10 @@ static int joydev_connect(struct input_h
+       int i, j, t, minor;
+       int error;
+-      for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
++      for (minor = 0; minor < JOYDEV_MINORS; minor++)
++              if (!joydev_table[minor])
++                      break;
++
+       if (minor == JOYDEV_MINORS) {
+               printk(KERN_ERR "joydev: no more free joydev devices\n");
+               return -ENFILE;
+@@ -505,15 +741,19 @@ static int joydev_connect(struct input_h
+               return -ENOMEM;
+       INIT_LIST_HEAD(&joydev->client_list);
++      spin_lock_init(&joydev->client_lock);
++      mutex_init(&joydev->mutex);
+       init_waitqueue_head(&joydev->wait);
++      snprintf(joydev->name, sizeof(joydev->name), "js%d", minor);
++      joydev->exist = 1;
+       joydev->minor = minor;
++
+       joydev->exist = 1;
+       joydev->handle.dev = dev;
+       joydev->handle.name = joydev->name;
+       joydev->handle.handler = handler;
+       joydev->handle.private = joydev;
+-      snprintf(joydev->name, sizeof(joydev->name), "js%d", minor);
+       for (i = 0; i < ABS_MAX + 1; i++)
+               if (test_bit(i, dev->absbit)) {
+@@ -545,67 +785,65 @@ static int joydev_connect(struct input_h
+               }
+               joydev->corr[i].type = JS_CORR_BROKEN;
+               joydev->corr[i].prec = dev->absfuzz[j];
+-              joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
+-              joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
+-              if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j])))
+-                      continue;
+-              joydev->corr[i].coef[2] = (1 << 29) / t;
+-              joydev->corr[i].coef[3] = (1 << 29) / t;
++              joydev->corr[i].coef[0] =
++                      (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
++              joydev->corr[i].coef[1] =
++                      (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
++
++              t = (dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j];
++              if (t) {
++                      joydev->corr[i].coef[2] = (1 << 29) / t;
++                      joydev->corr[i].coef[3] = (1 << 29) / t;
+-              joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
++                      joydev->abs[i] = joydev_correct(dev->abs[j],
++                                                      joydev->corr + i);
++              }
+       }
+-      snprintf(joydev->dev.bus_id, sizeof(joydev->dev.bus_id),
+-               "js%d", minor);
++      strlcpy(joydev->dev.bus_id, joydev->name, sizeof(joydev->dev.bus_id));
++      joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
+       joydev->dev.class = &input_class;
+       joydev->dev.parent = &dev->dev;
+-      joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
+       joydev->dev.release = joydev_free;
+       device_initialize(&joydev->dev);
+-      joydev_table[minor] = joydev;
+-
+-      error = device_add(&joydev->dev);
++      error = input_register_handle(&joydev->handle);
+       if (error)
+               goto err_free_joydev;
+-      error = input_register_handle(&joydev->handle);
++      error = joydev_install_chrdev(joydev);
+       if (error)
+-              goto err_delete_joydev;
++              goto err_unregister_handle;
++
++      error = device_add(&joydev->dev);
++      if (error)
++              goto err_cleanup_joydev;
+       return 0;
+- err_delete_joydev:
+-      device_del(&joydev->dev);
++ err_cleanup_joydev:
++      joydev_cleanup(joydev);
++ err_unregister_handle:
++      input_unregister_handle(&joydev->handle);
+  err_free_joydev:
+       put_device(&joydev->dev);
+       return error;
+ }
+-
+ static void joydev_disconnect(struct input_handle *handle)
+ {
+       struct joydev *joydev = handle->private;
+-      struct joydev_client *client;
+-      input_unregister_handle(handle);
+       device_del(&joydev->dev);
+-
+-      joydev->exist = 0;
+-
+-      if (joydev->open) {
+-              input_close_device(handle);
+-              list_for_each_entry(client, &joydev->client_list, node)
+-                      kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+-              wake_up_interruptible(&joydev->wait);
+-      }
+-
++      joydev_cleanup(joydev);
++      input_unregister_handle(handle);
+       put_device(&joydev->dev);
+ }
+ static const struct input_device_id joydev_blacklist[] = {
+       {
+-              .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
++              .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++                              INPUT_DEVICE_ID_MATCH_KEYBIT,
+               .evbit = { BIT(EV_KEY) },
+               .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
+       },      /* Avoid itouchpads, touchscreens and tablets */
+@@ -614,17 +852,20 @@ static const struct input_device_id joyd
+ static const struct input_device_id joydev_ids[] = {
+       {
+-              .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
++              .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++                              INPUT_DEVICE_ID_MATCH_ABSBIT,
+               .evbit = { BIT(EV_ABS) },
+               .absbit = { BIT(ABS_X) },
+       },
+       {
+-              .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
++              .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++                              INPUT_DEVICE_ID_MATCH_ABSBIT,
+               .evbit = { BIT(EV_ABS) },
+               .absbit = { BIT(ABS_WHEEL) },
+       },
+       {
+-              .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
++              .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++                              INPUT_DEVICE_ID_MATCH_ABSBIT,
+               .evbit = { BIT(EV_ABS) },
+               .absbit = { BIT(ABS_THROTTLE) },
+       },
+@@ -634,14 +875,14 @@ static const struct input_device_id joyd
+ MODULE_DEVICE_TABLE(input, joydev_ids);
+ static struct input_handler joydev_handler = {
+-      .event =        joydev_event,
+-      .connect =      joydev_connect,
+-      .disconnect =   joydev_disconnect,
+-      .fops =         &joydev_fops,
+-      .minor =        JOYDEV_MINOR_BASE,
+-      .name =         "joydev",
+-      .id_table =     joydev_ids,
+-      .blacklist =    joydev_blacklist,
++      .event          = joydev_event,
++      .connect        = joydev_connect,
++      .disconnect     = joydev_disconnect,
++      .fops           = &joydev_fops,
++      .minor          = JOYDEV_MINOR_BASE,
++      .name           = "joydev",
++      .id_table       = joydev_ids,
++      .blacklist      = joydev_blacklist,
+ };
+ static int __init joydev_init(void)
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:45 2008
+Message-Id: <20080206234445.258220795@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:54 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Dmitry Torokhov <dtor@mail.ru>,
+ Al Viro <viro@ZenIV.linux.org.uk>
+Subject: [patch 52/73] Input: tsdev - implement proper locking
+Content-Disposition: inline; filename=input-tsdev-implement-proper-locking.patch
+Content-Length: 16167
+Lines: 622
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+patch b9d2d110b10f7b4788d0fdd328cf57e34b767817 in mainline.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/tsdev.c |  392 +++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 278 insertions(+), 114 deletions(-)
+
+--- a/drivers/input/tsdev.c
++++ b/drivers/input/tsdev.c
+@@ -112,6 +112,8 @@ struct tsdev {
+       struct input_handle handle;
+       wait_queue_head_t wait;
+       struct list_head client_list;
++      spinlock_t client_lock; /* protects client_list */
++      struct mutex mutex;
+       struct device dev;
+       int x, y, pressure;
+@@ -122,8 +124,9 @@ struct tsdev_client {
+       struct fasync_struct *fasync;
+       struct list_head node;
+       struct tsdev *tsdev;
++      struct ts_event buffer[TSDEV_BUFFER_SIZE];
+       int head, tail;
+-      struct ts_event event[TSDEV_BUFFER_SIZE];
++      spinlock_t buffer_lock; /* protects access to buffer, head and tail */
+       int raw;
+ };
+@@ -137,6 +140,7 @@ struct tsdev_client {
+ #define TS_SET_CAL    _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
+ static struct tsdev *tsdev_table[TSDEV_MINORS/2];
++static DEFINE_MUTEX(tsdev_table_mutex);
+ static int tsdev_fasync(int fd, struct file *file, int on)
+ {
+@@ -144,9 +148,91 @@ static int tsdev_fasync(int fd, struct f
+       int retval;
+       retval = fasync_helper(fd, file, on, &client->fasync);
++
+       return retval < 0 ? retval : 0;
+ }
++static void tsdev_free(struct device *dev)
++{
++      struct tsdev *tsdev = container_of(dev, struct tsdev, dev);
++
++      kfree(tsdev);
++}
++
++static void tsdev_attach_client(struct tsdev *tsdev, struct tsdev_client *client)
++{
++      spin_lock(&tsdev->client_lock);
++      list_add_tail_rcu(&client->node, &tsdev->client_list);
++      spin_unlock(&tsdev->client_lock);
++      synchronize_sched();
++}
++
++static void tsdev_detach_client(struct tsdev *tsdev, struct tsdev_client *client)
++{
++      spin_lock(&tsdev->client_lock);
++      list_del_rcu(&client->node);
++      spin_unlock(&tsdev->client_lock);
++      synchronize_sched();
++}
++
++static int tsdev_open_device(struct tsdev *tsdev)
++{
++      int retval;
++
++      retval = mutex_lock_interruptible(&tsdev->mutex);
++      if (retval)
++              return retval;
++
++      if (!tsdev->exist)
++              retval = -ENODEV;
++      else if (!tsdev->open++)
++              retval = input_open_device(&tsdev->handle);
++
++      mutex_unlock(&tsdev->mutex);
++      return retval;
++}
++
++static void tsdev_close_device(struct tsdev *tsdev)
++{
++      mutex_lock(&tsdev->mutex);
++
++      if (tsdev->exist && !--tsdev->open)
++              input_close_device(&tsdev->handle);
++
++      mutex_unlock(&tsdev->mutex);
++}
++
++/*
++ * Wake up users waiting for IO so they can disconnect from
++ * dead device.
++ */
++static void tsdev_hangup(struct tsdev *tsdev)
++{
++      struct tsdev_client *client;
++
++      spin_lock(&tsdev->client_lock);
++      list_for_each_entry(client, &tsdev->client_list, node)
++              kill_fasync(&client->fasync, SIGIO, POLL_HUP);
++      spin_unlock(&tsdev->client_lock);
++
++      wake_up_interruptible(&tsdev->wait);
++}
++
++static int tsdev_release(struct inode *inode, struct file *file)
++{
++      struct tsdev_client *client = file->private_data;
++      struct tsdev *tsdev = client->tsdev;
++
++      tsdev_fasync(-1, file, 0);
++      tsdev_detach_client(tsdev, client);
++      kfree(client);
++
++      tsdev_close_device(tsdev);
++      put_device(&tsdev->dev);
++
++      return 0;
++}
++
+ static int tsdev_open(struct inode *inode, struct file *file)
+ {
+       int i = iminor(inode) - TSDEV_MINOR_BASE;
+@@ -161,11 +247,16 @@ static int tsdev_open(struct inode *inod
+       if (i >= TSDEV_MINORS)
+               return -ENODEV;
++      error = mutex_lock_interruptible(&tsdev_table_mutex);
++      if (error)
++              return error;
+       tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
+-      if (!tsdev || !tsdev->exist)
+-              return -ENODEV;
++      if (tsdev)
++              get_device(&tsdev->dev);
++      mutex_unlock(&tsdev_table_mutex);
+-      get_device(&tsdev->dev);
++      if (!tsdev)
++              return -ENODEV;
+       client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);
+       if (!client) {
+@@ -173,51 +264,42 @@ static int tsdev_open(struct inode *inod
+               goto err_put_tsdev;
+       }
++      spin_lock_init(&client->buffer_lock);
+       client->tsdev = tsdev;
+-      client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0;
+-      list_add_tail(&client->node, &tsdev->client_list);
++      client->raw = i >= TSDEV_MINORS / 2;
++      tsdev_attach_client(tsdev, client);
+-      if (!tsdev->open++ && tsdev->exist) {
+-              error = input_open_device(&tsdev->handle);
+-              if (error)
+-                      goto err_free_client;
+-      }
++      error = tsdev_open_device(tsdev);
++      if (error)
++              goto err_free_client;
+       file->private_data = client;
+       return 0;
+  err_free_client:
+-      list_del(&client->node);
++      tsdev_detach_client(tsdev, client);
+       kfree(client);
+  err_put_tsdev:
+       put_device(&tsdev->dev);
+       return error;
+ }
+-static void tsdev_free(struct device *dev)
++static int tsdev_fetch_next_event(struct tsdev_client *client,
++                                struct ts_event *event)
+ {
+-      struct tsdev *tsdev = container_of(dev, struct tsdev, dev);
++      int have_event;
+-      tsdev_table[tsdev->minor] = NULL;
+-      kfree(tsdev);
+-}
+-
+-static int tsdev_release(struct inode *inode, struct file *file)
+-{
+-      struct tsdev_client *client = file->private_data;
+-      struct tsdev *tsdev = client->tsdev;
+-
+-      tsdev_fasync(-1, file, 0);
++      spin_lock_irq(&client->buffer_lock);
+-      list_del(&client->node);
+-      kfree(client);
+-
+-      if (!--tsdev->open && tsdev->exist)
+-              input_close_device(&tsdev->handle);
++      have_event = client->head != client->tail;
++      if (have_event) {
++              *event = client->buffer[client->tail++];
++              client->tail &= TSDEV_BUFFER_SIZE - 1;
++      }
+-      put_device(&tsdev->dev);
++      spin_unlock_irq(&client->buffer_lock);
+-      return 0;
++      return have_event;
+ }
+ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
+@@ -225,9 +307,11 @@ static ssize_t tsdev_read(struct file *f
+ {
+       struct tsdev_client *client = file->private_data;
+       struct tsdev *tsdev = client->tsdev;
+-      int retval = 0;
++      struct ts_event event;
++      int retval;
+-      if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK))
++      if (client->head == client->tail && tsdev->exist &&
++          (file->f_flags & O_NONBLOCK))
+               return -EAGAIN;
+       retval = wait_event_interruptible(tsdev->wait,
+@@ -238,13 +322,14 @@ static ssize_t tsdev_read(struct file *f
+       if (!tsdev->exist)
+               return -ENODEV;
+-      while (client->head != client->tail &&
+-             retval + sizeof (struct ts_event) <= count) {
+-              if (copy_to_user (buffer + retval, client->event + client->tail,
+-                                sizeof (struct ts_event)))
++      while (retval + sizeof(struct ts_event) <= count &&
++             tsdev_fetch_next_event(client, &event)) {
++
++              if (copy_to_user(buffer + retval, &event,
++                               sizeof(struct ts_event)))
+                       return -EFAULT;
+-              client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
+-              retval += sizeof (struct ts_event);
++
++              retval += sizeof(struct ts_event);
+       }
+       return retval;
+@@ -261,14 +346,23 @@ static unsigned int tsdev_poll(struct fi
+               (tsdev->exist ? 0 : (POLLHUP | POLLERR));
+ }
+-static int tsdev_ioctl(struct inode *inode, struct file *file,
+-                     unsigned int cmd, unsigned long arg)
++static long tsdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+       struct tsdev_client *client = file->private_data;
+       struct tsdev *tsdev = client->tsdev;
+       int retval = 0;
++      retval = mutex_lock_interruptible(&tsdev->mutex);
++      if (retval)
++              return retval;
++
++      if (!tsdev->exist) {
++              retval = -ENODEV;
++              goto out;
++      }
++
+       switch (cmd) {
++
+       case TS_GET_CAL:
+               if (copy_to_user((void __user *)arg, &tsdev->cal,
+                                sizeof (struct ts_calibration)))
+@@ -277,7 +371,7 @@ static int tsdev_ioctl(struct inode *ino
+       case TS_SET_CAL:
+               if (copy_from_user(&tsdev->cal, (void __user *)arg,
+-                                 sizeof (struct ts_calibration)))
++                                 sizeof(struct ts_calibration)))
+                       retval = -EFAULT;
+               break;
+@@ -286,29 +380,79 @@ static int tsdev_ioctl(struct inode *ino
+               break;
+       }
++ out:
++      mutex_unlock(&tsdev->mutex);
+       return retval;
+ }
+ static const struct file_operations tsdev_fops = {
+-      .owner =        THIS_MODULE,
+-      .open =         tsdev_open,
+-      .release =      tsdev_release,
+-      .read =         tsdev_read,
+-      .poll =         tsdev_poll,
+-      .fasync =       tsdev_fasync,
+-      .ioctl =        tsdev_ioctl,
++      .owner          = THIS_MODULE,
++      .open           = tsdev_open,
++      .release        = tsdev_release,
++      .read           = tsdev_read,
++      .poll           = tsdev_poll,
++      .fasync         = tsdev_fasync,
++      .unlocked_ioctl = tsdev_ioctl,
+ };
++static void tsdev_pass_event(struct tsdev *tsdev, struct tsdev_client *client,
++                           int x, int y, int pressure, int millisecs)
++{
++      struct ts_event *event;
++      int tmp;
++
++      /* Interrupts are already disabled, just acquire the lock */
++      spin_lock(&client->buffer_lock);
++
++      event = &client->buffer[client->head++];
++      client->head &= TSDEV_BUFFER_SIZE - 1;
++
++      /* Calibration */
++      if (!client->raw) {
++              x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
++              y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
++              if (tsdev->cal.xyswap) {
++                      tmp = x; x = y; y = tmp;
++              }
++      }
++
++      event->millisecs = millisecs;
++      event->x = x;
++      event->y = y;
++      event->pressure = pressure;
++
++      spin_unlock(&client->buffer_lock);
++
++      kill_fasync(&client->fasync, SIGIO, POLL_IN);
++}
++
++static void tsdev_distribute_event(struct tsdev *tsdev)
++{
++      struct tsdev_client *client;
++      struct timeval time;
++      int millisecs;
++
++      do_gettimeofday(&time);
++      millisecs = time.tv_usec / 1000;
++
++      list_for_each_entry_rcu(client, &tsdev->client_list, node)
++              tsdev_pass_event(tsdev, client,
++                               tsdev->x, tsdev->y,
++                               tsdev->pressure, millisecs);
++}
++
+ static void tsdev_event(struct input_handle *handle, unsigned int type,
+                       unsigned int code, int value)
+ {
+       struct tsdev *tsdev = handle->private;
+-      struct tsdev_client *client;
+-      struct timeval time;
++      struct input_dev *dev = handle->dev;
++      int wake_up_readers = 0;
+       switch (type) {
++
+       case EV_ABS:
+               switch (code) {
++
+               case ABS_X:
+                       tsdev->x = value;
+                       break;
+@@ -318,9 +462,9 @@ static void tsdev_event(struct input_han
+                       break;
+               case ABS_PRESSURE:
+-                      if (value > handle->dev->absmax[ABS_PRESSURE])
+-                              value = handle->dev->absmax[ABS_PRESSURE];
+-                      value -= handle->dev->absmin[ABS_PRESSURE];
++                      if (value > dev->absmax[ABS_PRESSURE])
++                              value = dev->absmax[ABS_PRESSURE];
++                      value -= dev->absmin[ABS_PRESSURE];
+                       if (value < 0)
+                               value = 0;
+                       tsdev->pressure = value;
+@@ -330,6 +474,7 @@ static void tsdev_event(struct input_han
+       case EV_REL:
+               switch (code) {
++
+               case REL_X:
+                       tsdev->x += value;
+                       if (tsdev->x < 0)
+@@ -351,6 +496,7 @@ static void tsdev_event(struct input_han
+       case EV_KEY:
+               if (code == BTN_TOUCH || code == BTN_MOUSE) {
+                       switch (value) {
++
+                       case 0:
+                               tsdev->pressure = 0;
+                               break;
+@@ -362,49 +508,71 @@ static void tsdev_event(struct input_han
+                       }
+               }
+               break;
++
++      case EV_SYN:
++              if (code == SYN_REPORT) {
++                      tsdev_distribute_event(tsdev);
++                      wake_up_readers = 1;
++              }
++              break;
+       }
+-      if (type != EV_SYN || code != SYN_REPORT)
+-              return;
++      if (wake_up_readers)
++              wake_up_interruptible(&tsdev->wait);
++}
+-      list_for_each_entry(client, &tsdev->client_list, node) {
+-              int x, y, tmp;
++static int tsdev_install_chrdev(struct tsdev *tsdev)
++{
++      tsdev_table[tsdev->minor] = tsdev;
++      return 0;
++}
+-              do_gettimeofday(&time);
+-              client->event[client->head].millisecs = time.tv_usec / 1000;
+-              client->event[client->head].pressure = tsdev->pressure;
+-
+-              x = tsdev->x;
+-              y = tsdev->y;
+-
+-              /* Calibration */
+-              if (!client->raw) {
+-                      x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
+-                      y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
+-                      if (tsdev->cal.xyswap) {
+-                              tmp = x; x = y; y = tmp;
+-                      }
+-              }
++static void tsdev_remove_chrdev(struct tsdev *tsdev)
++{
++      mutex_lock(&tsdev_table_mutex);
++      tsdev_table[tsdev->minor] = NULL;
++      mutex_unlock(&tsdev_table_mutex);
++}
+-              client->event[client->head].x = x;
+-              client->event[client->head].y = y;
+-              client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1);
+-              kill_fasync(&client->fasync, SIGIO, POLL_IN);
+-      }
+-      wake_up_interruptible(&tsdev->wait);
++/*
++ * Mark device non-existant. This disables writes, ioctls and
++ * prevents new users from opening the device. Already posted
++ * blocking reads will stay, however new ones will fail.
++ */
++static void tsdev_mark_dead(struct tsdev *tsdev)
++{
++      mutex_lock(&tsdev->mutex);
++      tsdev->exist = 0;
++      mutex_unlock(&tsdev->mutex);
++}
++
++static void tsdev_cleanup(struct tsdev *tsdev)
++{
++      struct input_handle *handle = &tsdev->handle;
++
++      tsdev_mark_dead(tsdev);
++      tsdev_hangup(tsdev);
++      tsdev_remove_chrdev(tsdev);
++
++      /* tsdev is marked dead so noone else accesses tsdev->open */
++      if (tsdev->open)
++              input_close_device(handle);
+ }
+ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
+                        const struct input_device_id *id)
+ {
+       struct tsdev *tsdev;
+-      int minor, delta;
++      int delta;
++      int minor;
+       int error;
+-      for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
+-      if (minor >= TSDEV_MINORS / 2) {
+-              printk(KERN_ERR
+-                     "tsdev: You have way too many touchscreens\n");
++      for (minor = 0; minor < TSDEV_MINORS / 2; minor++)
++              if (!tsdev_table[minor])
++                      break;
++
++      if (minor == TSDEV_MINORS) {
++              printk(KERN_ERR "tsdev: no more free tsdev devices\n");
+               return -ENFILE;
+       }
+@@ -413,15 +581,18 @@ static int tsdev_connect(struct input_ha
+               return -ENOMEM;
+       INIT_LIST_HEAD(&tsdev->client_list);
++      spin_lock_init(&tsdev->client_lock);
++      mutex_init(&tsdev->mutex);
+       init_waitqueue_head(&tsdev->wait);
++      snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor);
+       tsdev->exist = 1;
+       tsdev->minor = minor;
++
+       tsdev->handle.dev = dev;
+       tsdev->handle.name = tsdev->name;
+       tsdev->handle.handler = handler;
+       tsdev->handle.private = tsdev;
+-      snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor);
+       /* Precompute the rough calibration matrix */
+       delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
+@@ -436,28 +607,31 @@ static int tsdev_connect(struct input_ha
+       tsdev->cal.yscale = (yres << 8) / delta;
+       tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);
+-      snprintf(tsdev->dev.bus_id, sizeof(tsdev->dev.bus_id),
+-               "ts%d", minor);
++      strlcpy(tsdev->dev.bus_id, tsdev->name, sizeof(tsdev->dev.bus_id));
++      tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor);
+       tsdev->dev.class = &input_class;
+       tsdev->dev.parent = &dev->dev;
+-      tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor);
+       tsdev->dev.release = tsdev_free;
+       device_initialize(&tsdev->dev);
+-      tsdev_table[minor] = tsdev;
+-
+-      error = device_add(&tsdev->dev);
++      error = input_register_handle(&tsdev->handle);
+       if (error)
+               goto err_free_tsdev;
+-      error = input_register_handle(&tsdev->handle);
++      error = tsdev_install_chrdev(tsdev);
+       if (error)
+-              goto err_delete_tsdev;
++              goto err_unregister_handle;
++
++      error = device_add(&tsdev->dev);
++      if (error)
++              goto err_cleanup_tsdev;
+       return 0;
+- err_delete_tsdev:
+-      device_del(&tsdev->dev);
++ err_cleanup_tsdev:
++      tsdev_cleanup(tsdev);
++ err_unregister_handle:
++      input_unregister_handle(&tsdev->handle);
+  err_free_tsdev:
+       put_device(&tsdev->dev);
+       return error;
+@@ -466,20 +640,10 @@ static int tsdev_connect(struct input_ha
+ static void tsdev_disconnect(struct input_handle *handle)
+ {
+       struct tsdev *tsdev = handle->private;
+-      struct tsdev_client *client;
+-      input_unregister_handle(handle);
+       device_del(&tsdev->dev);
+-
+-      tsdev->exist = 0;
+-
+-      if (tsdev->open) {
+-              input_close_device(handle);
+-              list_for_each_entry(client, &tsdev->client_list, node)
+-                      kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+-              wake_up_interruptible(&tsdev->wait);
+-      }
+-
++      tsdev_cleanup(tsdev);
++      input_unregister_handle(handle);
+       put_device(&tsdev->dev);
+ }
+@@ -510,13 +674,13 @@ static const struct input_device_id tsde
+ MODULE_DEVICE_TABLE(input, tsdev_ids);
+ static struct input_handler tsdev_handler = {
+-      .event =        tsdev_event,
+-      .connect =      tsdev_connect,
+-      .disconnect =   tsdev_disconnect,
+-      .fops =         &tsdev_fops,
+-      .minor =        TSDEV_MINOR_BASE,
+-      .name =         "tsdev",
+-      .id_table =     tsdev_ids,
++      .event          = tsdev_event,
++      .connect        = tsdev_connect,
++      .disconnect     = tsdev_disconnect,
++      .fops           = &tsdev_fops,
++      .minor          = TSDEV_MINOR_BASE,
++      .name           = "tsdev",
++      .id_table       = tsdev_ids,
+ };
+ static int __init tsdev_init(void)
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:45 2008
+Message-Id: <20080206234445.480630762@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:55 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Oliver Neukum <oneukum@suse.de>,
+ Al Viro <viro@ZenIV.linux.org.uk>,
+ Dmitry Torokhov <dtor@mail.ru>
+Subject: [patch 53/73] Input: fix open count handling in input interfaces
+Content-Disposition: inline; filename=input-fix-open-count-handling-in-input-interfaces.patch
+Content-Length: 2054
+Lines: 81
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Oliver Neukum <oliver@neukum.org>
+
+patch 064450140f1eab959bd0eca0245f449993216074 in mainline.
+
+If input_open_device() fails we should not leave interfaces marked
+as opened.
+
+Signed-off-by: Oliver Neukum <oneukum@suse.de>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/evdev.c    |    5 ++++-
+ drivers/input/joydev.c   |    5 ++++-
+ drivers/input/mousedev.c |    5 ++++-
+ drivers/input/tsdev.c    |    5 ++++-
+ 4 files changed, 16 insertions(+), 4 deletions(-)
+
+--- a/drivers/input/evdev.c
++++ b/drivers/input/evdev.c
+@@ -192,8 +192,11 @@ static int evdev_open_device(struct evde
+       if (!evdev->exist)
+               retval = -ENODEV;
+-      else if (!evdev->open++)
++      else if (!evdev->open++) {
+               retval = input_open_device(&evdev->handle);
++              if (retval)
++                      evdev->open--;
++      }
+       mutex_unlock(&evdev->mutex);
+       return retval;
+--- a/drivers/input/joydev.c
++++ b/drivers/input/joydev.c
+@@ -205,8 +205,11 @@ static int joydev_open_device(struct joy
+       if (!joydev->exist)
+               retval = -ENODEV;
+-      else if (!joydev->open++)
++      else if (!joydev->open++) {
+               retval = input_open_device(&joydev->handle);
++              if (retval)
++                      joydev->open--;
++      }
+       mutex_unlock(&joydev->mutex);
+       return retval;
+--- a/drivers/input/mousedev.c
++++ b/drivers/input/mousedev.c
+@@ -428,8 +428,11 @@ static int mousedev_open_device(struct m
+               mixdev_open_devices();
+       else if (!mousedev->exist)
+               retval = -ENODEV;
+-      else if (!mousedev->open++)
++      else if (!mousedev->open++) {
+               retval = input_open_device(&mousedev->handle);
++              if (retval)
++                      mousedev->open--;
++      }
+       mutex_unlock(&mousedev->mutex);
+       return retval;
+--- a/drivers/input/tsdev.c
++++ b/drivers/input/tsdev.c
+@@ -185,8 +185,11 @@ static int tsdev_open_device(struct tsde
+       if (!tsdev->exist)
+               retval = -ENODEV;
+-      else if (!tsdev->open++)
++      else if (!tsdev->open++) {
+               retval = input_open_device(&tsdev->handle);
++              if (retval)
++                      tsdev->open--;
++      }
+       mutex_unlock(&tsdev->mutex);
+       return retval;
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:45 2008
+Message-Id: <20080206234445.700205454@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:56 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Steve French <sfrench@us.ibm.com>,
+ Jeff <jlayton@redhat.com>,
+ maximilian attems <max@stro.at>
+Subject: [patch 54/73] CIFS: Respect umask when using POSIX mkdir
+Content-Disposition: inline; filename=cifs-respect-umask-when-using-posix-mkdir.patch
+Content-Length: 870
+Lines: 31
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Steve French <sfrench@us.ibm.com>
+
+patch a8cd925f74c3b1b6d1192f9e75f9d12cc2ab148a in mainline.
+
+[CIFS] Respect umask when using POSIX mkdir
+
+When making a directory with POSIX mkdir calls, cifs_mkdir does not
+respect the umask.  This patch causes the new POSIX mkdir to create with
+the right mode
+
+Signed-off-by: Jeff Layton <jlayton@redhat.com>
+Signed-off-by: Steve French <sfrench@us.ibm.com>
+Cc: maximilian attems <max@stro.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/cifs/inode.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/fs/cifs/inode.c
++++ b/fs/cifs/inode.c
+@@ -919,6 +919,7 @@ int cifs_mkdir(struct inode *inode, stru
+                       goto mkdir_out;
+               }
++              mode &= ~current->fs->umask;
+               rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
+                               mode, NULL /* netfid */, pInfo, &oplock,
+                               full_path, cifs_sb->local_nls,
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:46 2008
+Message-Id: <20080206234445.919571790@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:57 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Matthew Wilcox <matthew@wil.cx>,
+ maximilian attems <max@stro.at>,
+ Geert Uytterhoeven <geert@linux-m68k.org>
+Subject: [patch 55/73] m68k: Export cachectl.h
+Content-Disposition: inline; filename=m68k-export-cachectl.h.patch
+Content-Length: 733
+Lines: 26
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Matthew Wilcox <matthew@wil.cx>
+
+patch e92042e5c009d84ba741ec4a978a13f260e6ee24 in mainline.
+
+m68k: Export cachectl.h
+
+libffi in GCC 4.2 needs cachectl.h to do its cache flushing.  But we
+don't currently export it.  I believe this patch should do the trick.
+
+Signed-off-by: Matthew Wilcox <matthew@wil.cx>
+Cc: maximilian attems <max@stro.at>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/asm-m68k/Kbuild |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/include/asm-m68k/Kbuild
++++ b/include/asm-m68k/Kbuild
+@@ -1 +1,2 @@
+ include include/asm-generic/Kbuild.asm
++header-y += cachectl.h
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:46 2008
+Message-Id: <20080206234446.139178589@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:58 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Eric Paris <eparis@redhat.com>,
+ Alan Cox <alan@redhat.com>,
+ Stephen Smalley <sds@tycho.nsa.gov>,
+ James Morris <jmorris@namei.org>,
+ Chris Wright <chrisw@sous-sol.org>,
+ maximilian attems <max@stro.at>
+Subject: [patch 56/73] VM/Security: add security hook to do_brk (CVE-2007-6434)
+Content-Disposition: inline; filename=vm-security-add-security-hook-to-do_brk.patch
+Content-Length: 1190
+Lines: 39
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Eric Paris <eparis@redhat.com>
+
+patch ecaf18c15aac8bb9bed7b7aa0e382fe252e275d5 in mainline.
+
+VM/Security: add security hook to do_brk
+
+Given a specifically crafted binary do_brk() can be used to get low pages
+available in userspace virtual memory and can thus be used to circumvent
+the mmap_min_addr low memory protection.  Add security checks in do_brk().
+
+Signed-off-by: Eric Paris <eparis@redhat.com>
+Acked-by: Alan Cox <alan@redhat.com>
+Cc: Stephen Smalley <sds@tycho.nsa.gov>
+Cc: James Morris <jmorris@namei.org>
+Cc: Chris Wright <chrisw@sous-sol.org>
+Cc: maximilian attems <max@stro.at>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/mmap.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/mm/mmap.c
++++ b/mm/mmap.c
+@@ -1938,6 +1938,10 @@ unsigned long do_brk(unsigned long addr,
+       if (is_hugepage_only_range(mm, addr, len))
+               return -EINVAL;
++      error = security_file_mmap(0, 0, 0, 0, addr, 1);
++      if (error)
++              return error;
++
+       flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
+       error = arch_mmap_check(addr, len, flags);
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:46 2008
+Message-Id: <20080206234446.359692397@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:59 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Eric Paris <eparis@redhat.com>,
+ James Morris <jmorris@namei.org>
+Subject: [patch 57/73] security: protect from stack expantion into low vm addresses
+Content-Disposition: inline; filename=security-protect-from-stack-expantion-into-low-vm-addresses.patch
+Content-Length: 1082
+Lines: 41
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Eric Paris <eparis@redhat.com>
+
+patch 8869477a49c3e99def1fcdadd6bbc407fea14b45 in mainline.
+
+Add security checks to make sure we are not attempting to expand the
+stack into memory protected by mmap_min_addr
+
+Signed-off-by: Eric Paris <eparis@redhat.com>
+Signed-off-by: James Morris <jmorris@namei.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/mmap.c |    8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/mm/mmap.c
++++ b/mm/mmap.c
+@@ -1619,6 +1619,12 @@ static inline int expand_downwards(struc
+        */
+       if (unlikely(anon_vma_prepare(vma)))
+               return -ENOMEM;
++
++      address &= PAGE_MASK;
++      error = security_file_mmap(0, 0, 0, 0, address, 1);
++      if (error)
++              return error;
++
+       anon_vma_lock(vma);
+       /*
+@@ -1626,8 +1632,6 @@ static inline int expand_downwards(struc
+        * is required to hold the mmap_sem in read mode.  We need the
+        * anon_vma lock to serialize against concurrent expand_stacks.
+        */
+-      address &= PAGE_MASK;
+-      error = 0;
+       /* Somebody else might have raced and expanded it already */
+       if (address < vma->vm_start) {
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:46 2008
+Message-Id: <20080206234446.579494091@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:00 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Dan Williams <dan.j.williams@intel.com>,
+ Neil Brown <neilb@suse.de>
+Subject: [patch 58/73] md: fix data corruption when a degraded raid5 array is reshaped
+Content-Disposition: inline; filename=md-fix-data-corruption-when-a-degraded-raid5-array-is-reshaped.patch
+Content-Length: 1503
+Lines: 47
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Dan Williams <dan.j.williams@intel.com>
+
+patch 0f94e87cdeaaac9f0f9a28a5dd2a5070b87cd3e8 in mainline.
+
+We currently do not wait for the block from the missing device to be
+computed from parity before copying data to the new stripe layout.
+
+The change in the raid6 code is not techincally needed as we don't delay
+data block recovery in the same way for raid6 yet.  But making the change
+now is safer long-term.
+
+This bug exists in 2.6.23 and 2.6.24-rc
+
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Acked-by: Neil Brown <neilb@suse.de>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/raid5.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/md/raid5.c
++++ b/drivers/md/raid5.c
+@@ -2875,7 +2875,8 @@ static void handle_stripe5(struct stripe
+               md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
+       }
+-      if (s.expanding && s.locked == 0)
++      if (s.expanding && s.locked == 0 &&
++          !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending))
+               handle_stripe_expansion(conf, sh, NULL);
+       if (sh->ops.count)
+@@ -3077,7 +3078,8 @@ static void handle_stripe6(struct stripe
+               md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
+       }
+-      if (s.expanding && s.locked == 0)
++      if (s.expanding && s.locked == 0 &&
++          !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending))
+               handle_stripe_expansion(conf, sh, &r6s);
+       spin_unlock(&sh->lock);
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:47 2008
+Message-Id: <20080206234446.798573865@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:01 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org,
+ Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ NeilBrown <neilb@suse.de>,
+ Peter Staubach <staubach@redhat.com>,
+ "J. Bruce Fields" <bfields@citi.umich.edu>,
+ nfs@lists.sourceforge.net
+Subject: [patch 59/73] knfsd: Allow NFSv2/3 WRITE calls to succeed when krb5i etc is used.
+Content-Disposition: inline; filename=knfsd-allow-nfsv2-3-write-calls-to-succeed-when-krb5i-etc-is-used.patch
+Content-Length: 2090
+Lines: 62
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: NeilBrown <neilb@suse.de>
+
+patch ba67a39efde8312e386c6f603054f8945433d91f in mainline.
+
+When RPCSEC/GSS and krb5i is used, requests are padded, typically to a multiple
+of 8 bytes.  This can make the request look slightly longer than it
+really is.
+
+As of
+
+       f34b95689d2ce001c "The NFSv2/NFSv3 server does not handle zero
+               length WRITE request correctly",
+
+the xdr decode routines for NFSv2 and NFSv3 reject requests that aren't
+the right length, so krb5i (for example) WRITE requests can get lost.
+
+This patch relaxes the appropriate test and enhances the related comment.
+
+Signed-off-by: Neil Brown <neilb@suse.de>
+Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
+Cc: Peter Staubach <staubach@redhat.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/nfsd/nfs3xdr.c |    5 ++++-
+ fs/nfsd/nfsxdr.c  |    5 ++++-
+ 2 files changed, 8 insertions(+), 2 deletions(-)
+
+--- a/fs/nfsd/nfs3xdr.c
++++ b/fs/nfsd/nfs3xdr.c
+@@ -396,8 +396,11 @@ nfs3svc_decode_writeargs(struct svc_rqst
+        * Round the length of the data which was specified up to
+        * the next multiple of XDR units and then compare that
+        * against the length which was actually received.
++       * Note that when RPCSEC/GSS (for example) is used, the
++       * data buffer can be padded so dlen might be larger
++       * than required.  It must never be smaller.
+        */
+-      if (dlen != XDR_QUADLEN(len)*4)
++      if (dlen < XDR_QUADLEN(len)*4)
+               return 0;
+       if (args->count > max_blocksize) {
+--- a/fs/nfsd/nfsxdr.c
++++ b/fs/nfsd/nfsxdr.c
+@@ -313,8 +313,11 @@ nfssvc_decode_writeargs(struct svc_rqst 
+        * Round the length of the data which was specified up to
+        * the next multiple of XDR units and then compare that
+        * against the length which was actually received.
++       * Note that when RPCSEC/GSS (for example) is used, the
++       * data buffer can be padded so dlen might be larger
++       * than required.  It must never be smaller.
+        */
+-      if (dlen != XDR_QUADLEN(len)*4)
++      if (dlen < XDR_QUADLEN(len)*4)
+               return 0;
+       rqstp->rq_vec[0].iov_base = (void*)p;
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:47 2008
+Message-Id: <20080206234447.018666787@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:02 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Nick Piggin <npiggin@suse.de>
+Subject: [patch 60/73] vm audit: add VM_DONTEXPAND to mmap for drivers that need it (CVE-2008-0007)
+Content-Disposition: inline; filename=vm-audit-add-vm_dontexpand-to-mmap-for-drivers-that-need-it.patch
+Content-Length: 4620
+Lines: 141
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Nick Piggin <npiggin@suse.de>
+
+Drivers that register a ->fault handler, but do not range-check the
+offset argument, must set VM_DONTEXPAND in the vm_flags in order to
+prevent an expanding mremap from overflowing the resource.
+
+I've audited the tree and attempted to fix these problems (usually by
+adding VM_DONTEXPAND where it is not obvious).
+
+Signed-off-by: Nick Piggin <npiggin@suse.de>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/drm/drm_vm.c       |    2 ++
+ drivers/char/mspec.c            |    2 +-
+ fs/ncpfs/mmap.c                 |    4 ----
+ kernel/relay.c                  |    1 +
+ mm/mmap.c                       |    2 +-
+ sound/oss/via82cxxx_audio.c     |   14 ++++++--------
+ sound/usb/usx2y/usX2Yhwdep.c    |    2 +-
+ sound/usb/usx2y/usx2yhwdeppcm.c |    2 +-
+ 8 files changed, 13 insertions(+), 16 deletions(-)
+
+--- a/drivers/char/drm/drm_vm.c
++++ b/drivers/char/drm/drm_vm.c
+@@ -506,6 +506,7 @@ static int drm_mmap_dma(struct file *fil
+       vma->vm_ops = &drm_vm_dma_ops;
+       vma->vm_flags |= VM_RESERVED;   /* Don't swap */
++      vma->vm_flags |= VM_DONTEXPAND;
+       vma->vm_file = filp;    /* Needed for drm_vm_open() */
+       drm_vm_open_locked(vma);
+@@ -655,6 +656,7 @@ static int drm_mmap_locked(struct file *
+               return -EINVAL; /* This should never happen. */
+       }
+       vma->vm_flags |= VM_RESERVED;   /* Don't swap */
++      vma->vm_flags |= VM_DONTEXPAND;
+       vma->vm_file = filp;    /* Needed for drm_vm_open() */
+       drm_vm_open_locked(vma);
+--- a/drivers/char/mspec.c
++++ b/drivers/char/mspec.c
+@@ -283,7 +283,7 @@ mspec_mmap(struct file *file, struct vm_
+       vdata->refcnt = ATOMIC_INIT(1);
+       vma->vm_private_data = vdata;
+-      vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP);
++      vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP | VM_DONTEXPAND);
+       if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED)
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       vma->vm_ops = &mspec_vm_ops;
+--- a/fs/ncpfs/mmap.c
++++ b/fs/ncpfs/mmap.c
+@@ -50,10 +50,6 @@ static int ncp_file_mmap_fault(struct vm
+       pos = vmf->pgoff << PAGE_SHIFT;
+       count = PAGE_SIZE;
+-      if ((unsigned long)vmf->virtual_address + PAGE_SIZE > area->vm_end) {
+-              WARN_ON(1); /* shouldn't happen? */
+-              count = area->vm_end - (unsigned long)vmf->virtual_address;
+-      }
+       /* what we can read in one go */
+       bufsize = NCP_SERVER(inode)->buffer_size;
+--- a/kernel/relay.c
++++ b/kernel/relay.c
+@@ -92,6 +92,7 @@ static int relay_mmap_buf(struct rchan_b
+               return -EINVAL;
+       vma->vm_ops = &relay_file_mmap_ops;
++      vma->vm_flags |= VM_DONTEXPAND;
+       vma->vm_private_data = buf;
+       buf->chan->cb->buf_mapped(buf, filp);
+--- a/mm/mmap.c
++++ b/mm/mmap.c
+@@ -2217,7 +2217,7 @@ int install_special_mapping(struct mm_st
+       vma->vm_start = addr;
+       vma->vm_end = addr + len;
+-      vma->vm_flags = vm_flags | mm->def_flags;
++      vma->vm_flags = vm_flags | mm->def_flags | VM_DONTEXPAND;
+       vma->vm_page_prot = protection_map[vma->vm_flags & 7];
+       vma->vm_ops = &special_mapping_vmops;
+--- a/sound/oss/via82cxxx_audio.c
++++ b/sound/oss/via82cxxx_audio.c
+@@ -2104,6 +2104,7 @@ static struct page * via_mm_nopage (stru
+ {
+       struct via_info *card = vma->vm_private_data;
+       struct via_channel *chan = &card->ch_out;
++      unsigned long max_bufs;
+       struct page *dmapage;
+       unsigned long pgoff;
+       int rd, wr;
+@@ -2127,14 +2128,11 @@ static struct page * via_mm_nopage (stru
+       rd = card->ch_in.is_mapped;
+       wr = card->ch_out.is_mapped;
+-#ifndef VIA_NDEBUG
+-      {
+-      unsigned long max_bufs = chan->frag_number;
+-      if (rd && wr) max_bufs *= 2;
+-      /* via_dsp_mmap() should ensure this */
+-      assert (pgoff < max_bufs);
+-      }
+-#endif
++      max_bufs = chan->frag_number;
++      if (rd && wr)
++              max_bufs *= 2;
++      if (pgoff >= max_bufs)
++              return NOPAGE_SIGBUS;
+       /* if full-duplex (read+write) and we have two sets of bufs,
+        * then the playback buffers come first, sez soundcard.c */
+--- a/sound/usb/usx2y/usX2Yhwdep.c
++++ b/sound/usb/usx2y/usX2Yhwdep.c
+@@ -88,7 +88,7 @@ static int snd_us428ctls_mmap(struct snd
+               us428->us428ctls_sharedmem->CtlSnapShotLast = -2;
+       }
+       area->vm_ops = &us428ctls_vm_ops;
+-      area->vm_flags |= VM_RESERVED;
++      area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
+       area->vm_private_data = hw->private_data;
+       return 0;
+ }
+--- a/sound/usb/usx2y/usx2yhwdeppcm.c
++++ b/sound/usb/usx2y/usx2yhwdeppcm.c
+@@ -728,7 +728,7 @@ static int snd_usX2Y_hwdep_pcm_mmap(stru
+               return -ENODEV;
+       }
+       area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
+-      area->vm_flags |= VM_RESERVED;
++      area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
+       area->vm_private_data = hw->private_data;
+       return 0;
+ }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:47 2008
+Message-Id: <20080206234447.239550651@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:03 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Jeff Garzik <jeff@garzik.org>,
+ Mikael Pettersson <mikpe@it.uu.se>
+Subject: [patch 61/73] sata_promise: ASIC PRD table bug workaround
+Content-Disposition: inline; filename=sata_promise-asic-prd-table-bug-workaround.patch
+Content-Length: 4299
+Lines: 156
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Mikael Pettersson <mikpe@it.uu.se>
+
+patch 03116d67e0973bb493fe9307e28973a24a272bcc in mainline.
+
+Second-generation Promise SATA controllers have an ASIC bug
+which can trigger if the last PRD entry is larger than 164 bytes,
+resulting in intermittent errors and possible data corruption.
+
+Work around this by replacing calls to ata_qc_prep() with a
+private version that fills the PRD, checks the size of the
+last entry, and if necessary splits it to avoid the bug.
+Also reduce sg_tablesize by 1 to accommodate the new entry.
+
+Tested on the second-generation SATA300 TX4 and SATA300 TX2plus,
+and the first-generation PDC20378.
+
+Thanks to Alexander Sabourenkov for verifying the bug by
+studying the vendor driver, and for writing the initial patch
+upon which this one is based.
+
+Signed-off-by: Mikael Pettersson <mikpe@it.uu.se>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/ata/sata_promise.c |   87 ++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 83 insertions(+), 4 deletions(-)
+
+--- a/drivers/ata/sata_promise.c
++++ b/drivers/ata/sata_promise.c
+@@ -50,6 +50,7 @@
+ enum {
+       PDC_MAX_PORTS           = 4,
+       PDC_MMIO_BAR            = 3,
++      PDC_MAX_PRD             = LIBATA_MAX_PRD - 1, /* -1 for ASIC PRD bug workaround */
+       /* register offsets */
+       PDC_FEATURE             = 0x04, /* Feature/Error reg (per port) */
+@@ -155,7 +156,7 @@ static struct scsi_host_template pdc_ata
+       .queuecommand           = ata_scsi_queuecmd,
+       .can_queue              = ATA_DEF_QUEUE,
+       .this_id                = ATA_SHT_THIS_ID,
+-      .sg_tablesize           = LIBATA_MAX_PRD,
++      .sg_tablesize           = PDC_MAX_PRD,
+       .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
+       .emulated               = ATA_SHT_EMULATED,
+       .use_clustering         = ATA_SHT_USE_CLUSTERING,
+@@ -527,6 +528,84 @@ static void pdc_atapi_pkt(struct ata_que
+       memcpy(buf+31, cdb, cdb_len);
+ }
++/**
++ *    pdc_fill_sg - Fill PCI IDE PRD table
++ *    @qc: Metadata associated with taskfile to be transferred
++ *
++ *    Fill PCI IDE PRD (scatter-gather) table with segments
++ *    associated with the current disk command.
++ *    Make sure hardware does not choke on it.
++ *
++ *    LOCKING:
++ *    spin_lock_irqsave(host lock)
++ *
++ */
++static void pdc_fill_sg(struct ata_queued_cmd *qc)
++{
++      struct ata_port *ap = qc->ap;
++      struct scatterlist *sg;
++      unsigned int idx;
++      const u32 SG_COUNT_ASIC_BUG = 41*4;
++
++      if (!(qc->flags & ATA_QCFLAG_DMAMAP))
++              return;
++
++      WARN_ON(qc->__sg == NULL);
++      WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
++
++      idx = 0;
++      ata_for_each_sg(sg, qc) {
++              u32 addr, offset;
++              u32 sg_len, len;
++
++              /* determine if physical DMA addr spans 64K boundary.
++               * Note h/w doesn't support 64-bit, so we unconditionally
++               * truncate dma_addr_t to u32.
++               */
++              addr = (u32) sg_dma_address(sg);
++              sg_len = sg_dma_len(sg);
++
++              while (sg_len) {
++                      offset = addr & 0xffff;
++                      len = sg_len;
++                      if ((offset + sg_len) > 0x10000)
++                              len = 0x10000 - offset;
++
++                      ap->prd[idx].addr = cpu_to_le32(addr);
++                      ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
++                      VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
++
++                      idx++;
++                      sg_len -= len;
++                      addr += len;
++              }
++      }
++
++      if (idx) {
++              u32 len = le32_to_cpu(ap->prd[idx - 1].flags_len);
++
++              if (len > SG_COUNT_ASIC_BUG) {
++                      u32 addr;
++
++                      VPRINTK("Splitting last PRD.\n");
++
++                      addr = le32_to_cpu(ap->prd[idx - 1].addr);
++                      ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG);
++                      VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG);
++
++                      addr = addr + len - SG_COUNT_ASIC_BUG;
++                      len = SG_COUNT_ASIC_BUG;
++                      ap->prd[idx].addr = cpu_to_le32(addr);
++                      ap->prd[idx].flags_len = cpu_to_le32(len);
++                      VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
++
++                      idx++;
++              }
++
++              ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
++      }
++}
++
+ static void pdc_qc_prep(struct ata_queued_cmd *qc)
+ {
+       struct pdc_port_priv *pp = qc->ap->private_data;
+@@ -536,7 +615,7 @@ static void pdc_qc_prep(struct ata_queue
+       switch (qc->tf.protocol) {
+       case ATA_PROT_DMA:
+-              ata_qc_prep(qc);
++              pdc_fill_sg(qc);
+               /* fall through */
+       case ATA_PROT_NODATA:
+@@ -552,11 +631,11 @@ static void pdc_qc_prep(struct ata_queue
+               break;
+       case ATA_PROT_ATAPI:
+-              ata_qc_prep(qc);
++              pdc_fill_sg(qc);
+               break;
+       case ATA_PROT_ATAPI_DMA:
+-              ata_qc_prep(qc);
++              pdc_fill_sg(qc);
+               /*FALLTHROUGH*/
+       case ATA_PROT_ATAPI_NODATA:
+               pdc_atapi_pkt(qc);
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:47 2008
+Message-Id: <20080206234447.458794679@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:04 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Tony Luck <tony.luck@intel.com>
+Subject: [patch 62/73] ia64: Fix unaligned handler for floating point instructions with base update
+Content-Disposition: inline; filename=ia64-fix-unaligned-handler-for-floating-point-instructions-with-base-update.patch
+Content-Length: 1932
+Lines: 59
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Luck, Tony <tony.luck@intel.com>
+
+commit 1a499150e4ec1299232e24389f648d059ce5617a in mainline.
+
+[IA64] Fix unaligned handler for floating point instructions with base update
+
+The compiler team did the hard work for this distilling a problem in
+large fortran application which showed up when applied to a 290MB input
+data set down to this instruction:
+
+       ldfd f34=[r17],-8
+
+Which they noticed incremented r17 by 0x10 rather than decrementing it
+by 8 when the value in r17 caused an unaligned data fault.  I tracked
+it down to some bad instruction decoding in unaligned.c. The code
+assumes that the 'x' bit can determine whether the instruction is
+an "ldf" or "ldfp" ... which it is for opcode=6 (see table 4-29 on
+page 3:302 of the SDM).  But for opcode=7 the 'x' bit is irrelevent,
+all variants are "ldf" instructions (see table 4-36 on page 3:306).
+
+Note also that interpreting the instruction as "ldfp" means that the
+"paired" floating point register (f35 in the example here) will also
+be corrupted.
+
+Signed-off-by: Tony Luck <tony.luck@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/ia64/kernel/unaligned.c |   11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/arch/ia64/kernel/unaligned.c
++++ b/arch/ia64/kernel/unaligned.c
+@@ -1487,16 +1487,19 @@ ia64_handle_unaligned (unsigned long ifa
+             case LDFA_OP:
+             case LDFCCLR_OP:
+             case LDFCNC_OP:
+-            case LDF_IMM_OP:
+-            case LDFA_IMM_OP:
+-            case LDFCCLR_IMM_OP:
+-            case LDFCNC_IMM_OP:
+               if (u.insn.x)
+                       ret = emulate_load_floatpair(ifa, u.insn, regs);
+               else
+                       ret = emulate_load_float(ifa, u.insn, regs);
+               break;
++            case LDF_IMM_OP:
++            case LDFA_IMM_OP:
++            case LDFCCLR_IMM_OP:
++            case LDFCNC_IMM_OP:
++              ret = emulate_load_float(ifa, u.insn, regs);
++              break;
++
+             case STF_OP:
+             case STF_IMM_OP:
+               ret = emulate_store_float(ifa, u.insn, regs);
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:47 2008
+Message-Id: <20080206234447.677408700@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:05 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org,
+ torvalds@linux-foundation.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ nigel@nigel.suspend2.net,
+ nigel@tuxonice.net
+Subject: [patch 63/73] Fix unbalanced helper_lock in kernel/kmod.c
+Content-Disposition: inline; filename=fix-unbalanced-helper_lock-in-kernel-kmod.c.patch
+Content-Length: 1424
+Lines: 56
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Nigel Cunningham <nigel@nigel.suspend2.net>
+
+patch 784680336b616dcc4c17cbd25add3b49c555cdeb in mainline.
+
+call_usermodehelper_exec() has an exit path that can leave the
+helper_lock() call at the top of the routine unbalanced.  The attached
+patch fixes this issue.
+
+Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ kernel/kmod.c |   13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/kernel/kmod.c
++++ b/kernel/kmod.c
+@@ -451,13 +451,11 @@ int call_usermodehelper_exec(struct subp
+                            enum umh_wait wait)
+ {
+       DECLARE_COMPLETION_ONSTACK(done);
+-      int retval;
++      int retval = 0;
+       helper_lock();
+-      if (sub_info->path[0] == '\0') {
+-              retval = 0;
++      if (sub_info->path[0] == '\0')
+               goto out;
+-      }
+       if (!khelper_wq || usermodehelper_disabled) {
+               retval = -EBUSY;
+@@ -468,13 +466,14 @@ int call_usermodehelper_exec(struct subp
+       sub_info->wait = wait;
+       queue_work(khelper_wq, &sub_info->work);
+-      if (wait == UMH_NO_WAIT) /* task has freed sub_info */
+-              return 0;
++      if (wait == UMH_NO_WAIT)        /* task has freed sub_info */
++              goto unlock;
+       wait_for_completion(&done);
+       retval = sub_info->retval;
+-  out:
++out:
+       call_usermodehelper_freeinfo(sub_info);
++unlock:
+       helper_unlock();
+       return retval;
+ }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:48 2008
+Message-Id: <20080206234447.897680202@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:06 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org,
+ torvalds@linux-foundation.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ dbrownell@users.sourceforge.net,
+ kalle.valo@nokia.com
+Subject: [patch 64/73] spi: omap2_mcspi PIO RX fix
+Content-Disposition: inline; filename=spi-omap2_mcspi-pio-rx-fix.patch
+Content-Length: 2165
+Lines: 82
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Kalle Valo <kalle.valo@nokia.com>
+
+patch feed9bab7b14b77be8d796bcee95e2343fb82955 in mainline.
+
+Before transmission of the last word in PIO RX_ONLY mode rx+tx mode
+is enabled:
+
+       /* prevent last RX_ONLY read from triggering
+        * more word i/o: switch to rx+tx
+        */
+       if (c == 0 && tx == NULL)
+               mcspi_write_cs_reg(spi,
+                               OMAP2_MCSPI_CHCONF0, l);
+
+But because c is decremented after the test, c will never be zero and
+rx+tx will not be enabled. This breaks RX_ONLY mode PIO transfers.
+
+Fix it by decrementing c in the beginning of the various I/O loops.
+
+Signed-off-by: Kalle Valo <kalle.valo@nokia.com>
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/spi/omap2_mcspi.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/spi/omap2_mcspi.c
++++ b/drivers/spi/omap2_mcspi.c
+@@ -350,6 +350,7 @@ omap2_mcspi_txrx_pio(struct spi_device *
+               tx = xfer->tx_buf;
+               do {
++                      c -= 1;
+                       if (tx != NULL) {
+                               if (mcspi_wait_for_reg_bit(chstat_reg,
+                                               OMAP2_MCSPI_CHSTAT_TXS) < 0) {
+@@ -380,7 +381,6 @@ omap2_mcspi_txrx_pio(struct spi_device *
+                                               word_len, *(rx - 1));
+ #endif
+                       }
+-                      c -= 1;
+               } while (c);
+       } else if (word_len <= 16) {
+               u16             *rx;
+@@ -389,6 +389,7 @@ omap2_mcspi_txrx_pio(struct spi_device *
+               rx = xfer->rx_buf;
+               tx = xfer->tx_buf;
+               do {
++                      c -= 2;
+                       if (tx != NULL) {
+                               if (mcspi_wait_for_reg_bit(chstat_reg,
+                                               OMAP2_MCSPI_CHSTAT_TXS) < 0) {
+@@ -419,7 +420,6 @@ omap2_mcspi_txrx_pio(struct spi_device *
+                                               word_len, *(rx - 1));
+ #endif
+                       }
+-                      c -= 2;
+               } while (c);
+       } else if (word_len <= 32) {
+               u32             *rx;
+@@ -428,6 +428,7 @@ omap2_mcspi_txrx_pio(struct spi_device *
+               rx = xfer->rx_buf;
+               tx = xfer->tx_buf;
+               do {
++                      c -= 4;
+                       if (tx != NULL) {
+                               if (mcspi_wait_for_reg_bit(chstat_reg,
+                                               OMAP2_MCSPI_CHSTAT_TXS) < 0) {
+@@ -458,7 +459,6 @@ omap2_mcspi_txrx_pio(struct spi_device *
+                                               word_len, *(rx - 1));
+ #endif
+                       }
+-                      c -= 4;
+               } while (c);
+       }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:48 2008
+Message-Id: <20080206234448.120720950@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:07 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Tomasz Chmielewski <mangoo@wpkg.org>,
+ Mark Lord <liml@rtr.ca>,
+ Tejun Heo <htejun@gmail.com>,
+ Jeff Garzik <jeff@garzik.org>
+Subject: [patch 65/73] libata: port and host should be stopped before hardware resources are released
+Content-Disposition: inline; filename=libata-port-and-host-should-be-stopped-before-hardware-resources-are-released.patch
+Content-Length: 3098
+Lines: 123
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Tejun Heo <htejun@gmail.com>
+
+This is backport of 32ebbc0c0d5d18c0135b55d1eb0029f48c54aff0 and fixes
+oops on driver module unload.
+
+Port / host stop calls used to be made from ata_host_release() which
+is called after all hardware resources acquired after host allocation
+are released.  This is wrong as port and host stop routines often
+access the hardware.
+
+Add separate devres for port / host stop which is invoked right after
+IRQ is released but with all other hardware resources intact.  The
+devres is added iff ->host_stop and/or ->port_stop exist.
+
+This problem has been spotted by Mark Lord.
+
+Signed-off-by: Tejun Heo <htejun@gmail.com>
+Cc: Mark Lord <liml@rtr.ca>
+Signed-off-by: Jeff Garzik <jeff@garzik.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/ata/libata-core.c |   52 ++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 39 insertions(+), 13 deletions(-)
+
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -6121,19 +6121,6 @@ static void ata_host_release(struct devi
+               if (!ap)
+                       continue;
+-              if ((host->flags & ATA_HOST_STARTED) && ap->ops->port_stop)
+-                      ap->ops->port_stop(ap);
+-      }
+-
+-      if ((host->flags & ATA_HOST_STARTED) && host->ops->host_stop)
+-              host->ops->host_stop(host);
+-
+-      for (i = 0; i < host->n_ports; i++) {
+-              struct ata_port *ap = host->ports[i];
+-
+-              if (!ap)
+-                      continue;
+-
+               if (ap->scsi_host)
+                       scsi_host_put(ap->scsi_host);
+@@ -6258,6 +6245,24 @@ struct ata_host *ata_host_alloc_pinfo(st
+       return host;
+ }
++static void ata_host_stop(struct device *gendev, void *res)
++{
++      struct ata_host *host = dev_get_drvdata(gendev);
++      int i;
++
++      WARN_ON(!(host->flags & ATA_HOST_STARTED));
++
++      for (i = 0; i < host->n_ports; i++) {
++              struct ata_port *ap = host->ports[i];
++
++              if (ap->ops->port_stop)
++                      ap->ops->port_stop(ap);
++      }
++
++      if (host->ops->host_stop)
++              host->ops->host_stop(host);
++}
++
+ /**
+  *    ata_host_start - start and freeze ports of an ATA host
+  *    @host: ATA host to start ports for
+@@ -6276,6 +6281,8 @@ struct ata_host *ata_host_alloc_pinfo(st
+  */
+ int ata_host_start(struct ata_host *host)
+ {
++      int have_stop = 0;
++      void *start_dr = NULL;
+       int i, rc;
+       if (host->flags & ATA_HOST_STARTED)
+@@ -6287,6 +6294,22 @@ int ata_host_start(struct ata_host *host
+               if (!host->ops && !ata_port_is_dummy(ap))
+                       host->ops = ap->ops;
++              if (ap->ops->port_stop)
++                      have_stop = 1;
++      }
++
++      if (host->ops->host_stop)
++              have_stop = 1;
++
++      if (have_stop) {
++              start_dr = devres_alloc(ata_host_stop, 0, GFP_KERNEL);
++              if (!start_dr)
++                      return -ENOMEM;
++      }
++
++      for (i = 0; i < host->n_ports; i++) {
++              struct ata_port *ap = host->ports[i];
++
+               if (ap->ops->port_start) {
+                       rc = ap->ops->port_start(ap);
+                       if (rc) {
+@@ -6299,6 +6322,8 @@ int ata_host_start(struct ata_host *host
+               ata_eh_freeze_port(ap);
+       }
++      if (start_dr)
++              devres_add(host->dev, start_dr);
+       host->flags |= ATA_HOST_STARTED;
+       return 0;
+@@ -6309,6 +6334,7 @@ int ata_host_start(struct ata_host *host
+               if (ap->ops->port_stop)
+                       ap->ops->port_stop(ap);
+       }
++      devres_free(start_dr);
+       return rc;
+ }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:48 2008
+Message-Id: <20080206234448.340926058@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:08 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ "Gerd v. Egidy" <gerd.von.egidy@intra2net.com>,
+ Karsten Keil <kkeil@suse.de>
+Subject: [patch 66/73] fix oops on rmmod capidrv
+Content-Disposition: inline; filename=fix-oops-on-rmmod-capidrv.patch
+Content-Length: 1126
+Lines: 43
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Karsten Keil <kkeil@suse.de>
+
+patch eb36f4fc019835cecf0788907f6cab774508087b in mainline.
+
+Fix overwriting the stack with the version string
+(it is currently 10 bytes + zero) when unloading the
+capidrv module. Safeguard against overwriting it
+should the version string grow in the future.
+
+Should fix Kernel Bug Tracker Bug 9696.
+
+Signed-off-by: Gerd v. Egidy <gerd.von.egidy@intra2net.com>
+Acked-by: Karsten Keil <kkeil@suse.de>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/isdn/capi/capidrv.c |    9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+--- a/drivers/isdn/capi/capidrv.c
++++ b/drivers/isdn/capi/capidrv.c
+@@ -2306,13 +2306,14 @@ static int __init capidrv_init(void)
+ static void __exit capidrv_exit(void)
+ {
+-      char rev[10];
++      char rev[32];
+       char *p;
+       if ((p = strchr(revision, ':')) != 0) {
+-              strcpy(rev, p + 1);
+-              p = strchr(rev, '$');
+-              *p = 0;
++              strncpy(rev, p + 1, sizeof(rev));
++              rev[sizeof(rev)-1] = 0;
++              if ((p = strchr(rev, '$')) != 0)
++                      *p = 0;
+       } else {
+               strcpy(rev, " ??? ");
+       }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:48 2008
+Message-Id: <20080206234448.561411919@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:09 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Netfilter Development Mailinglist <netfilter-devel@vger.kernel.org>,
+ "David S. Miller" <davem@davemloft.net>,
+ Patrick McHardy <kaber@trash.net>
+Subject: [patch 67/73] Netfilter: bridge: fix double POST_ROUTING invocation
+Content-Disposition: inline; filename=netfilter-bridge-fix-double-post_routing-invocation.patch
+Content-Length: 2557
+Lines: 72
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Patrick McHardy <kaber@trash.net>
+
+[NETFILTER]: bridge: fix double POST_ROUTING invocation
+
+Upstream commit 2948d2ebbb98747b912ac6d0c864b4d02be8a6f5
+
+The bridge code incorrectly causes two POST_ROUTING hook invocations
+for DNATed packets that end up on the same bridge device. This
+happens because packets with a changed destination address are passed
+to dst_output() to make them go through the neighbour output function
+again to build a new destination MAC address, before they will continue
+through the IP hooks simulated by bridge netfilter.
+
+The resulting hook order is:
+ PREROUTING (bridge netfilter)
+ POSTROUTING        (dst_output -> ip_output)
+ FORWARD    (bridge netfilter)
+ POSTROUTING        (bridge netfilter)
+
+The deferred hooks used to abort the first POST_ROUTING invocation,
+but since the only thing bridge netfilter actually really wants is
+a new MAC address, we can avoid going through the IP stack completely
+by simply calling the neighbour output function directly.
+
+Tested, reported and lots of data provided by: Damien Thebault <damien.thebault@gmail.com>
+
+Signed-off-by: Patrick McHardy <kaber@trash.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/bridge/br_netfilter.c |   18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+--- a/net/bridge/br_netfilter.c
++++ b/net/bridge/br_netfilter.c
+@@ -247,8 +247,9 @@ static void __br_dnat_complain(void)
+  * Let us first consider the case that ip_route_input() succeeds:
+  *
+  * If skb->dst->dev equals the logical bridge device the packet
+- * came in on, we can consider this bridging. We then call
+- * skb->dst->output() which will make the packet enter br_nf_local_out()
++ * came in on, we can consider this bridging. The packet is passed
++ * through the neighbour output function to build a new destination
++ * MAC address, which will make the packet enter br_nf_local_out()
+  * not much later. In that function it is assured that the iptables
+  * FORWARD chain is traversed for the packet.
+  *
+@@ -285,12 +286,17 @@ static int br_nf_pre_routing_finish_brid
+       skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
+       skb->dev = bridge_parent(skb->dev);
+-      if (!skb->dev)
+-              kfree_skb(skb);
+-      else {
++      if (skb->dev) {
++              struct dst_entry *dst = skb->dst;
++
+               nf_bridge_pull_encap_header(skb);
+-              skb->dst->output(skb);
++
++              if (dst->hh)
++                      return neigh_hh_output(dst->hh, skb);
++              else if (dst->neighbour)
++                      return dst->neighbour->output(skb);
+       }
++      kfree_skb(skb);
+       return 0;
+ }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:48 2008
+Message-Id: <20080206234448.781225168@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:10 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Netfilter Development Mailinglist <netfilter-devel@vger.kernel.org>,
+ "David S. Miller" <davem@davemloft.net>,
+ Patrick McHardy <kaber@trash.net>
+Subject: [patch 68/73] Netfilter: bridge-netfilter: fix net_device refcnt leaks
+Content-Disposition: inline; filename=netfilter-bridge-netfilter-fix-net_device-refcnt-leaks.patch
+Content-Length: 2468
+Lines: 82
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Patrick McHardy <kaber@trash.net>
+
+[NETFILTER]: bridge-netfilter: fix net_device refcnt leaks
+
+Upstream commit 2dc2f207fb251666d2396fe1a69272b307ecc333
+
+When packets are flood-forwarded to multiple output devices, the
+bridge-netfilter code reuses skb->nf_bridge for each clone to store
+the bridge port. When queueing packets using NFQUEUE netfilter takes
+a reference to skb->nf_bridge->physoutdev, which is overwritten
+when the packet is forwarded to the second port. This causes
+refcount unterflows for the first device and refcount leaks for all
+others. Additionally this provides incorrect data to the iptables
+physdev match.
+
+Unshare skb->nf_bridge by copying it if it is shared before assigning
+the physoutdev device.
+
+Reported, tested and based on initial patch by
+Jan Christoph Nordholz <hesso@pool.math.tu-berlin.de>.
+
+Signed-off-by: Patrick McHardy <kaber@trash.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/bridge/br_netfilter.c |   27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+--- a/net/bridge/br_netfilter.c
++++ b/net/bridge/br_netfilter.c
+@@ -142,6 +142,23 @@ static inline struct nf_bridge_info *nf_
+       return skb->nf_bridge;
+ }
++static inline struct nf_bridge_info *nf_bridge_unshare(struct sk_buff *skb)
++{
++      struct nf_bridge_info *nf_bridge = skb->nf_bridge;
++
++      if (atomic_read(&nf_bridge->use) > 1) {
++              struct nf_bridge_info *tmp = nf_bridge_alloc(skb);
++
++              if (tmp) {
++                      memcpy(tmp, nf_bridge, sizeof(struct nf_bridge_info));
++                      atomic_set(&tmp->use, 1);
++                      nf_bridge_put(nf_bridge);
++              }
++              nf_bridge = tmp;
++      }
++      return nf_bridge;
++}
++
+ static inline void nf_bridge_push_encap_header(struct sk_buff *skb)
+ {
+       unsigned int len = nf_bridge_encap_header_len(skb);
+@@ -644,6 +661,11 @@ static unsigned int br_nf_forward_ip(uns
+       if (!skb->nf_bridge)
+               return NF_ACCEPT;
++      /* Need exclusive nf_bridge_info since we might have multiple
++       * different physoutdevs. */
++      if (!nf_bridge_unshare(skb))
++              return NF_DROP;
++
+       parent = bridge_parent(out);
+       if (!parent)
+               return NF_DROP;
+@@ -727,6 +749,11 @@ static unsigned int br_nf_local_out(unsi
+       if (!skb->nf_bridge)
+               return NF_ACCEPT;
++      /* Need exclusive nf_bridge_info since we might have multiple
++       * different physoutdevs. */
++      if (!nf_bridge_unshare(skb))
++              return NF_DROP;
++
+       nf_bridge = skb->nf_bridge;
+       if (!(nf_bridge->mask & BRNF_BRIDGED_DNAT))
+               return NF_ACCEPT;
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:49 2008
+Message-Id: <20080206234449.000829807@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:11 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ B.Steinbrink@gmx.de,
+ jack@suse.cz,
+ Jan Kara <jack@ucw.cz>,
+ Nick Piggin <nickpiggin@yahoo.com.au>,
+ Peter Zijlstra <a.p.zijlstra@chello.nl>,
+ Thomas Osterried <osterried@jesse.de>,
+ Kerin Millar <kerframil@gmail.com>
+Subject: [patch 69/73] Fix dirty page accounting leak with ext3 data=journal
+Content-Disposition: inline; filename=fix-dirty-page-accounting-leak-with-ext3-data-journal.patch
+Content-Length: 2314
+Lines: 68
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Björn Steinbrink <B.Steinbrink@gmx.de>
+
+patch a2b345642f530054a92b8d2b5108436225a8093e in mainline.
+
+In 46d2277c796f9f4937bfa668c40b2e3f43e93dd0, try_to_free_buffers was
+changed to bail out if the page was dirty. That caused
+truncate_complete_page to leak massive amounts of memory, because the
+dirty bit was only cleared after the call to try_to_free_buffers. So the
+call to cancel_dirty_page was moved up to have the dirty bit cleared
+early in 3e67c0987d7567ad666641164a153dca9a43b11d.
+
+The problem with that fix is, that the page can be redirtied after
+cancel_dirty_page was called, eg. like this:
+
+truncate_complete_page()
+  cancel_dirty_page() // PG_dirty cleared, decr. dirty pages
+  do_invalidatepage()
+    ext3_invalidatepage()
+      journal_invalidatepage()
+        journal_unmap_buffer()
+          __dispose_buffer()
+            __journal_unfile_buffer()
+              __journal_temp_unlink_buffer()
+                mark_buffer_dirty(); // PG_dirty set, incr. dirty pages
+
+And then we end up with dirty pages being wrongly accounted.
+
+In ecdfc9787fe527491baefc22dce8b2dbd5b2908d the changes to
+try_to_free_buffers were reverted, so the original reason for the
+massive memory leak is gone, so we can also revert the move of
+the call to cancel_dirty_page from truncate_complete_page and get the
+accounting right again.
+
+Signed-off-by: Björn Steinbrink <B.Steinbrink@gmx.de>
+Tested-by: Krzysztof Piotr Oledzki <ole@ans.pl>
+Tested-by: Zaid D. <zaid.box@gmail.com>
+Cc: Jan Kara <jack@ucw.cz>
+Cc: Nick Piggin <nickpiggin@yahoo.com.au>
+Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Cc: Thomas Osterried <osterried@jesse.de>
+Cc: Kerin Millar <kerframil@gmail.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ mm/truncate.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/mm/truncate.c
++++ b/mm/truncate.c
+@@ -95,11 +95,11 @@ truncate_complete_page(struct address_sp
+       if (page->mapping != mapping)
+               return;
+-      cancel_dirty_page(page, PAGE_CACHE_SIZE);
+-
+       if (PagePrivate(page))
+               do_invalidatepage(page, 0);
++      cancel_dirty_page(page, PAGE_CACHE_SIZE);
++
+       remove_from_page_cache(page);
+       ClearPageUptodate(page);
+       ClearPageMappedToDisk(page);
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:49 2008
+Message-Id: <20080206234449.221656923@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:12 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org,
+ Jeff Garzik <jgarzik@pobox.com>,
+ Andrew Morton <akpm@osdl.org>,
+ nedev <netdev@vger.kernel.org>
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Ayaz Abdulla <aabdulla@nvidia.com>,
+ Jeff Garzik <jeff@garzik.org>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [patch 70/73] forcedeth: mac address mcp77/79
+Content-Disposition: inline; filename=forcedeth-mac-address-mcp77-79.patch
+Content-Length: 5073
+Lines: 65
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Ayaz Abdulla <aabdulla@nvidia.com>
+
+patch 2b91213064bd882c3adf35f028c6d12fab3269ec in mainline.
+
+This patch is a critical fix for MCP77 and MCP79 devices. The feature
+flags were missing the define for correct mac address
+(DEV_HAS_CORRECT_MACADDR).
+
+Signed-off-by: Ayaz Abdulla <aabdulla@nvidia.com>
+Signed-off-by: Jeff Garzik <jeff@garzik.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/forcedeth.c |   16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/forcedeth.c
++++ b/drivers/net/forcedeth.c
+@@ -5564,35 +5564,35 @@ static struct pci_device_id pci_tbl[] = 
+       },
+       {       /* MCP77 Ethernet Controller */
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32),
+-              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
++              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+       },
+       {       /* MCP77 Ethernet Controller */
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33),
+-              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
++              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+       },
+       {       /* MCP77 Ethernet Controller */
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34),
+-              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
++              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+       },
+       {       /* MCP77 Ethernet Controller */
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35),
+-              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
++              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+       },
+       {       /* MCP79 Ethernet Controller */
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36),
+-              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
++              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+       },
+       {       /* MCP79 Ethernet Controller */
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37),
+-              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
++              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+       },
+       {       /* MCP79 Ethernet Controller */
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38),
+-              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
++              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+       },
+       {       /* MCP79 Ethernet Controller */
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39),
+-              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
++              .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+       },
+       {0,},
+ };
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:49 2008
+Message-Id: <20080206234449.442265164@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:13 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org,
+ greg@kroah.com,
+ chrisw@sous-sol.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ david.harris@cpni-inc.com,
+ csnook@redhat.com,
+ jeff@garzik.org,
+ Jay Cliburn <jacliburn@bellsouth.net>
+Subject: [patch 71/73] atl1: fix frame length bug
+Content-Disposition: inline; filename=atl1-fix-frame-length-bug.patch
+Content-Length: 2014
+Lines: 55
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Jay Cliburn <jacliburn@bellsouth.net>
+
+
+Upstream commit: 2a49128f0a6edee337174ea341c1d6d7565be350
+
+The driver sets up the hardware to accept a frame with max length
+equal to MTU + Ethernet header + FCS + VLAN tag, but we neglect to
+add the VLAN tag size to the ingress buffer.  When a VLAN-tagged
+frame arrives, the hardware passes it, but bad things happen
+because the buffer is too small.  This patch fixes that.
+
+Thanks to David Harris for reporting the bug and testing the fix.
+
+Signed-off-by: Jay Cliburn <jacliburn@bellsouth.net>
+Tested-by: David Harris <david.harris@cpni-inc.com>
+Signed-off-by: Jeff Garzik <jeff@garzik.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/atl1/atl1_main.c |    8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/atl1/atl1_main.c
++++ b/drivers/net/atl1/atl1_main.c
+@@ -121,7 +121,7 @@ static int __devinit atl1_sw_init(struct
+       struct atl1_hw *hw = &adapter->hw;
+       struct net_device *netdev = adapter->netdev;
+-      hw->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
++      hw->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+       hw->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+       adapter->wol = 0;
+@@ -689,7 +689,7 @@ static int atl1_change_mtu(struct net_de
+ {
+       struct atl1_adapter *adapter = netdev_priv(netdev);
+       int old_mtu = netdev->mtu;
+-      int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
++      int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+       if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
+           (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+@@ -854,8 +854,8 @@ static u32 atl1_configure(struct atl1_ad
+       /* set Interrupt Clear Timer */
+       iowrite16(adapter->ict, hw->hw_addr + REG_CMBDISDMA_TIMER);
+-      /* set MTU, 4 : VLAN */
+-      iowrite32(hw->max_frame_size + 4, hw->hw_addr + REG_MTU);
++      /* set max frame size hw will accept */
++      iowrite32(hw->max_frame_size, hw->hw_addr + REG_MTU);
+       /* jumbo size & rrd retirement timer */
+       value = (((u32) hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK)
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:49 2008
+Message-Id: <20080206234449.663500496@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:14 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ linux-acpi@vger.kernel.org,
+ Len Brown <len.brown@intel.com>
+Subject: [patch 72/73] ACPI: sync blacklist w/ latest
+Content-Disposition: inline; filename=acpi-sync-blacklist-w-latest.patch
+Content-Length: 21235
+Lines: 721
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Len Brown <len.brown@intel.com>
+
+This patch is appropriate for supporting a 2.6.23-based products.
+
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/blacklist.c  |  388 +++++++++++++++++++++++++++++++++++++++++++++-
+ drivers/acpi/osl.c        |  173 +++++++++++++++-----
+ drivers/firmware/dmi-id.c |    2 
+ include/linux/acpi.h      |    7 
+ include/linux/dmi.h       |    2 
+ 5 files changed, 523 insertions(+), 49 deletions(-)
+
+--- a/drivers/acpi/blacklist.c
++++ b/drivers/acpi/blacklist.c
+@@ -3,6 +3,7 @@
+  *
+  *  Check to see if the given machine has a known bad ACPI BIOS
+  *  or if the BIOS is too old.
++ *  Check given machine against acpi_osi_dmi_table[].
+  *
+  *  Copyright (C) 2004 Len Brown <len.brown@intel.com>
+  *  Copyright (C) 2002 Andy Grover <andrew.grover@intel.com>
+@@ -50,6 +51,8 @@ struct acpi_blacklist_item {
+       u32 is_critical_error;
+ };
++static struct dmi_system_id acpi_osi_dmi_table[] __initdata;
++
+ /*
+  * POLICY: If *anything* doesn't work, put it on the blacklist.
+  *       If they are critical errors, mark it critical, and abort driver load.
+@@ -67,8 +70,6 @@ static struct acpi_blacklist_item acpi_b
+       /* IBM 600E - _ADR should return 7, but it returns 1 */
+       {"IBM   ", "TP600E  ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
+        "Incorrect _ADR", 1},
+-      {"ASUS\0\0", "P2B-S   ", 0, ACPI_SIG_DSDT, all_versions,
+-       "Bogus PCI routing", 1},
+       {""}
+ };
+@@ -165,5 +166,388 @@ int __init acpi_blacklisted(void)
+       blacklisted += blacklist_by_year();
++      dmi_check_system(acpi_osi_dmi_table);
++
+       return blacklisted;
+ }
++#ifdef CONFIG_DMI
++static int __init dmi_enable_osi_linux(struct dmi_system_id *d)
++{
++      acpi_dmi_osi_linux(1, d);       /* enable */
++      return 0;
++}
++static int __init dmi_disable_osi_linux(struct dmi_system_id *d)
++{
++      acpi_dmi_osi_linux(0, d);       /* disable */
++      return 0;
++}
++static int __init dmi_unknown_osi_linux(struct dmi_system_id *d)
++{
++      acpi_dmi_osi_linux(-1, d);      /* unknown */
++      return 0;
++}
++
++/*
++ * Most BIOS that invoke OSI(Linux) do nothing with it.
++ * But some cause Linux to break.
++ * Only a couple use it to make Linux run better.
++ *
++ * Thus, Linux should continue to disable OSI(Linux) by default,
++ * should continue to discourage BIOS writers from using it, and
++ * should whitelist the few existing systems that require it.
++ *
++ * If it appears clear a vendor isn't using OSI(Linux)
++ * for anything constructive, blacklist them by name to disable
++ * unnecessary dmesg warnings on all of their products.
++ */
++
++static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
++      /*
++       * Disable OSI(Linux) warnings on all "Acer, inc."
++       *
++       * _OSI(Linux) disables the latest Windows BIOS code:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5050"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5580"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 3010"),
++       * _OSI(Linux) effect unknown:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Ferrari 5000"),
++       */
++      /*
++       * note that dmi_check_system() uses strstr()
++       * to match sub-strings rather than !strcmp(),
++       * so "Acer" below matches "Acer, inc." above.
++       */
++      /*
++       * Disable OSI(Linux) warnings on all "Acer"
++       *
++       * _OSI(Linux) effect unknown:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720Z"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"),
++       */
++      {
++      .callback = dmi_unknown_osi_linux,
++      .ident = "Acer",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
++              },
++      },
++      /*
++       * Disable OSI(Linux) warnings on all "Apple Computer, Inc."
++       *
++       * _OSI(Linux) confirmed to be a NOP:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
++       * _OSI(Linux) effect unknown:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "MacPro2,1"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
++       */
++      {
++      .callback = dmi_disable_osi_linux,
++      .ident = "Apple",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
++              },
++      },
++      /*
++       * Disable OSI(Linux) warnings on all "BenQ"
++       *
++       * _OSI(Linux) confirmed to be a NOP:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Joybook S31"),
++       */
++      {
++      .callback = dmi_disable_osi_linux,
++      .ident = "BenQ",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "BenQ"),
++              },
++      },
++      /*
++       * Disable OSI(Linux) warnings on all "Clevo Co."
++       *
++       * _OSI(Linux) confirmed to be a NOP:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "M570RU"),
++       */
++      {
++      .callback = dmi_disable_osi_linux,
++      .ident = "Clevo",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Clevo Co."),
++              },
++      },
++      /*
++       * Disable OSI(Linux) warnings on all "COMPAL"
++       *
++       * _OSI(Linux) confirmed to be a NOP:
++       * DMI_MATCH(DMI_BOARD_NAME, "HEL8X"),
++       * _OSI(Linux) unknown effect:
++       * DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
++       */
++      {
++      .callback = dmi_unknown_osi_linux,
++      .ident = "Compal",
++      .matches = {
++                   DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
++              },
++      },
++      { /* OSI(Linux) touches USB, unknown side-effect */
++      .callback = dmi_disable_osi_linux,
++      .ident = "Dell Dimension 5150",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++                   DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM051"),
++              },
++      },
++      { /* OSI(Linux) is a NOP */
++      .callback = dmi_disable_osi_linux,
++      .ident = "Dell",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++                   DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1501"),
++              },
++      },
++      { /* OSI(Linux) effect unknown */
++      .callback = dmi_unknown_osi_linux,
++      .ident = "Dell",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++                   DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D830"),
++              },
++      },
++      { /* OSI(Linux) effect unknown */
++      .callback = dmi_unknown_osi_linux,
++      .ident = "Dell",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++                   DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX620"),
++              },
++      },
++      { /* OSI(Linux) effect unknown */
++      .callback = dmi_unknown_osi_linux,
++      .ident = "Dell",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++                   DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1900"),
++              },
++      },
++      { /* OSI(Linux) touches USB */
++      .callback = dmi_disable_osi_linux,
++      .ident = "Dell",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++                   DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 390"),
++              },
++      },
++      { /* OSI(Linux) is a NOP */
++      .callback = dmi_disable_osi_linux,
++      .ident = "Dell Vostro 1000",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++                   DMI_MATCH(DMI_PRODUCT_NAME, "Vostro   1000"),
++              },
++      },
++      { /* OSI(Linux) effect unknown */
++      .callback = dmi_unknown_osi_linux,
++      .ident = "Dell",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++                   DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge SC440"),
++              },
++      },
++      { /* OSI(Linux) effect unknown */
++      .callback = dmi_unknown_osi_linux,
++      .ident = "Dialogue Flybook V5",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Dialogue Technology Corporation"),
++                   DMI_MATCH(DMI_PRODUCT_NAME, "Flybook V5"),
++              },
++      },
++      /*
++       * Disable OSI(Linux) warnings on all "FUJITSU SIEMENS"
++       *
++       * _OSI(Linux) disables latest Windows BIOS code:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2510"),
++       * _OSI(Linux) confirmed to be a NOP:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 1536"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 1556"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 1546"),
++       * _OSI(Linux) unknown effect:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Amilo M1425"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Amilo Si 1520"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"),
++       */
++      {
++      .callback = dmi_disable_osi_linux,
++      .ident = "Fujitsu Siemens",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
++              },
++      },
++      /*
++       * Disable OSI(Linux) warnings on all "Hewlett-Packard"
++       *
++       * _OSI(Linux) confirmed to be a NOP:
++       * .ident = "HP Pavilion tx 1000"
++       * DMI_MATCH(DMI_BOARD_NAME, "30BF"),
++       * .ident = "HP Pavilion dv2000"
++       * DMI_MATCH(DMI_BOARD_NAME, "30B5"),
++       * .ident = "HP Pavilion dv5000",
++       * DMI_MATCH(DMI_BOARD_NAME, "30A7"),
++       * .ident = "HP Pavilion dv6300 30BC",
++       * DMI_MATCH(DMI_BOARD_NAME, "30BC"),
++       * .ident = "HP Pavilion dv6000",
++       * DMI_MATCH(DMI_BOARD_NAME, "30B7"),
++       * DMI_MATCH(DMI_BOARD_NAME, "30B8"),
++       * .ident = "HP Pavilion dv9000",
++       * DMI_MATCH(DMI_BOARD_NAME, "30B9"),
++       * .ident = "HP Pavilion dv9500",
++       * DMI_MATCH(DMI_BOARD_NAME, "30CB"),
++       * .ident = "HP/Compaq Presario C500",
++       * DMI_MATCH(DMI_BOARD_NAME, "30C6"),
++       * .ident = "HP/Compaq Presario F500",
++       * DMI_MATCH(DMI_BOARD_NAME, "30D3"),
++       * _OSI(Linux) unknown effect:
++       * .ident = "HP Pavilion dv6500",
++       * DMI_MATCH(DMI_BOARD_NAME, "30D0"),
++       */
++      {
++      .callback = dmi_disable_osi_linux,
++      .ident = "Hewlett-Packard",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
++              },
++      },
++      /*
++       * Lenovo has a mix of systems OSI(Linux) situations
++       * and thus we can not wildcard the vendor.
++       *
++       * _OSI(Linux) helps sound
++       * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
++       * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
++       * _OSI(Linux) is a NOP:
++       * DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
++       */
++      {
++      .callback = dmi_enable_osi_linux,
++      .ident = "Lenovo ThinkPad R61",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
++                   DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
++              },
++      },
++      {
++      .callback = dmi_enable_osi_linux,
++      .ident = "Lenovo ThinkPad T61",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
++                   DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
++              },
++      },
++      {
++      .callback = dmi_unknown_osi_linux,
++      .ident = "Lenovo 3000 V100",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
++                   DMI_MATCH(DMI_PRODUCT_VERSION, "LENOVO3000 V100"),
++              },
++      },
++      {
++      .callback = dmi_disable_osi_linux,
++      .ident = "Lenovo 3000 N100",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
++                   DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
++              },
++      },
++      /*
++       * Disable OSI(Linux) warnings on all "LG Electronics"
++       *
++       * _OSI(Linux) confirmed to be a NOP:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "P1-J150B"),
++       * with DMI_MATCH(DMI_BOARD_NAME, "ROCKY"),
++       *
++       * unknown:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "S1-MDGDG"),
++       * with DMI_MATCH(DMI_BOARD_NAME, "ROCKY"),
++       */
++      {
++      .callback = dmi_disable_osi_linux,
++      .ident = "LG",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
++              },
++      },
++      /* NEC - OSI(Linux) effect unknown */
++      {
++      .callback = dmi_unknown_osi_linux,
++      .ident = "NEC VERSA M360",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "NEC Computers SAS"),
++                   DMI_MATCH(DMI_PRODUCT_NAME, "NEC VERSA M360"),
++              },
++      },
++      /*
++       * Disable OSI(Linux) warnings on all "Samsung Electronics"
++       *
++       * OSI(Linux) disables PNP0C32 and other BIOS code for Windows:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "R40P/R41P"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "R59P/R60P/R61P"),
++       */
++      {
++      .callback = dmi_disable_osi_linux,
++      .ident = "Samsung",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
++              },
++      },
++      /*
++       * Disable OSI(Linux) warnings on all "Sony Corporation"
++       *
++       * _OSI(Linux) is a NOP:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SZ650N"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SZ38GP_C"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-TZ21MN_N"),
++       * _OSI(Linux) unknown effect:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"),
++       */
++      {
++      .callback = dmi_unknown_osi_linux,
++      .ident = "Sony",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
++              },
++      },
++      /*
++       * Disable OSI(Linux) warnings on all "TOSHIBA"
++       *
++       * _OSI(Linux) breaks sound (bugzilla 7787):
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P100"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P105"),
++       * _OSI(Linux) is a NOP:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A100"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A210"),
++       * _OSI(Linux) unknown effect:
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A135"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A200"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P205"),
++       * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U305"),
++       */
++      {
++      .callback = dmi_disable_osi_linux,
++      .ident = "Toshiba",
++      .matches = {
++                   DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
++              },
++      },
++      {}
++};
++
++#endif /* CONFIG_DMI */
+--- a/drivers/acpi/osl.c
++++ b/drivers/acpi/osl.c
+@@ -77,11 +77,55 @@ static struct workqueue_struct *kacpi_no
+ #define       OSI_STRING_LENGTH_MAX 64        /* arbitrary */
+ static char osi_additional_string[OSI_STRING_LENGTH_MAX];
+-static int osi_linux;         /* disable _OSI(Linux) by default */
++/*
++ * "Ode to _OSI(Linux)"
++ *
++ * osi_linux -- Control response to BIOS _OSI(Linux) query.
++ *
++ * As Linux evolves, the features that it supports change.
++ * So an OSI string such as "Linux" is not specific enough
++ * to be useful across multiple versions of Linux.  It
++ * doesn't identify any particular feature, interface,
++ * or even any particular version of Linux...
++ *
++ * Unfortunately, Linux-2.6.22 and earlier responded "yes"
++ * to a BIOS _OSI(Linux) query.  When
++ * a reference mobile BIOS started using it, its use
++ * started to spread to many vendor platforms.
++ * As it is not supportable, we need to halt that spread.
++ *
++ * Today, most BIOS references to _OSI(Linux) are noise --
++ * they have no functional effect and are just dead code
++ * carried over from the reference BIOS.
++ *
++ * The next most common case is that _OSI(Linux) harms Linux,
++ * usually by causing the BIOS to follow paths that are
++ * not tested during Windows validation.
++ *
++ * Finally, there is a short list of platforms
++ * where OSI(Linux) benefits Linux.
++ *
++ * In Linux-2.6.23, OSI(Linux) is first disabled by default.
++ * DMI is used to disable the dmesg warning about OSI(Linux)
++ * on platforms where it is known to have no effect.
++ * But a dmesg warning remains for systems where
++ * we do not know if OSI(Linux) is good or bad for the system.
++ * DMI is also used to enable OSI(Linux) for the machines
++ * that are known to need it.
++ *
++ * BIOS writers should NOT query _OSI(Linux) on future systems.
++ * It will be ignored by default, and to get Linux to
++ * not ignore it will require a kernel source update to
++ * add a DMI entry, or a boot-time "acpi_osi=Linux" invocation.
++ */
++#define OSI_LINUX_ENABLE 0
+-#ifdef CONFIG_DMI
+-static struct __initdata dmi_system_id acpi_osl_dmi_table[];
+-#endif
++static struct osi_linux {
++      unsigned int    enable:1;
++      unsigned int    dmi:1;
++      unsigned int    cmdline:1;
++      unsigned int    known:1;
++} osi_linux = { OSI_LINUX_ENABLE, 0, 0, 0};
+ static void __init acpi_request_region (struct acpi_generic_address *addr,
+       unsigned int length, char *desc)
+@@ -133,7 +177,6 @@ device_initcall(acpi_reserve_resources);
+ acpi_status __init acpi_os_initialize(void)
+ {
+-      dmi_check_system(acpi_osl_dmi_table);
+       return AE_OK;
+ }
+@@ -971,13 +1014,37 @@ static int __init acpi_os_name_setup(cha
+ __setup("acpi_os_name=", acpi_os_name_setup);
+-static void enable_osi_linux(int enable) {
++static void __init set_osi_linux(unsigned int enable)
++{
++      if (osi_linux.enable != enable) {
++              osi_linux.enable = enable;
++              printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
++                      enable ? "Add": "Delet");
++      }
++      return;
++}
+-      if (osi_linux != enable)
+-              printk(KERN_INFO PREFIX "%sabled _OSI(Linux)\n",
+-                      enable ? "En": "Dis");
++static void __init acpi_cmdline_osi_linux(unsigned int enable)
++{
++      osi_linux.cmdline = 1;  /* cmdline set the default */
++      set_osi_linux(enable);
++
++      return;
++}
++
++void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
++{
++      osi_linux.dmi = 1;      /* DMI knows that this box asks OSI(Linux) */
++
++      printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
++
++      if (enable == -1)
++              return;
++
++      osi_linux.known = 1;    /* DMI knows which OSI(Linux) default needed */
++
++      set_osi_linux(enable);
+-      osi_linux = enable;
+       return;
+ }
+@@ -994,12 +1061,12 @@ static int __init acpi_osi_setup(char *s
+               printk(KERN_INFO PREFIX "_OSI method disabled\n");
+               acpi_gbl_create_osi_method = FALSE;
+       } else if (!strcmp("!Linux", str)) {
+-              enable_osi_linux(0);
++              acpi_cmdline_osi_linux(0);      /* !enable */
+       } else if (*str == '!') {
+               if (acpi_osi_invalidate(++str) == AE_OK)
+                       printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
+       } else if (!strcmp("Linux", str)) {
+-              enable_osi_linux(1);
++              acpi_cmdline_osi_linux(1);      /* enable */
+       } else if (*osi_additional_string == '\0') {
+               strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX);
+               printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
+@@ -1156,6 +1223,34 @@ acpi_status acpi_os_release_object(acpi_
+       return (AE_OK);
+ }
++/**
++ *    acpi_dmi_dump - dump DMI slots needed for blacklist entry
++ *
++ *    Returns 0 on success
++ */
++static int acpi_dmi_dump(void)
++{
++
++      if (!dmi_available)
++              return -1;
++
++      printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n",
++              dmi_get_system_info(DMI_SYS_VENDOR));
++      printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n",
++              dmi_get_system_info(DMI_PRODUCT_NAME));
++      printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n",
++              dmi_get_system_info(DMI_PRODUCT_VERSION));
++      printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n",
++              dmi_get_system_info(DMI_BOARD_NAME));
++      printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n",
++              dmi_get_system_info(DMI_BIOS_VENDOR));
++      printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n",
++              dmi_get_system_info(DMI_BIOS_DATE));
++
++      return 0;
++}
++
++
+ /******************************************************************************
+  *
+  * FUNCTION:    acpi_os_validate_interface
+@@ -1175,13 +1270,29 @@ acpi_os_validate_interface (char *interf
+       if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX))
+               return AE_OK;
+       if (!strcmp("Linux", interface)) {
+-              printk(KERN_WARNING PREFIX
+-                      "System BIOS is requesting _OSI(Linux)\n");
+-              printk(KERN_WARNING PREFIX
+-                      "If \"acpi_osi=Linux\" works better,\n"
+-                      "Please send dmidecode "
+-                      "to linux-acpi@vger.kernel.org\n");
+-              if(osi_linux)
++
++              printk(KERN_NOTICE PREFIX
++                      "BIOS _OSI(Linux) query %s%s\n",
++                      osi_linux.enable ? "honored" : "ignored",
++                      osi_linux.cmdline ? " via cmdline" :
++                      osi_linux.dmi ? " via DMI" : "");
++
++              if (!osi_linux.dmi) {
++                      if (acpi_dmi_dump())
++                              printk(KERN_NOTICE PREFIX
++                                      "[please extract dmidecode output]\n");
++                      printk(KERN_NOTICE PREFIX
++                              "Please send DMI info above to "
++                              "linux-acpi@vger.kernel.org\n");
++              }
++              if (!osi_linux.known && !osi_linux.cmdline) {
++                      printk(KERN_NOTICE PREFIX
++                              "If \"acpi_osi=%sLinux\" works better, "
++                              "please notify linux-acpi@vger.kernel.org\n",
++                              osi_linux.enable ? "!" : "");
++              }
++
++              if (osi_linux.enable)
+                       return AE_OK;
+       }
+       return AE_SUPPORT;
+@@ -1213,28 +1324,4 @@ acpi_os_validate_address (
+     return AE_OK;
+ }
+-#ifdef CONFIG_DMI
+-static int dmi_osi_linux(struct dmi_system_id *d)
+-{
+-      printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
+-      enable_osi_linux(1);
+-      return 0;
+-}
+-
+-static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
+-      /*
+-       * Boxes that need _OSI(Linux)
+-       */
+-      {
+-       .callback = dmi_osi_linux,
+-       .ident = "Intel Napa CRB",
+-       .matches = {
+-                   DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
+-                   DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
+-                   },
+-       },
+-      {}
+-};
+-#endif /* CONFIG_DMI */
+-
+ #endif
+--- a/drivers/firmware/dmi-id.c
++++ b/drivers/firmware/dmi-id.c
+@@ -159,8 +159,6 @@ static struct device *dmi_dev;
+       if (dmi_get_system_info(_field)) \
+               sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr;
+-extern int dmi_available;
+-
+ static int __init dmi_id_init(void)
+ {
+       int ret, i;
+--- a/include/linux/acpi.h
++++ b/include/linux/acpi.h
+@@ -40,6 +40,7 @@
+ #include <acpi/acpi_drivers.h>
+ #include <acpi/acpi_numa.h>
+ #include <asm/acpi.h>
++#include <linux/dmi.h>
+ #ifdef CONFIG_ACPI
+@@ -187,7 +188,9 @@ extern int ec_transaction(u8 command,
+ #endif /*CONFIG_ACPI_EC*/
+ extern int acpi_blacklisted(void);
+-extern void acpi_bios_year(char *s);
++#ifdef CONFIG_DMI
++extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d);
++#endif
+ #define       ACPI_CSTATE_LIMIT_DEFINED       /* for driver builds */
+ #ifdef        CONFIG_ACPI
+@@ -247,5 +250,5 @@ static inline int acpi_boot_table_init(v
+       return 0;
+ }
+-#endif        /* CONFIG_ACPI */
++#endif        /* !CONFIG_ACPI */
+ #endif        /*_LINUX_ACPI_H*/
+--- a/include/linux/dmi.h
++++ b/include/linux/dmi.h
+@@ -78,6 +78,7 @@ extern struct dmi_device * dmi_find_devi
+ extern void dmi_scan_machine(void);
+ extern int dmi_get_year(int field);
+ extern int dmi_name_in_vendors(char *str);
++extern int dmi_available;
+ #else
+@@ -87,6 +88,7 @@ static inline struct dmi_device * dmi_fi
+       struct dmi_device *from) { return NULL; }
+ static inline int dmi_get_year(int year) { return 0; }
+ static inline int dmi_name_in_vendors(char *s) { return 0; }
++#define dmi_available 0
+ #endif
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:50 2008
+Message-Id: <20080206234449.885545885@mini.kroah.org>
+References: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:44:15 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ linux-pci@atrey.karlin.mff.cuni.cz,
+ Ian Abbott <abbotti@mev.co.uk>
+Subject: [patch 73/73] PCI: Fix fakephp deadlock
+Content-Disposition: inline; filename=pci-fix-fakephp-deadlock.patch
+Content-Length: 3994
+Lines: 133
+
+
+2.6.23-stable review patch.  If anyone has any objections, please let us know.
+------------------
+From: Ian Abbott <abbotti@mev.co.uk>
+
+This patch works around a problem in the fakephp driver when a process
+writing "0" to a "power" sysfs file to fake removal of a PCI device ends
+up deadlocking itself in the sysfs code.
+
+The patch is functionally identical to the one in Linus' tree post 2.6.24:
+http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=5c796ae7a7ebe56967ed9b9963d7c16d733635ff
+
+I have tested it on a 2.6.23 kernel.
+
+Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/pci/hotplug/fakephp.c |   39 +++++++++++++++++++++++++++++++++++----
+ 1 file changed, 35 insertions(+), 4 deletions(-)
+
+--- a/drivers/pci/hotplug/fakephp.c
++++ b/drivers/pci/hotplug/fakephp.c
+@@ -39,6 +39,7 @@
+ #include <linux/init.h>
+ #include <linux/string.h>
+ #include <linux/slab.h>
++#include <linux/workqueue.h>
+ #include "../pci.h"
+ #if !defined(MODULE)
+@@ -63,10 +64,16 @@ struct dummy_slot {
+       struct list_head node;
+       struct hotplug_slot *slot;
+       struct pci_dev *dev;
++      struct work_struct remove_work;
++      unsigned long removed;
+ };
+ static int debug;
+ static LIST_HEAD(slot_list);
++static struct workqueue_struct *dummyphp_wq;
++
++static void pci_rescan_worker(struct work_struct *work);
++static DECLARE_WORK(pci_rescan_work, pci_rescan_worker);
+ static int enable_slot (struct hotplug_slot *slot);
+ static int disable_slot (struct hotplug_slot *slot);
+@@ -109,7 +116,7 @@ static int add_slot(struct pci_dev *dev)
+       slot->name = &dev->dev.bus_id[0];
+       dbg("slot->name = %s\n", slot->name);
+-      dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL);
++      dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL);
+       if (!dslot)
+               goto error_info;
+@@ -164,6 +171,14 @@ static void remove_slot(struct dummy_slo
+               err("Problem unregistering a slot %s\n", dslot->slot->name);
+ }
++/* called from the single-threaded workqueue handler to remove a slot */
++static void remove_slot_worker(struct work_struct *work)
++{
++      struct dummy_slot *dslot =
++              container_of(work, struct dummy_slot, remove_work);
++      remove_slot(dslot);
++}
++
+ /**
+  * Rescan slot.
+  * Tries hard not to re-enable already existing devices
+@@ -267,11 +282,17 @@ static inline void pci_rescan(void) {
+       pci_rescan_buses(&pci_root_buses);
+ }
++/* called from the single-threaded workqueue handler to rescan all pci buses */
++static void pci_rescan_worker(struct work_struct *work)
++{
++      pci_rescan();
++}
+ static int enable_slot(struct hotplug_slot *hotplug_slot)
+ {
+       /* mis-use enable_slot for rescanning of the pci bus */
+-      pci_rescan();
++      cancel_work_sync(&pci_rescan_work);
++      queue_work(dummyphp_wq, &pci_rescan_work);
+       return -ENODEV;
+ }
+@@ -306,6 +327,10 @@ static int disable_slot(struct hotplug_s
+               err("Can't remove PCI devices with other PCI devices behind it yet.\n");
+               return -ENODEV;
+       }
++      if (test_and_set_bit(0, &dslot->removed)) {
++              dbg("Slot already scheduled for removal\n");
++              return -ENODEV;
++      }
+       /* search for subfunctions and disable them first */
+       if (!(dslot->dev->devfn & 7)) {
+               for (func = 1; func < 8; func++) {
+@@ -328,8 +353,9 @@ static int disable_slot(struct hotplug_s
+       /* remove the device from the pci core */
+       pci_remove_bus_device(dslot->dev);
+-      /* blow away this sysfs entry and other parts. */
+-      remove_slot(dslot);
++      /* queue work item to blow away this sysfs entry and other parts. */
++      INIT_WORK(&dslot->remove_work, remove_slot_worker);
++      queue_work(dummyphp_wq, &dslot->remove_work);
+       return 0;
+ }
+@@ -340,6 +366,7 @@ static void cleanup_slots (void)
+       struct list_head *next;
+       struct dummy_slot *dslot;
++      destroy_workqueue(dummyphp_wq);
+       list_for_each_safe (tmp, next, &slot_list) {
+               dslot = list_entry (tmp, struct dummy_slot, node);
+               remove_slot(dslot);
+@@ -351,6 +378,10 @@ static int __init dummyphp_init(void)
+ {
+       info(DRIVER_DESC "\n");
++      dummyphp_wq = create_singlethread_workqueue(MY_NAME);
++      if (!dummyphp_wq)
++              return -ENOMEM;
++
+       return pci_scan_buses();
+ }
+
+-- 
+
+From gregkh@mini.kroah.org Wed Feb  6 15:44:33 2008
+Message-Id: <20080206234302.769849277@mini.kroah.org>
+User-Agent: quilt/0.46-1
+Date: Wed, 06 Feb 2008 15:43:02 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: Justin Forbes <jmforbes@linuxtx.org>,
+ Zwane Mwaikambo <zwane@arm.linux.org.uk>,
+ Theodore Ts'o <tytso@mit.edu>,
+ Randy Dunlap <rdunlap@xenotime.net>,
+ Dave Jones <davej@redhat.com>,
+ Chuck Wolber <chuckw@quantumlinux.com>,
+ Chris Wedgwood <reviews@ml.cw.f00f.org>,
+ Michael Krufky <mkrufky@linuxtv.org>,
+ Chuck Ebbert <cebbert@redhat.com>,
+ Domenico Andreoli <cavokz@gmail.com>,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk
+Subject: [patch 00/73] 2.6.23-stable review
+Content-Length: 819
+Lines: 20
+
+This is the start of the stable review cycle for the 2.6.23.15 release.
+There are 73 patches in this series, all will be posted as a response to
+this one.  If anyone has any issues with these being applied, please let
+us know.  If anyone is a maintainer of the proper subsystem, and wants
+to add a Signed-off-by: line to the patch, please respond with it.
+
+These patches are sent out with a number of different people on the Cc:
+line.  If you wish to be a reviewer, please email stable@kernel.org to
+add your name to the list.  If you want to be off the reviewer list,
+also email us.
+
+Responses should be made by Friday, Feb 8 2008 12:00:00 UTC.  Anything
+received after that time might be too late.
+
+Note, this is going to be one of the last .23-stable releases, unless
+something major comes along.
+
+thanks,
+
+greg k-h
+