--- /dev/null
+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
+