]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
more stable patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Wed, 7 Mar 2007 00:29:30 +0000 (16:29 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 7 Mar 2007 00:29:30 +0000 (16:29 -0800)
queue-2.6.20/agp-intel-agp-bugfix.patch [new file with mode: 0644]
queue-2.6.20/fix-various-bugs-with-aligned-reads-in-raid5.patch [new file with mode: 0644]
queue-2.6.20/hda-intel-don-t-try-to-probe-invalid-codecs.patch [new file with mode: 0644]
queue-2.6.20/libata-fix-drive-side-80c-cable-check.patch [new file with mode: 0644]
queue-2.6.20/missing-critical-phys_to_virt-in-lib-swiotlb.c.patch [new file with mode: 0644]
queue-2.6.20/series
queue-2.6.20/usb-audio-fixes-1.patch [new file with mode: 0644]
queue-2.6.20/usb-audio-fixes-2.patch [new file with mode: 0644]
queue-2.6.20/usb-fix-concurrent-buffer-access-in-the-hub-driver.patch [new file with mode: 0644]

diff --git a/queue-2.6.20/agp-intel-agp-bugfix.patch b/queue-2.6.20/agp-intel-agp-bugfix.patch
new file mode 100644 (file)
index 0000000..c99cf5d
--- /dev/null
@@ -0,0 +1,75 @@
+From stable-bounces@linux.kernel.org Sun Feb  4 14:40:37 2007
+Date: Sun, 4 Feb 2007 12:18:50 -0500
+From: Dave Jones <davej@redhat.com>
+To: Eric Piel <Eric.Piel@tremplin-utc.net>
+Cc: Wang Zhenyu <zhenyu.z.wang@intel.com>, linux-kernel@vger.kernel.org, Adrian Bunk <bunk@stusta.de>
+Subject: AGP: intel-agp bugfix
+Message-ID: <20070204171850.GA17171@redhat.com>
+
+From: Dave Jones <davej@redhat.com>
+
+On Sun, Feb 04, 2007 at 04:51:38PM +0100, Eric Piel wrote:
+ > Hello,
+ > 
+ > I've got a regression in 2.6.20-rc7 (-rc6 was fine) due to commit 
+ > 4b95320fc4d21b0ff2f8604305dd6c851aff6096 ([AGPGART] intel_agp: restore 
+ > graphics device's pci space early in resume).
+
+I think the key to this failure is the last line here ..
+
+ > agpgart-intel 0000:00:00.0: resuming
+ > PM: Writing back config space on device 0000:00:02.0 at offset f (was 10b, writing 0)
+ > PM: Writing back config space on device 0000:00:02.0 at offset d (was dc, writing 0)
+ > PM: Writing back config space on device 0000:00:02.0 at offset b (was 10161025, writing 0)
+ > PM: Writing back config space on device 0000:00:02.0 at offset 5 (was f4000000, writing 0)
+ > PM: Writing back config space on device 0000:00:02.0 at offset 4 (was f8000008, writing 0)
+ > PM: Writing back config space on device 0000:00:02.0 at offset 2 (was 3000011, writing 0)
+ > PM: Writing back config space on device 0000:00:02.0 at offset 1 (was 2b00007, writing 0)
+ > PM: Writing back config space on device 0000:00:02.0 at offset 0 (was 11328086, writing 0)
+ > agpgart: Unable to remap memory.
+
+This then blows up the next access to intel_i810_private.registers, which happens to
+be intel_i810_insert_entries.
+
+Either we need .suspend methods which unmap these regions, or we need
+to skip trying to map them a second time on resume.
+
+There's an ugly patch below which does the latter. Give it a try?
+
+The intel-agp suspend/resume code has really grown into something
+of a monster, and could use some refactoring in a big way.
+
+               Dave
+
+
+From: Dave Jones <davej@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/agp/intel-agp.c |   14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+--- linux-2.6.20.1.orig/drivers/char/agp/intel-agp.c
++++ linux-2.6.20.1/drivers/char/agp/intel-agp.c
+@@ -117,13 +117,15 @@ static int intel_i810_configure(void)
+       current_size = A_SIZE_FIX(agp_bridge->current_size);
+-      pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp);
+-      temp &= 0xfff80000;
+-
+-      intel_i810_private.registers = ioremap(temp, 128 * 4096);
+       if (!intel_i810_private.registers) {
+-              printk(KERN_ERR PFX "Unable to remap memory.\n");
+-              return -ENOMEM;
++              pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp);
++              temp &= 0xfff80000;
++
++              intel_i810_private.registers = ioremap(temp, 128 * 4096);
++              if (!intel_i810_private.registers) {
++                      printk(KERN_ERR PFX "Unable to remap memory.\n");
++                      return -ENOMEM;
++              }
+       }
+       if ((readl(intel_i810_private.registers+I810_DRAM_CTL)
diff --git a/queue-2.6.20/fix-various-bugs-with-aligned-reads-in-raid5.patch b/queue-2.6.20/fix-various-bugs-with-aligned-reads-in-raid5.patch
new file mode 100644 (file)
index 0000000..68c4ea8
--- /dev/null
@@ -0,0 +1,116 @@
+From stable-bounces@linux.kernel.org Tue Feb  6 15:45:04 2007
+From: Neil Brown <neilb@suse.de>
+Date: Wed, 7 Feb 2007 10:26:56 +1100
+Subject: Fix various bugs with aligned reads in RAID5.
+To: "Kai" <epimetreus@fastmail.fm>, Andrew Morton <akpm@linux-foundation.org>, stable@kernel.org
+Cc: linux-kernel@vger.kernel.org, Jens Axboe <jens.axboe@oracle.com>
+Message-ID: <17865.3776.511594.763544@notabene.brown>
+
+From: Neil Brown <neilb@suse.de>
+
+Fix various bugs with aligned reads in RAID5.
+
+It is possible for raid5 to be sent a bio that is too big
+for an underlying device.  So if it is a READ that we
+pass stright down to a device, it will fail and confuse
+RAID5.
+
+So in 'chunk_aligned_read' we check that the bio fits within the
+parameters for the target device and if it doesn't fit, fall back
+on reading through the stripe cache and making lots of one-page
+requests.
+
+Note that this is the earliest time we can check against the device
+because earlier we don't have a lock on the device, so it could change
+underneath us.
+
+Also, the code for handling a retry through the cache when a read
+fails has not been tested and was badly broken.  This patch fixes that
+code.
+
+Signed-off-by: Neil Brown <neilb@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/raid5.c |   42 +++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 39 insertions(+), 3 deletions(-)
+
+--- linux-2.6.20.1.orig/drivers/md/raid5.c
++++ linux-2.6.20.1/drivers/md/raid5.c
+@@ -2620,7 +2620,7 @@ static struct bio *remove_bio_from_retry
+       }
+       bi = conf->retry_read_aligned_list;
+       if(bi) {
+-              conf->retry_read_aligned = bi->bi_next;
++              conf->retry_read_aligned_list = bi->bi_next;
+               bi->bi_next = NULL;
+               bi->bi_phys_segments = 1; /* biased count of active stripes */
+               bi->bi_hw_segments = 0; /* count of processed stripes */
+@@ -2669,6 +2669,27 @@ static int raid5_align_endio(struct bio 
+       return 0;
+ }
++static int bio_fits_rdev(struct bio *bi)
++{
++      request_queue_t *q = bdev_get_queue(bi->bi_bdev);
++
++      if ((bi->bi_size>>9) > q->max_sectors)
++              return 0;
++      blk_recount_segments(q, bi);
++      if (bi->bi_phys_segments > q->max_phys_segments ||
++          bi->bi_hw_segments > q->max_hw_segments)
++              return 0;
++
++      if (q->merge_bvec_fn)
++              /* it's too hard to apply the merge_bvec_fn at this stage,
++               * just just give up
++               */
++              return 0;
++
++      return 1;
++}
++
++
+ static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio)
+ {
+       mddev_t *mddev = q->queuedata;
+@@ -2715,6 +2736,13 @@ static int chunk_aligned_read(request_qu
+               align_bi->bi_flags &= ~(1 << BIO_SEG_VALID);
+               align_bi->bi_sector += rdev->data_offset;
++              if (!bio_fits_rdev(align_bi)) {
++                      /* too big in some way */
++                      bio_put(align_bi);
++                      rdev_dec_pending(rdev, mddev);
++                      return 0;
++              }
++
+               spin_lock_irq(&conf->device_lock);
+               wait_event_lock_irq(conf->wait_for_stripe,
+                                   conf->quiesce == 0,
+@@ -3107,7 +3135,9 @@ static int  retry_aligned_read(raid5_con
+       last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9);
+       for (; logical_sector < last_sector;
+-           logical_sector += STRIPE_SECTORS, scnt++) {
++           logical_sector += STRIPE_SECTORS,
++                   sector += STRIPE_SECTORS,
++                   scnt++) {
+               if (scnt < raid_bio->bi_hw_segments)
+                       /* already done this stripe */
+@@ -3123,7 +3153,13 @@ static int  retry_aligned_read(raid5_con
+               }
+               set_bit(R5_ReadError, &sh->dev[dd_idx].flags);
+-              add_stripe_bio(sh, raid_bio, dd_idx, 0);
++              if (!add_stripe_bio(sh, raid_bio, dd_idx, 0)) {
++                      release_stripe(sh);
++                      raid_bio->bi_hw_segments = scnt;
++                      conf->retry_read_aligned = raid_bio;
++                      return handled;
++              }
++
+               handle_stripe(sh, NULL);
+               release_stripe(sh);
+               handled++;
diff --git a/queue-2.6.20/hda-intel-don-t-try-to-probe-invalid-codecs.patch b/queue-2.6.20/hda-intel-don-t-try-to-probe-invalid-codecs.patch
new file mode 100644 (file)
index 0000000..55ece81
--- /dev/null
@@ -0,0 +1,35 @@
+From stable-bounces@linux.kernel.org Tue Feb  6 10:16:59 2007
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 06 Feb 2007 19:15:26 +0100
+Subject: hda-intel - Don't try to probe invalid codecs
+To: stable@kernel.org
+Message-ID: <s5hzm7rup8h.wl%tiwai@suse.de>
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ALSA] hda-intel - Don't try to probe invalid codecs
+
+Fix the max number of codecs detected by HD-intel (and compatible)
+controllers to 3.  Some hardware reports extra bits as if
+connected, and the driver gets confused to probe unexisting codecs.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Jaroslav Kysela <perex@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ sound/pci/hda/hda_intel.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- linux-2.6.20.1.orig/sound/pci/hda/hda_intel.c
++++ linux-2.6.20.1/sound/pci/hda/hda_intel.c
+@@ -199,7 +199,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO
+ /* STATESTS int mask: SD2,SD1,SD0 */
+ #define STATESTS_INT_MASK     0x07
+-#define AZX_MAX_CODECS                4
++#define AZX_MAX_CODECS                3
+ /* SD_CTL bits */
+ #define SD_CTL_STREAM_RESET   0x01    /* stream reset bit */
diff --git a/queue-2.6.20/libata-fix-drive-side-80c-cable-check.patch b/queue-2.6.20/libata-fix-drive-side-80c-cable-check.patch
new file mode 100644 (file)
index 0000000..386ec36
--- /dev/null
@@ -0,0 +1,38 @@
+From stable-bounces@linux.kernel.org Mon Feb  5 06:22:51 2007
+From: Tejun Heo <htejun@gmail.com>
+Date: Mon, 5 Feb 2007 23:21:19 +0900
+Subject: libata: fix drive side 80c cable check
+To: Alan <alan@lxorguk.ukuu.org.uk>
+Cc: linux-ide@vger.kernel.org, stable@kernel.org, Jeff Garzik <jeff@garzik.org>
+Message-ID: <20070205142119.GM1625@htj.dyndns.org>
+Content-Disposition: inline
+
+
+From: Tejun Heo <htejun@gmail.com>
+
+The 80c wire bit is bit 13, not 14.  Bit 14 is always 1 if word93 is
+implemented.  This increases the chance of incorrect wire detection
+especially because host side cable detection is often unreliable and
+we sometimes soley depend on drive side cable detection.  Fix the test
+and add word93 validity check.
+
+Signed-off-by: Tejun Heo <htejun@gmail.com>
+Acked-by: Alan Cox <alan@redhat.com>
+Cc: Jeff Garzik <jeff@garzik.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/linux/ata.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- linux-2.6.20.1.orig/include/linux/ata.h
++++ linux-2.6.20.1/include/linux/ata.h
+@@ -347,7 +347,7 @@ static inline int ata_drive_40wire(const
+ {
+       if (ata_id_major_version(dev_id) >= 5 && ata_id_is_sata(dev_id))
+               return 0;       /* SATA */
+-      if (dev_id[93] & 0x4000)
++      if ((dev_id[93] & 0xE000) == 0x6000)
+               return 0;       /* 80 wire */
+       return 1;
+ }
diff --git a/queue-2.6.20/missing-critical-phys_to_virt-in-lib-swiotlb.c.patch b/queue-2.6.20/missing-critical-phys_to_virt-in-lib-swiotlb.c.patch
new file mode 100644 (file)
index 0000000..dbe6893
--- /dev/null
@@ -0,0 +1,44 @@
+From stable-bounces@linux.kernel.org Sun Feb  4 12:37:49 2007
+From: Stefan Richter <stefanr@s5r6.in-berlin.de>
+Date: Sun, 04 Feb 2007 21:36:15 +0100
+Subject: Missing critical phys_to_virt in lib/swiotlb.c
+To: stable@kernel.org
+Cc: discuss@x86-64.org, Jan Beulich <jbeulich@novell.com>, David Moore <dcm@MIT.EDU>, akpm@linux-foundation.org, linux1394-devel <linux1394-devel@lists.sourceforge.net>
+Message-ID: <45C643BF.80204@s5r6.in-berlin.de>
+
+From: Stefan Richter <stefanr@s5r6.in-berlin.de>
+
+David Moore wrote:
+[...]
+> considering the severity of this one-liner bug, I would like to
+> request that this simplified patch make it into 2.6.20, despite how
+> close we are to the final cut.
+
+So we were too close. Maybe the -stable team likes to have it in 2.6.20.1.
+
+> It fixes real crashes:
+> http://lists.opensuse.org/opensuse-bugs/2006-12/msg02943.html
+> http://qa.mandriva.com/show_bug.cgi?id=28224
+> http://www.pchdtv.com/forum/viewtopic.php?t=2063&sid=a959a14a4c2db0eebaab7b0df56103ce
+
+and FireWire crashes too.
+
+
+From: Stefan Richter <stefanr@s5r6.in-berlin.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ lib/swiotlb.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- linux-2.6.20.1.orig/lib/swiotlb.c
++++ linux-2.6.20.1/lib/swiotlb.c
+@@ -750,7 +750,7 @@ swiotlb_sync_sg(struct device *hwdev, st
+       for (i = 0; i < nelems; i++, sg++)
+               if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
+-                      sync_single(hwdev, (void *) sg->dma_address,
++                      sync_single(hwdev, phys_to_virt(sg->dma_address),
+                                   sg->dma_length, dir, target);
+ }
index 17aba4dab4f81ff5cee0dd9d1e2cd946768b3a92..777f580176a0366d828f7b02eb0ecedd8a81049e 100644 (file)
@@ -8,3 +8,11 @@ keys-fix-key-serial-number-collision-handling.patch
 ide-fix-drive-side-80c-cable-check.patch
 bcm43xx-fix-for-oops-on-resume.patch
 bcm43xx-fix-for-oops-on-ampdu-status.patch
+agp-intel-agp-bugfix.patch
+missing-critical-phys_to_virt-in-lib-swiotlb.c.patch
+libata-fix-drive-side-80c-cable-check.patch
+usb-fix-concurrent-buffer-access-in-the-hub-driver.patch
+usb-audio-fixes-1.patch
+usb-audio-fixes-2.patch
+hda-intel-don-t-try-to-probe-invalid-codecs.patch
+fix-various-bugs-with-aligned-reads-in-raid5.patch
diff --git a/queue-2.6.20/usb-audio-fixes-1.patch b/queue-2.6.20/usb-audio-fixes-1.patch
new file mode 100644 (file)
index 0000000..4054ff3
--- /dev/null
@@ -0,0 +1,52 @@
+From stable-bounces@linux.kernel.org Tue Feb  6 10:13:42 2007
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 06 Feb 2007 19:12:11 +0100
+Subject: USB audio fixes 1
+To: stable@kernel.org
+Message-ID: <s5h3b5jw3yc.wl%tiwai@suse.de>
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[PATCH] usbaudio - Fix Oops with broken usb descriptors
+
+This is a patch for ALSA Bug #2724. Some webcams provide bogus
+settings with no valid rates. With this patch those are skipped.
+
+Signed-off-by: Gregor Jasny <gjasny@web.de>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Jaroslav Kysela <perex@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/usb/usbaudio.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- linux-2.6.20.1.orig/sound/usb/usbaudio.c
++++ linux-2.6.20.1/sound/usb/usbaudio.c
+@@ -2456,6 +2456,7 @@ static int parse_audio_format_rates(stru
+                * build the rate table and bitmap flags
+                */
+               int r, idx, c;
++              unsigned int nonzero_rates = 0;
+               /* this table corresponds to the SNDRV_PCM_RATE_XXX bit */
+               static unsigned int conv_rates[] = {
+                       5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
+@@ -2478,6 +2479,7 @@ static int parse_audio_format_rates(stru
+                           fp->altsetting == 5 && fp->maxpacksize == 392)
+                               rate = 96000;
+                       fp->rate_table[r] = rate;
++                      nonzero_rates |= rate;
+                       if (rate < fp->rate_min)
+                               fp->rate_min = rate;
+                       else if (rate > fp->rate_max)
+@@ -2493,6 +2495,10 @@ static int parse_audio_format_rates(stru
+                       if (!found)
+                               fp->needs_knot = 1;
+               }
++              if (!nonzero_rates) {
++                      hwc_debug("All rates were zero. Skipping format!\n");
++                      return -1;
++              }
+               if (fp->needs_knot)
+                       fp->rates |= SNDRV_PCM_RATE_KNOT;
+       } else {
diff --git a/queue-2.6.20/usb-audio-fixes-2.patch b/queue-2.6.20/usb-audio-fixes-2.patch
new file mode 100644 (file)
index 0000000..d05321b
--- /dev/null
@@ -0,0 +1,92 @@
+From stable-bounces@linux.kernel.org Tue Feb  6 10:14:56 2007
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 06 Feb 2007 19:13:31 +0100
+Subject: USB audio fixes 2
+To: stable@kernel.org
+Message-ID: <s5h1wl3w3w4.wl%tiwai@suse.de>
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[PATCH] usbaudio - Fix Oops with unconventional sample rates
+
+The patch fixes the memory corruption by the support of unconventional
+sample rates.  Also, it avoids the too restrictive constraints if
+any of usb descriptions contain continuous rates.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/usb/usbaudio.c |   43 +++++++++++++++++++++++++------------------
+ 1 file changed, 25 insertions(+), 18 deletions(-)
+
+--- linux-2.6.20.1.orig/sound/usb/usbaudio.c
++++ linux-2.6.20.1/sound/usb/usbaudio.c
+@@ -186,6 +186,7 @@ struct snd_usb_substream {
+       u64 formats;                    /* format bitmasks (all or'ed) */
+       unsigned int num_formats;               /* number of supported audio formats (list) */
+       struct list_head fmt_list;      /* format list */
++      struct snd_pcm_hw_constraint_list rate_list;    /* limited rates */
+       spinlock_t lock;
+       struct snd_urb_ops ops;         /* callbacks (must be filled at init) */
+@@ -1810,28 +1811,33 @@ static int check_hw_params_convention(st
+ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
+                                 struct snd_usb_substream *subs)
+ {
+-      struct list_head *p;
+-      struct snd_pcm_hw_constraint_list constraints_rates;
++      struct audioformat *fp;
++      int count = 0, needs_knot = 0;
+       int err;
+-      list_for_each(p, &subs->fmt_list) {
+-              struct audioformat *fp;
+-              fp = list_entry(p, struct audioformat, list);
+-
+-              if (!fp->needs_knot)
+-                      continue;
+-
+-              constraints_rates.count = fp->nr_rates;
+-              constraints_rates.list = fp->rate_table;
+-              constraints_rates.mask = 0;
+-
+-              err = snd_pcm_hw_constraint_list(runtime, 0,
+-                      SNDRV_PCM_HW_PARAM_RATE,
+-                      &constraints_rates);
++      list_for_each_entry(fp, &subs->fmt_list, list) {
++              if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)
++                      return 0;
++              count += fp->nr_rates;
++              if (fp->needs_knot)
++                      needs_knot = 1;
++      }
++      if (!needs_knot)
++              return 0;
+-              if (err < 0)
+-                      return err;
++      subs->rate_list.count = count;
++      subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL);
++      subs->rate_list.mask = 0;
++      count = 0;
++      list_for_each_entry(fp, &subs->fmt_list, list) {
++              int i;
++              for (i = 0; i < fp->nr_rates; i++)
++                      subs->rate_list.list[count++] = fp->rate_table[i];
+       }
++      err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
++                                       &subs->rate_list);
++      if (err < 0)
++              return err;
+       return 0;
+ }
+@@ -2231,6 +2237,7 @@ static void free_substream(struct snd_us
+               kfree(fp->rate_table);
+               kfree(fp);
+       }
++      kfree(subs->rate_list.list);
+ }
diff --git a/queue-2.6.20/usb-fix-concurrent-buffer-access-in-the-hub-driver.patch b/queue-2.6.20/usb-fix-concurrent-buffer-access-in-the-hub-driver.patch
new file mode 100644 (file)
index 0000000..fec9c45
--- /dev/null
@@ -0,0 +1,71 @@
+From stable-bounces@linux.kernel.org Mon Feb  5 06:57:55 2007
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Mon, 5 Feb 2007 09:56:15 -0500 (EST)
+Subject: USB: fix concurrent buffer access in the hub driver
+To: Greg KH <greg@kroah.com>
+Cc: stable@kernel.org, USB development list <linux-usb-devel@lists.sourceforge.net>, Adrian Bunk <bunk@stusta.de>
+Message-ID: <Pine.LNX.4.44L0.0702050950390.3533-100000@iolanthe.rowland.org>
+
+
+This patch (as849) fixes a bug in the USB hub driver.  A single
+pre-allocated buffer is used for all port status reads, but nothing
+guarantees exclusive use of the buffer.  A mutex is added to provide
+this guarantee.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/hub.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- linux-2.6.20.1.orig/drivers/usb/core/hub.c
++++ linux-2.6.20.1/drivers/usb/core/hub.c
+@@ -44,6 +44,7 @@ struct usb_hub {
+               struct usb_hub_status   hub;
+               struct usb_port_status  port;
+       }                       *status;        /* buffer for status reports */
++      struct mutex            status_mutex;   /* for the status buffer */
+       int                     error;          /* last reported error */
+       int                     nerrors;        /* track consecutive errors */
+@@ -538,6 +539,7 @@ static int hub_hub_status(struct usb_hub
+ {
+       int ret;
++      mutex_lock(&hub->status_mutex);
+       ret = get_hub_status(hub->hdev, &hub->status->hub);
+       if (ret < 0)
+               dev_err (hub->intfdev,
+@@ -547,6 +549,7 @@ static int hub_hub_status(struct usb_hub
+               *change = le16_to_cpu(hub->status->hub.wHubChange); 
+               ret = 0;
+       }
++      mutex_unlock(&hub->status_mutex);
+       return ret;
+ }
+@@ -620,6 +623,7 @@ static int hub_configure(struct usb_hub 
+               ret = -ENOMEM;
+               goto fail;
+       }
++      mutex_init(&hub->status_mutex);
+       hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
+       if (!hub->descriptor) {
+@@ -1418,6 +1422,7 @@ static int hub_port_status(struct usb_hu
+ {
+       int ret;
++      mutex_lock(&hub->status_mutex);
+       ret = get_port_status(hub->hdev, port1, &hub->status->port);
+       if (ret < 4) {
+               dev_err (hub->intfdev,
+@@ -1429,6 +1434,7 @@ static int hub_port_status(struct usb_hu
+               *change = le16_to_cpu(hub->status->port.wPortChange); 
+               ret = 0;
+       }
++      mutex_unlock(&hub->status_mutex);
+       return ret;
+ }