diff options
14 files changed, 1104 insertions, 0 deletions
diff --git a/releases/2.6.16.22/fs-namei.c-call-to-file_permission-under-a-spinlock-in-do_lookup_path.patch b/releases/2.6.16.22/fs-namei.c-call-to-file_permission-under-a-spinlock-in-do_lookup_path.patch new file mode 100644 index 0000000000..8605484b6c --- /dev/null +++ b/releases/2.6.16.22/fs-namei.c-call-to-file_permission-under-a-spinlock-in-do_lookup_path.patch @@ -0,0 +1,98 @@ +From stable-bounces@linux.kernel.org Tue Jun 6 08:23:00 2006 +Date: Tue, 6 Jun 2006 11:19:35 -0400 +From: Joe Korty <joe.korty@ccur.com> +To: stable@kernel.org +Cc: +Subject: fs/namei.c: Call to file_permission() under a spinlock in do_lookup_path() + +From: Trond Myklebust <Trond.Myklebust@netapp.com> + +We're presently running lock_kernel() under fs_lock via nfs's ->permission +handler. That's a ranking bug and sometimes a sleep-in-spinlock bug. This +problem was introduced in the openat() patchset. + +We should not need to hold the current->fs->lock for a codepath that doesn't +use current->fs. + +[vsu@altlinux.ru: fix error path] +Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> +Cc: Al Viro <viro@ftp.linux.org.uk> +Signed-off-by: Sergey Vlasov <vsu@altlinux.ru> +Signed-off-by: Andrew Morton <akpm@osdl.org> +Signed-off-by: Linus Torvalds <torvalds@osdl.org> +Signed-off-by: Chris Wright <chrisw@sous-sol.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + + fs/namei.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +--- linux-2.6.16.21.orig/fs/namei.c ++++ linux-2.6.16.21/fs/namei.c +@@ -1077,8 +1077,8 @@ static int fastcall do_path_lookup(int d + nd->flags = flags; + nd->depth = 0; + +- read_lock(¤t->fs->lock); + if (*name=='/') { ++ read_lock(¤t->fs->lock); + if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) { + nd->mnt = mntget(current->fs->altrootmnt); + nd->dentry = dget(current->fs->altroot); +@@ -1089,33 +1089,35 @@ static int fastcall do_path_lookup(int d + } + nd->mnt = mntget(current->fs->rootmnt); + nd->dentry = dget(current->fs->root); ++ read_unlock(¤t->fs->lock); + } else if (dfd == AT_FDCWD) { ++ read_lock(¤t->fs->lock); + nd->mnt = mntget(current->fs->pwdmnt); + nd->dentry = dget(current->fs->pwd); ++ read_unlock(¤t->fs->lock); + } else { + struct dentry *dentry; + + file = fget_light(dfd, &fput_needed); + retval = -EBADF; + if (!file) +- goto unlock_fail; ++ goto out_fail; + + dentry = file->f_dentry; + + retval = -ENOTDIR; + if (!S_ISDIR(dentry->d_inode->i_mode)) +- goto fput_unlock_fail; ++ goto fput_fail; + + retval = file_permission(file, MAY_EXEC); + if (retval) +- goto fput_unlock_fail; ++ goto fput_fail; + + nd->mnt = mntget(file->f_vfsmnt); + nd->dentry = dget(dentry); + + fput_light(file, fput_needed); + } +- read_unlock(¤t->fs->lock); + current->total_link_count = 0; + retval = link_path_walk(name, nd); + out: +@@ -1124,13 +1126,12 @@ out: + nd->dentry->d_inode)) + audit_inode(name, nd->dentry->d_inode, flags); + } ++out_fail: + return retval; + +-fput_unlock_fail: ++fput_fail: + fput_light(file, fput_needed); +-unlock_fail: +- read_unlock(¤t->fs->lock); +- return retval; ++ goto out_fail; + } + + int fastcall path_lookup(const char *name, unsigned int flags, diff --git a/releases/2.6.16.22/i2o-bugfixes-to-get-i2o-working-again.patch b/releases/2.6.16.22/i2o-bugfixes-to-get-i2o-working-again.patch new file mode 100644 index 0000000000..0c5654616d --- /dev/null +++ b/releases/2.6.16.22/i2o-bugfixes-to-get-i2o-working-again.patch @@ -0,0 +1,249 @@ +From stable-bounces@linux.kernel.org Sat Jun 10 09:57:42 2006 +Date: Sat, 10 Jun 2006 09:54:14 -0700 +From: akpm@osdl.org +To: torvalds@osdl.org +Cc: Markus.Lidel@shadowconnect.com, stable@kernel.org +Subject: I2O: Bugfixes to get I2O working again + +From: Markus Lidel <Markus.Lidel@shadowconnect.com> + +- Fixed locking of struct i2o_exec_wait in Executive-OSM + +- Removed LCT Notify in i2o_exec_probe() which caused freeing memory and + accessing freed memory during first enumeration of I2O devices + +- Added missing locking in i2o_exec_lct_notify() + +- removed put_device() of I2O controller in i2o_iop_remove() which caused + the controller structure get freed to early + +- Fixed size of mempool in i2o_iop_alloc() + +- Fixed access to freed memory in i2o_msg_get() + +See http://bugzilla.kernel.org/show_bug.cgi?id=6561 + +Signed-off-by: Markus Lidel <Markus.Lidel@shadowconnect.com> +Signed-off-by: Andrew Morton <akpm@osdl.org> +Signed-off-by: Chris Wright <chrisw@sous-sol.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + + drivers/message/i2o/exec-osm.c | 72 +++++++++++++++++++++-------------------- + drivers/message/i2o/iop.c | 4 -- + include/linux/i2o.h | 5 ++ + 3 files changed, 42 insertions(+), 39 deletions(-) + +--- linux-2.6.16.21.orig/drivers/message/i2o/exec-osm.c ++++ linux-2.6.16.21/drivers/message/i2o/exec-osm.c +@@ -55,6 +55,7 @@ struct i2o_exec_wait { + u32 m; /* message id */ + struct i2o_message *msg; /* pointer to the reply message */ + struct list_head list; /* node in global wait list */ ++ spinlock_t lock; /* lock before modifying */ + }; + + /* Exec OSM class handling definition */ +@@ -80,6 +81,7 @@ static struct i2o_exec_wait *i2o_exec_wa + return NULL; + + INIT_LIST_HEAD(&wait->list); ++ spin_lock_init(&wait->lock); + + return wait; + }; +@@ -118,6 +120,7 @@ int i2o_msg_post_wait_mem(struct i2o_con + DECLARE_WAIT_QUEUE_HEAD(wq); + struct i2o_exec_wait *wait; + static u32 tcntxt = 0x80000000; ++ long flags; + int rc = 0; + + wait = i2o_exec_wait_alloc(); +@@ -139,33 +142,28 @@ int i2o_msg_post_wait_mem(struct i2o_con + wait->tcntxt = tcntxt++; + msg->u.s.tcntxt = cpu_to_le32(wait->tcntxt); + ++ wait->wq = &wq; ++ /* ++ * we add elements to the head, because if a entry in the list will ++ * never be removed, we have to iterate over it every time ++ */ ++ list_add(&wait->list, &i2o_exec_wait_list); ++ + /* + * Post the message to the controller. At some point later it will + * return. If we time out before it returns then complete will be zero. + */ + i2o_msg_post(c, msg); + +- if (!wait->complete) { +- wait->wq = &wq; +- /* +- * we add elements add the head, because if a entry in the list +- * will never be removed, we have to iterate over it every time +- */ +- list_add(&wait->list, &i2o_exec_wait_list); +- +- wait_event_interruptible_timeout(wq, wait->complete, +- timeout * HZ); ++ wait_event_interruptible_timeout(wq, wait->complete, timeout * HZ); + +- wait->wq = NULL; +- } ++ spin_lock_irqsave(&wait->lock, flags); + +- barrier(); ++ wait->wq = NULL; + +- if (wait->complete) { ++ if (wait->complete) + rc = le32_to_cpu(wait->msg->body[0]) >> 24; +- i2o_flush_reply(c, wait->m); +- i2o_exec_wait_free(wait); +- } else { ++ else { + /* + * We cannot remove it now. This is important. When it does + * terminate (which it must do if the controller has not +@@ -179,6 +177,13 @@ int i2o_msg_post_wait_mem(struct i2o_con + rc = -ETIMEDOUT; + } + ++ spin_unlock_irqrestore(&wait->lock, flags); ++ ++ if (rc != -ETIMEDOUT) { ++ i2o_flush_reply(c, wait->m); ++ i2o_exec_wait_free(wait); ++ } ++ + return rc; + }; + +@@ -206,7 +211,6 @@ static int i2o_msg_post_wait_complete(st + { + struct i2o_exec_wait *wait, *tmp; + unsigned long flags; +- static spinlock_t lock = SPIN_LOCK_UNLOCKED; + int rc = 1; + + /* +@@ -216,23 +220,24 @@ static int i2o_msg_post_wait_complete(st + * already expired. Not much we can do about that except log it for + * debug purposes, increase timeout, and recompile. + */ +- spin_lock_irqsave(&lock, flags); + list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) { + if (wait->tcntxt == context) { +- list_del(&wait->list); ++ spin_lock_irqsave(&wait->lock, flags); + +- spin_unlock_irqrestore(&lock, flags); ++ list_del(&wait->list); + + wait->m = m; + wait->msg = msg; + wait->complete = 1; + +- barrier(); +- +- if (wait->wq) { +- wake_up_interruptible(wait->wq); ++ if (wait->wq) + rc = 0; +- } else { ++ else ++ rc = -1; ++ ++ spin_unlock_irqrestore(&wait->lock, flags); ++ ++ if (rc) { + struct device *dev; + + dev = &c->pdev->dev; +@@ -241,15 +246,13 @@ static int i2o_msg_post_wait_complete(st + c->name); + i2o_dma_free(dev, &wait->dma); + i2o_exec_wait_free(wait); +- rc = -1; +- } ++ } else ++ wake_up_interruptible(wait->wq); + + return rc; + } + } + +- spin_unlock_irqrestore(&lock, flags); +- + osm_warn("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name, + context); + +@@ -315,14 +318,9 @@ static DEVICE_ATTR(product_id, S_IRUGO, + static int i2o_exec_probe(struct device *dev) + { + struct i2o_device *i2o_dev = to_i2o_device(dev); +- struct i2o_controller *c = i2o_dev->iop; + + i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff); + +- c->exec = i2o_dev; +- +- i2o_exec_lct_notify(c, c->lct->change_ind + 1); +- + device_create_file(dev, &dev_attr_vendor_id); + device_create_file(dev, &dev_attr_product_id); + +@@ -510,6 +508,8 @@ static int i2o_exec_lct_notify(struct i2 + struct device *dev; + struct i2o_message *msg; + ++ down(&c->lct_lock); ++ + dev = &c->pdev->dev; + + if (i2o_dma_realloc +@@ -532,6 +532,8 @@ static int i2o_exec_lct_notify(struct i2 + + i2o_msg_post(c, msg); + ++ up(&c->lct_lock); ++ + return 0; + }; + +--- linux-2.6.16.21.orig/drivers/message/i2o/iop.c ++++ linux-2.6.16.21/drivers/message/i2o/iop.c +@@ -804,8 +804,6 @@ void i2o_iop_remove(struct i2o_controlle + + /* Ask the IOP to switch to RESET state */ + i2o_iop_reset(c); +- +- put_device(&c->device); + } + + /** +@@ -1059,7 +1057,7 @@ struct i2o_controller *i2o_iop_alloc(voi + + snprintf(poolname, sizeof(poolname), "i2o_%s_msg_inpool", c->name); + if (i2o_pool_alloc +- (&c->in_msg, poolname, I2O_INBOUND_MSG_FRAME_SIZE * 4, ++ (&c->in_msg, poolname, I2O_INBOUND_MSG_FRAME_SIZE * 4 + sizeof(u32), + I2O_MSG_INPOOL_MIN)) { + kfree(c); + return ERR_PTR(-ENOMEM); +--- linux-2.6.16.21.orig/include/linux/i2o.h ++++ linux-2.6.16.21/include/linux/i2o.h +@@ -1116,8 +1116,11 @@ static inline struct i2o_message *i2o_ms + + mmsg->mfa = readl(c->in_port); + if (unlikely(mmsg->mfa >= c->in_queue.len)) { ++ u32 mfa = mmsg->mfa; ++ + mempool_free(mmsg, c->in_msg.mempool); +- if(mmsg->mfa == I2O_QUEUE_EMPTY) ++ ++ if (mfa == I2O_QUEUE_EMPTY) + return ERR_PTR(-EBUSY); + return ERR_PTR(-EFAULT); + } diff --git a/releases/2.6.16.22/jfs-fix-multiple-errors-in-metapage_releasepage.patch b/releases/2.6.16.22/jfs-fix-multiple-errors-in-metapage_releasepage.patch new file mode 100644 index 0000000000..9730ff167c --- /dev/null +++ b/releases/2.6.16.22/jfs-fix-multiple-errors-in-metapage_releasepage.patch @@ -0,0 +1,75 @@ +From stable-bounces@linux.kernel.org Tue Jun 6 20:00:50 2006 +Date: Tue, 6 Jun 2006 22:54:44 -0400 +From: Chuck Ebbert <76306.1226@compuserve.com> +To: linux-stable <stable@kernel.org> +Cc: Dave Kleikamp <shaggy@austin.ibm.com> +Subject: JFS: Fix multiple errors in metapage_releasepage + +From: Dave Kleikamp <shaggy@austin.ibm.com> + +It looks like metapage_releasepage was making in invalid assumption that +the releasepage method would not be called on a dirty page. Instead of +issuing a warning and releasing the metapage, it should return 0, indicating +that the private data for the page cannot be released. + +I also realized that metapage_releasepage had the return code all wrong. If +it is successful in releasing the private data, it should return 1, otherwise +it needs to return 0. + +Lastly, there is no need to call wait_on_page_writeback, since +try_to_release_page will not call us with a page in writback state. + +Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com> +Signed-off-by: Chris Wright <chrisw@sous-sol.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + + fs/jfs/jfs_metapage.c | 20 +++++--------------- + 1 file changed, 5 insertions(+), 15 deletions(-) + +--- linux-2.6.16.21.orig/fs/jfs/jfs_metapage.c ++++ linux-2.6.16.21/fs/jfs/jfs_metapage.c +@@ -543,7 +543,7 @@ add_failed: + static int metapage_releasepage(struct page *page, gfp_t gfp_mask) + { + struct metapage *mp; +- int busy = 0; ++ int ret = 1; + unsigned int offset; + + for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) { +@@ -553,30 +553,20 @@ static int metapage_releasepage(struct p + continue; + + jfs_info("metapage_releasepage: mp = 0x%p", mp); +- if (mp->count || mp->nohomeok) { ++ if (mp->count || mp->nohomeok || ++ test_bit(META_dirty, &mp->flag)) { + jfs_info("count = %ld, nohomeok = %d", mp->count, + mp->nohomeok); +- busy = 1; ++ ret = 0; + continue; + } +- wait_on_page_writeback(page); +- //WARN_ON(test_bit(META_dirty, &mp->flag)); +- if (test_bit(META_dirty, &mp->flag)) { +- dump_mem("dirty mp in metapage_releasepage", mp, +- sizeof(struct metapage)); +- dump_mem("page", page, sizeof(struct page)); +- dump_stack(); +- } + if (mp->lsn) + remove_from_logsync(mp); + remove_metapage(page, mp); + INCREMENT(mpStat.pagefree); + free_metapage(mp); + } +- if (busy) +- return -1; +- +- return 0; ++ return ret; + } + + static int metapage_invalidatepage(struct page *page, unsigned long offset) diff --git a/releases/2.6.16.22/missed-error-checking-for-intent-s-filp-in-open_namei.patch b/releases/2.6.16.22/missed-error-checking-for-intent-s-filp-in-open_namei.patch new file mode 100644 index 0000000000..304b0def52 --- /dev/null +++ b/releases/2.6.16.22/missed-error-checking-for-intent-s-filp-in-open_namei.patch @@ -0,0 +1,53 @@ +From nobody Mon Sep 17 00:00:00 2001 +From: Oleg Drokin <green@linuxhacker.ru> +Date: Sat, 25 Mar 2006 03:06:54 -0800 +Subject: [PATCH] Missed error checking for intent's filp in open_namei(). + +It seems there is error check missing in open_namei for errors returned +through intent.open.file (from lookup_instantiate_filp). + +If there is plain open performed, then such a check done inside +__path_lookup_intent_open called from path_lookup_open(), but when the open +is performed with O_CREAT flag set, then __path_lookup_intent_open is only +called with LOOKUP_PARENT set where no file opening can occur yet. + +Later on lookup_hash is called where exact opening might take place and +intent.open.file may be filled. If it is filled with error value of some +sort, then we get kernel attempting to dereference this error value as +address (and corresponding oops) in nameidata_to_filp() called from +filp_open(). + +While this is relatively simple to workaround in ->lookup() method by just +checking lookup_instantiate_filp() return value and returning error as +needed, this is not so easy in ->d_revalidate(), where we can only return +"yes, dentry is valid" or "no, dentry is invalid, perform full lookup +again", and just returning 0 on error would cause extra lookup (with +potential extra costly RPCs). + +So in short, I believe that there should be no difference in error handling +for opening a file and creating a file in open_namei() and propose this +simple patch as a solution. + +Signed-off-by: Andrew Morton <akpm@osdl.org> +Signed-off-by: Linus Torvalds <torvalds@osdl.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + fs/namei.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- linux-2.6.16.21.orig/fs/namei.c ++++ linux-2.6.16.21/fs/namei.c +@@ -1628,6 +1628,12 @@ do_last: + goto exit; + } + ++ if (IS_ERR(nd->intent.open.file)) { ++ mutex_unlock(&dir->d_inode->i_mutex); ++ error = PTR_ERR(nd->intent.open.file); ++ goto exit_dput; ++ } ++ + /* Negative dentry, just create the file */ + if (!path.dentry->d_inode) { + if (!IS_POSIXACL(dir->d_inode)) diff --git a/releases/2.6.16.22/ntfs-critical-bug-fix.patch b/releases/2.6.16.22/ntfs-critical-bug-fix.patch new file mode 100644 index 0000000000..3ee3d63aa1 --- /dev/null +++ b/releases/2.6.16.22/ntfs-critical-bug-fix.patch @@ -0,0 +1,50 @@ +From stable-bounces@linux.kernel.org Tue Jun 20 00:30:20 2006 +Date: Tue, 20 Jun 2006 00:29:41 -0700 +From: akpm@osdl.org +To: aia21@cam.ac.uk, aia21@cantab.net, stable@kernel.org +Cc: +Subject: NTFS: Critical bug fix (affects MIPS and possibly others) + +From: Anton Altaparmakov <aia21@cam.ac.uk> + +It fixes a crash in NTFS on architectures where flush_dcache_page() +is a real function. I never noticed this as all my testing is done on +i386 where flush_dcache_page() is NULL. + +http://bugzilla.kernel.org/show_bug.cgi?id=6700 + +Many thanks to Pauline Ng for the detailed bug report and analysis! + +Signed-off-by: Anton Altaparmakov <aia21@cantab.net> +Cc: <stable@kernel.org> +Signed-off-by: Andrew Morton <akpm@osdl.org> +Signed-off-by: Chris Wright <chrisw@sous-sol.org> +--- + + fs/ntfs/file.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +--- linux-2.6.16.21.orig/fs/ntfs/file.c ++++ linux-2.6.16.21/fs/ntfs/file.c +@@ -1489,14 +1489,15 @@ static inline void ntfs_flush_dcache_pag + unsigned nr_pages) + { + BUG_ON(!nr_pages); ++ /* ++ * Warning: Do not do the decrement at the same time as the call to ++ * flush_dcache_page() because it is a NULL macro on i386 and hence the ++ * decrement never happens so the loop never terminates. ++ */ + do { +- /* +- * Warning: Do not do the decrement at the same time as the +- * call because flush_dcache_page() is a NULL macro on i386 +- * and hence the decrement never happens. +- */ ++ --nr_pages; + flush_dcache_page(pages[nr_pages]); +- } while (--nr_pages > 0); ++ } while (nr_pages > 0); + } + + /** diff --git a/releases/2.6.16.22/powernow-k8-crash-workaround.patch b/releases/2.6.16.22/powernow-k8-crash-workaround.patch new file mode 100644 index 0000000000..27c3b3b570 --- /dev/null +++ b/releases/2.6.16.22/powernow-k8-crash-workaround.patch @@ -0,0 +1,47 @@ +From stable-bounces@linux.kernel.org Sat Jun 10 23:33:22 2006 +Date: Sat, 10 Jun 2006 18:59:23 GMT +From: Linux Kernel Mailing List <linux-kernel@vger.kernel.org> +To: git-commits-head@vger.kernel.org +Cc: +Subject: powernow-k8 crash workaround + +From: Andrew Morton <akpm@osdl.org> + +Work around the oops reported in +http://bugzilla.kernel.org/show_bug.cgi?id=6478. + +Thanks to Ralf Hildebrandt <ralf.hildebrandt@charite.de> for testing and +reporting. + +Acked-by: Dave Jones <davej@codemonkey.org.uk> +Cc: "Brown, Len" <len.brown@intel.com> +Signed-off-by: Andrew Morton <akpm@osdl.org> +Signed-off-by: Linus Torvalds <torvalds@osdl.org> +Signed-off-by: Chris Wright <chrisw@sous-sol.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + + drivers/acpi/processor_perflib.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- linux-2.6.16.21.orig/drivers/acpi/processor_perflib.c ++++ linux-2.6.16.21/drivers/acpi/processor_perflib.c +@@ -577,6 +577,8 @@ acpi_processor_register_performance(stru + return_VALUE(-EBUSY); + } + ++ WARN_ON(!performance); ++ + pr->performance = performance; + + if (acpi_processor_get_performance_info(pr)) { +@@ -609,7 +611,8 @@ acpi_processor_unregister_performance(st + return_VOID; + } + +- kfree(pr->performance->states); ++ if (pr->performance) ++ kfree(pr->performance->states); + pr->performance = NULL; + + acpi_cpufreq_remove_file(pr); diff --git a/releases/2.6.16.22/scsi_lib.c-properly-count-the-number-of-pages-in-scsi_req_map_sg.patch b/releases/2.6.16.22/scsi_lib.c-properly-count-the-number-of-pages-in-scsi_req_map_sg.patch new file mode 100644 index 0000000000..f773cd1afc --- /dev/null +++ b/releases/2.6.16.22/scsi_lib.c-properly-count-the-number-of-pages-in-scsi_req_map_sg.patch @@ -0,0 +1,33 @@ +From stable-bounces@linux.kernel.org Wed Jun 7 21:15:48 2006 +Date: Thu, 8 Jun 2006 00:03:28 -0400 +From: Chuck Ebbert <76306.1226@compuserve.com> +To: linux-stable <stable@kernel.org> +Cc: James Bottomley <James.Bottomley@steeleye.com>, Brian Holty <lgeek@frontiernet.net> +Subject: scsi_lib.c: properly count the number of pages in scsi_req_map_sg() + +From: James Bottomley <jejb@mulgrave.il.steeleye.com> + +The calculation of nr_pages in scsi_req_map_sg() doesn't account for +the fact that the first page could have an offset that pushes the end +of the buffer onto a new page. + +Signed-off-by: Bryan Holty <lgeek@frontiernet.net> +Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com> +Signed-off-by: Chris Wright <chrisw@sous-sol.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + + drivers/scsi/scsi_lib.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-2.6.16.21.orig/drivers/scsi/scsi_lib.c ++++ linux-2.6.16.21/drivers/scsi/scsi_lib.c +@@ -368,7 +368,7 @@ static int scsi_req_map_sg(struct reques + int nsegs, unsigned bufflen, gfp_t gfp) + { + struct request_queue *q = rq->q; +- int nr_pages = (bufflen + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ int nr_pages = (bufflen + sgl[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT; + unsigned int data_len = 0, len, bytes, off; + struct page *page; + struct bio *bio = NULL; diff --git a/releases/2.6.16.22/serial-parport_serial-should-depend-on-serial_8250_pci.patch b/releases/2.6.16.22/serial-parport_serial-should-depend-on-serial_8250_pci.patch new file mode 100644 index 0000000000..6e0e86a566 --- /dev/null +++ b/releases/2.6.16.22/serial-parport_serial-should-depend-on-serial_8250_pci.patch @@ -0,0 +1,28 @@ +Date: Sun, 18 Jun 2006 13:05:43 +0100 +From: Russell King <rmk+lkml@arm.linux.org.uk> +To: Andrey Borzenkov <arvidjaar@mail.ru> +Subject: SERIAL: PARPORT_SERIAL should depend on SERIAL_8250_PCI + +Since parport_serial uses symbols from 8250_pci, there should +be a dependency between the configuration symbols for these +two modules. Problem reported by Andrey Borzenkov + +Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> +Signed-off-by: Chris Wright <chrisw@sous-sol.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + + drivers/parport/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-2.6.16.21.orig/drivers/parport/Kconfig ++++ linux-2.6.16.21/drivers/parport/Kconfig +@@ -48,7 +48,7 @@ config PARPORT_PC + + config PARPORT_SERIAL + tristate "Multi-IO cards (parallel and serial)" +- depends on SERIAL_8250 && PARPORT_PC && PCI ++ depends on SERIAL_8250_PCI && PARPORT_PC && PCI + help + This adds support for multi-IO PCI cards that have parallel and + serial ports. You should say Y or M here. If you say M, the module diff --git a/releases/2.6.16.22/series b/releases/2.6.16.22/series new file mode 100644 index 0000000000..8c8a3b1e25 --- /dev/null +++ b/releases/2.6.16.22/series @@ -0,0 +1,13 @@ +usb-whiteheat-fix-firmware-spurious-errors.patch +sparc64-fix-d-cache-corruption-in-mremap.patch +sparc64-respect-gfp_t-argument-to-dma_alloc_coherent.patch +sparc64-fix-missing-fold-at-end-of-checksums.patch +missed-error-checking-for-intent-s-filp-in-open_namei.patch +tmpfs-time-granularity-fix-for-time-going-backwards.patch +serial-parport_serial-should-depend-on-serial_8250_pci.patch +fs-namei.c-call-to-file_permission-under-a-spinlock-in-do_lookup_path.patch +jfs-fix-multiple-errors-in-metapage_releasepage.patch +scsi_lib.c-properly-count-the-number-of-pages-in-scsi_req_map_sg.patch +i2o-bugfixes-to-get-i2o-working-again.patch +powernow-k8-crash-workaround.patch +ntfs-critical-bug-fix.patch diff --git a/releases/2.6.16.22/sparc64-fix-d-cache-corruption-in-mremap.patch b/releases/2.6.16.22/sparc64-fix-d-cache-corruption-in-mremap.patch new file mode 100644 index 0000000000..d18338640b --- /dev/null +++ b/releases/2.6.16.22/sparc64-fix-d-cache-corruption-in-mremap.patch @@ -0,0 +1,95 @@ +From stable-bounces@linux.kernel.org Fri Jun 2 18:34:53 2006 +Date: Fri, 02 Jun 2006 18:30:58 -0700 (PDT) +From: David Miller <davem@davemloft.net> +To: stable@kernel.org +Cc: +Subject: SPARC64: Fix D-cache corruption in mremap + +If we move a mapping from one virtual address to another, +and this changes the virtual color of the mapping to those +pages, we can see corrupt data due to D-cache aliasing. + +Check for and deal with this by overriding the move_pte() +macro. Set things up so that other platforms can cleanly +override the move_pte() macro too. + +This long standing bug corrupts user memory, and in particular +has been notorious for corrupting Debian package database +files on sparc64 boxes. + +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Chris Wright <chrisw@sous-sol.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + + include/asm-generic/pgtable.h | 11 +---------- + include/asm-mips/pgtable.h | 10 +++++++++- + include/asm-sparc64/pgtable.h | 17 +++++++++++++++++ + 3 files changed, 27 insertions(+), 11 deletions(-) + +--- linux-2.6.16.21.orig/include/asm-generic/pgtable.h ++++ linux-2.6.16.21/include/asm-generic/pgtable.h +@@ -159,17 +159,8 @@ static inline void ptep_set_wrprotect(st + #define lazy_mmu_prot_update(pte) do { } while (0) + #endif + +-#ifndef __HAVE_ARCH_MULTIPLE_ZERO_PAGE ++#ifndef __HAVE_ARCH_MOVE_PTE + #define move_pte(pte, prot, old_addr, new_addr) (pte) +-#else +-#define move_pte(pte, prot, old_addr, new_addr) \ +-({ \ +- pte_t newpte = (pte); \ +- if (pte_present(pte) && pfn_valid(pte_pfn(pte)) && \ +- pte_page(pte) == ZERO_PAGE(old_addr)) \ +- newpte = mk_pte(ZERO_PAGE(new_addr), (prot)); \ +- newpte; \ +-}) + #endif + + /* +--- linux-2.6.16.21.orig/include/asm-mips/pgtable.h ++++ linux-2.6.16.21/include/asm-mips/pgtable.h +@@ -70,7 +70,15 @@ extern unsigned long zero_page_mask; + #define ZERO_PAGE(vaddr) \ + (virt_to_page(empty_zero_page + (((unsigned long)(vaddr)) & zero_page_mask))) + +-#define __HAVE_ARCH_MULTIPLE_ZERO_PAGE ++#define __HAVE_ARCH_MOVE_PTE ++#define move_pte(pte, prot, old_addr, new_addr) \ ++({ \ ++ pte_t newpte = (pte); \ ++ if (pte_present(pte) && pfn_valid(pte_pfn(pte)) && \ ++ pte_page(pte) == ZERO_PAGE(old_addr)) \ ++ newpte = mk_pte(ZERO_PAGE(new_addr), (prot)); \ ++ newpte; \ ++}) + + extern void paging_init(void); + +--- linux-2.6.16.21.orig/include/asm-sparc64/pgtable.h ++++ linux-2.6.16.21/include/asm-sparc64/pgtable.h +@@ -335,6 +335,23 @@ static inline void set_pte_at(struct mm_ + #define pte_clear(mm,addr,ptep) \ + set_pte_at((mm), (addr), (ptep), __pte(0UL)) + ++#ifdef DCACHE_ALIASING_POSSIBLE ++#define __HAVE_ARCH_MOVE_PTE ++#define move_pte(pte, prot, old_addr, new_addr) \ ++({ \ ++ pte_t newpte = (pte); \ ++ if (pte_present(pte)) { \ ++ unsigned long this_pfn = pte_pfn(pte); \ ++ \ ++ if (pfn_valid(this_pfn) && \ ++ (((old_addr) ^ (new_addr)) & (1 << 13))) \ ++ flush_dcache_page_all(current->mm, \ ++ pfn_to_page(this_pfn)); \ ++ } \ ++ newpte; \ ++}) ++#endif ++ + extern pgd_t swapper_pg_dir[2048]; + extern pmd_t swapper_low_pmd_dir[2048]; + diff --git a/releases/2.6.16.22/sparc64-fix-missing-fold-at-end-of-checksums.patch b/releases/2.6.16.22/sparc64-fix-missing-fold-at-end-of-checksums.patch new file mode 100644 index 0000000000..a202573dde --- /dev/null +++ b/releases/2.6.16.22/sparc64-fix-missing-fold-at-end-of-checksums.patch @@ -0,0 +1,56 @@ +From stable-bounces@linux.kernel.org Mon Jun 5 11:30:48 2006 +Date: Mon, 05 Jun 2006 11:27:10 -0700 (PDT) +From: David Miller <davem@davemloft.net> +To: stable@kernel.org +Cc: +Subject: SPARC64: Fix missing fold at end of checksums. + +Both csum_partial() and the csum_partial_copy*() family of routines +forget to do a final fold on the computed checksum value on sparc64. +So do the standard Sparc "add + set condition codes, add carry" +sequence, then make sure the high 32-bits of the return value are +clear. + +Based upon some excellent detective work and debugging done by +Richard Braun and Samuel Thibault. + +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Chris Wright <chrisw@sous-sol.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + + arch/sparc64/lib/checksum.S | 5 +++-- + arch/sparc64/lib/csum_copy.S | 5 +++-- + 2 files changed, 6 insertions(+), 4 deletions(-) + +--- linux-2.6.16.21.orig/arch/sparc64/lib/checksum.S ++++ linux-2.6.16.21/arch/sparc64/lib/checksum.S +@@ -165,8 +165,9 @@ csum_partial_end_cruft: + sll %g1, 8, %g1 + or %o5, %g1, %o4 + +-1: add %o2, %o4, %o2 ++1: addcc %o2, %o4, %o2 ++ addc %g0, %o2, %o2 + + csum_partial_finish: + retl +- mov %o2, %o0 ++ srl %o2, 0, %o0 +--- linux-2.6.16.21.orig/arch/sparc64/lib/csum_copy.S ++++ linux-2.6.16.21/arch/sparc64/lib/csum_copy.S +@@ -221,11 +221,12 @@ FUNC_NAME: /* %o0=src, %o1=dst, %o2=len + sll %g1, 8, %g1 + or %o5, %g1, %o4 + +-1: add %o3, %o4, %o3 ++1: addcc %o3, %o4, %o3 ++ addc %g0, %o3, %o3 + + 70: + retl +- mov %o3, %o0 ++ srl %o3, 0, %o0 + + 95: mov 0, GLOBAL_SPARE + brlez,pn %o2, 4f diff --git a/releases/2.6.16.22/sparc64-respect-gfp_t-argument-to-dma_alloc_coherent.patch b/releases/2.6.16.22/sparc64-respect-gfp_t-argument-to-dma_alloc_coherent.patch new file mode 100644 index 0000000000..8713bafd72 --- /dev/null +++ b/releases/2.6.16.22/sparc64-respect-gfp_t-argument-to-dma_alloc_coherent.patch @@ -0,0 +1,226 @@ +From stable-bounces@linux.kernel.org Sun Jun 4 20:44:37 2006 +Date: Sun, 04 Jun 2006 20:41:00 -0700 (PDT) +From: David Miller <davem@davemloft.net> +To: stable@kernel.org +Cc: +Subject: SPARC64: Respect gfp_t argument to dma_alloc_coherent(). + +Using asm-generic/dma-mapping.h does not work because pushing +the call down to pci_alloc_coherent() causes the gfp_t argument +of dma_alloc_coherent() to be ignored. + +Fix this by implementing things directly, and adding a gfp_t +argument we can use in the internal call down to the PCI DMA +implementation of pci_alloc_coherent(). + +This fixes massive memory corruption when using the sound driver +layer, which passes things like __GFP_COMP down into these +routines and (correctly) expects that to work. + +This is a disk eater when sound is used, so it's pretty critical. + +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Chris Wright <chrisw@sous-sol.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + + arch/sparc64/kernel/pci_iommu.c | 4 - + arch/sparc64/kernel/sparc64_ksyms.c | 2 + include/asm-sparc64/dma-mapping.h | 141 +++++++++++++++++++++++++++++++++++- + include/asm-sparc64/pci.h | 4 - + 4 files changed, 146 insertions(+), 5 deletions(-) + +--- linux-2.6.16.21.orig/arch/sparc64/kernel/pci_iommu.c ++++ linux-2.6.16.21/arch/sparc64/kernel/pci_iommu.c +@@ -219,7 +219,7 @@ static inline void iommu_free_ctx(struct + * DMA for PCI device PDEV. Return non-NULL cpu-side address if + * successful and set *DMA_ADDRP to the PCI side dma address. + */ +-void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) ++void *__pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) + { + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; +@@ -233,7 +233,7 @@ void *pci_alloc_consistent(struct pci_de + if (order >= 10) + return NULL; + +- first_page = __get_free_pages(GFP_ATOMIC, order); ++ first_page = __get_free_pages(gfp, order); + if (first_page == 0UL) + return NULL; + memset((char *)first_page, 0, PAGE_SIZE << order); +--- linux-2.6.16.21.orig/arch/sparc64/kernel/sparc64_ksyms.c ++++ linux-2.6.16.21/arch/sparc64/kernel/sparc64_ksyms.c +@@ -221,7 +221,7 @@ EXPORT_SYMBOL(insl); + EXPORT_SYMBOL(ebus_chain); + EXPORT_SYMBOL(isa_chain); + EXPORT_SYMBOL(pci_memspace_mask); +-EXPORT_SYMBOL(pci_alloc_consistent); ++EXPORT_SYMBOL(__pci_alloc_consistent); + EXPORT_SYMBOL(pci_free_consistent); + EXPORT_SYMBOL(pci_map_single); + EXPORT_SYMBOL(pci_unmap_single); +--- linux-2.6.16.21.orig/include/asm-sparc64/dma-mapping.h ++++ linux-2.6.16.21/include/asm-sparc64/dma-mapping.h +@@ -4,7 +4,146 @@ + #include <linux/config.h> + + #ifdef CONFIG_PCI +-#include <asm-generic/dma-mapping.h> ++ ++/* we implement the API below in terms of the existing PCI one, ++ * so include it */ ++#include <linux/pci.h> ++/* need struct page definitions */ ++#include <linux/mm.h> ++ ++static inline int ++dma_supported(struct device *dev, u64 mask) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_dma_supported(to_pci_dev(dev), mask); ++} ++ ++static inline int ++dma_set_mask(struct device *dev, u64 dma_mask) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_set_dma_mask(to_pci_dev(dev), dma_mask); ++} ++ ++static inline void * ++dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, ++ gfp_t flag) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return __pci_alloc_consistent(to_pci_dev(dev), size, dma_handle, flag); ++} ++ ++static inline void ++dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, ++ dma_addr_t dma_handle) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle); ++} ++ ++static inline dma_addr_t ++dma_map_single(struct device *dev, void *cpu_addr, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction); ++} ++ ++static inline void ++dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction); ++} ++ ++static inline dma_addr_t ++dma_map_page(struct device *dev, struct page *page, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction); ++} ++ ++static inline void ++dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction); ++} ++ ++static inline int ++dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); ++} ++ ++static inline void ++dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction); ++} ++ ++static inline void ++dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, ++ size, (int)direction); ++} ++ ++static inline void ++dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, ++ size, (int)direction); ++} ++ ++static inline void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction); ++} ++ ++static inline void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction); ++} ++ ++static inline int ++dma_mapping_error(dma_addr_t dma_addr) ++{ ++ return pci_dma_mapping_error(dma_addr); ++} ++ + #else + + struct device; +--- linux-2.6.16.21.orig/include/asm-sparc64/pci.h ++++ linux-2.6.16.21/include/asm-sparc64/pci.h +@@ -44,7 +44,9 @@ struct pci_dev; + /* Allocate and map kernel buffer using consistent mode DMA for a device. + * hwdev should be valid struct pci_dev pointer for PCI devices. + */ +-extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle); ++extern void *__pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t gfp); ++#define pci_alloc_consistent(DEV,SZ,HANDLE) \ ++ __pci_alloc_consistent(DEV,SZ,HANDLE,GFP_ATOMIC) + + /* Free and unmap a consistent DMA buffer. + * cpu_addr is what was returned from pci_alloc_consistent, diff --git a/releases/2.6.16.22/tmpfs-time-granularity-fix-for-time-going-backwards.patch b/releases/2.6.16.22/tmpfs-time-granularity-fix-for-time-going-backwards.patch new file mode 100644 index 0000000000..7a627f6be4 --- /dev/null +++ b/releases/2.6.16.22/tmpfs-time-granularity-fix-for-time-going-backwards.patch @@ -0,0 +1,45 @@ +From hugh_dickins@symantec.com Tue Jun 13 10:08:40 2006 +Date: Tue, 13 Jun 2006 18:06:11 +0100 (BST) +From: Hugh Dickins <hugh@veritas.com> +To: Chris Wright <chrisw@sous-sol.org> +cc: "Robin H. Johnson" <robbat2@gentoo.org>, Andi Kleen <ak@suse.de>, stable@kernel.org +Subject: tmpfs: time granularity fix for [acm]time going backwards + +From: Robin H. Johnson <robbat2@gentoo.org> + +I noticed a strange behavior in a tmpfs file system the other day, while +building packages - occasionally, and seemingly at random, make decided to +rebuild a target. However, only on tmpfs. + +A file would be created, and if checked, it had a sub-second timestamp. +However, after an utimes related call where sub-seconds should be set, they +were zeroed instead. In the case that a file was created, and utimes(...,NULL) +was used on it in the same second, the timestamp on the file moved backwards. + +After some digging, I found that this was being caused by tmpfs not having a +time granularity set, thus inheriting the default 1 second granularity. + +Hugh adds: yes, we missed tmpfs when the s_time_gran mods went into 2.6.11. +Unfortunately, the granularity of CURRENT_TIME, often used in filesystems, +does not match the default granularity set by alloc_super. A few more such +discrepancies have been found, but this is the most important to fix now. + +Signed-off-by: Robin H. Johnson <robbat2@gentoo.org> +Acked-by: Andi Kleen <ak@suse.de> +Signed-off-by: Hugh Dickins <hugh@veritas.com> +Signed-off-by: Chris Wright <chrisw@sous-sol.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + mm/shmem.c | 1 + + 1 file changed, 1 insertion(+) + +--- linux-2.6.16.21.orig/mm/shmem.c ++++ linux-2.6.16.21/mm/shmem.c +@@ -2100,6 +2100,7 @@ static int shmem_fill_super(struct super + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = TMPFS_MAGIC; + sb->s_op = &shmem_ops; ++ sb->s_time_gran = 1; + + inode = shmem_get_inode(sb, S_IFDIR | mode, 0); + if (!inode) diff --git a/releases/2.6.16.22/usb-whiteheat-fix-firmware-spurious-errors.patch b/releases/2.6.16.22/usb-whiteheat-fix-firmware-spurious-errors.patch new file mode 100644 index 0000000000..189e049d69 --- /dev/null +++ b/releases/2.6.16.22/usb-whiteheat-fix-firmware-spurious-errors.patch @@ -0,0 +1,36 @@ +From stuartm@connecttech.com Wed May 31 10:40:58 2006 +From: "Stuart MacDonald" <stuartm@connecttech.com> +To: <greg@kroah.com> +Subject: USB: Whiteheat: fix firmware spurious errors +Date: Wed, 31 May 2006 13:28:40 -0400 +Message-ID: <02d901c684d7$a87b8460$294b82ce@stuartm> + +Attached patch fixes spurious errors during firmware load. + +Signed-off-by: Stuart MacDonald <stuartm@connecttech.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +Signed-off-by: Chris Wright <chrisw@sous-sol.org> +--- + drivers/usb/serial/whiteheat.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- linux-2.6.16.21.orig/drivers/usb/serial/whiteheat.c ++++ linux-2.6.16.21/drivers/usb/serial/whiteheat.c +@@ -388,7 +388,7 @@ static int whiteheat_attach (struct usb_ + if (ret) { + err("%s: Couldn't send command [%d]", serial->type->description, ret); + goto no_firmware; +- } else if (alen != sizeof(command)) { ++ } else if (alen != 2) { + err("%s: Send command incomplete [%d]", serial->type->description, alen); + goto no_firmware; + } +@@ -400,7 +400,7 @@ static int whiteheat_attach (struct usb_ + if (ret) { + err("%s: Couldn't get results [%d]", serial->type->description, ret); + goto no_firmware; +- } else if (alen != sizeof(result)) { ++ } else if (alen != sizeof(*hw_info) + 1) { + err("%s: Get results incomplete [%d]", serial->type->description, alen); + goto no_firmware; + } else if (result[0] != command[0]) { |