From: Greg Kroah-Hartman Date: Wed, 15 Sep 2010 22:14:48 +0000 (-0700) Subject: .35 patches X-Git-Tag: v2.6.27.54~26 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=05152c1c42e1cab842da3974684ee9cd5019bd4b;p=thirdparty%2Fkernel%2Fstable-queue.git .35 patches --- diff --git a/queue-2.6.35/ahci-fix-hang-on-failed-softreset.patch b/queue-2.6.35/ahci-fix-hang-on-failed-softreset.patch new file mode 100644 index 00000000000..675c419b2ff --- /dev/null +++ b/queue-2.6.35/ahci-fix-hang-on-failed-softreset.patch @@ -0,0 +1,40 @@ +From f1f5a807b051eddd3f302e503d39214e5bde0ef2 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Fri, 27 Aug 2010 11:09:15 +0200 +Subject: ahci: fix hang on failed softreset + +From: Tejun Heo + +commit f1f5a807b051eddd3f302e503d39214e5bde0ef2 upstream. + +ahci_do_softreset() compared the current time and deadline in reverse +when calculating timeout for SRST issue. The result is that if +@deadline is in future, SRST is issued with 0 timeout, which hasn't +caused any problem because it later waits for DRDY with the correct +timeout. If deadline is already exceeded by the time SRST is about to +be issued, the timeout calculation underflows and if the device +doesn't respond, timeout doesn't trigger for a _very_ long time. + +Reverse the incorrect comparison order. + +Signed-off-by: Tejun Heo +Reported-by: Anssi Hannula +Tested-by: Gwendal Grignou +Signed-off-by: Jeff Garzik +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/ata/libahci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/ata/libahci.c ++++ b/drivers/ata/libahci.c +@@ -1320,7 +1320,7 @@ int ahci_do_softreset(struct ata_link *l + /* issue the first D2H Register FIS */ + msecs = 0; + now = jiffies; +- if (time_after(now, deadline)) ++ if (time_after(deadline, now)) + msecs = jiffies_to_msecs(deadline - now); + + tf.ctl |= ATA_SRST; diff --git a/queue-2.6.35/gcov-fix-null-pointer-dereference-for-certain-module-types.patch b/queue-2.6.35/gcov-fix-null-pointer-dereference-for-certain-module-types.patch new file mode 100644 index 00000000000..dccdaaaab6f --- /dev/null +++ b/queue-2.6.35/gcov-fix-null-pointer-dereference-for-certain-module-types.patch @@ -0,0 +1,404 @@ +From 85a0fdfd0f967507f3903e8419bc7e408f5a59de Mon Sep 17 00:00:00 2001 +From: Peter Oberparleiter +Date: Thu, 9 Sep 2010 16:37:35 -0700 +Subject: gcov: fix null-pointer dereference for certain module types + +From: Peter Oberparleiter + +commit 85a0fdfd0f967507f3903e8419bc7e408f5a59de upstream. + +The gcov-kernel infrastructure expects that each object file is loaded +only once. This may not be true, e.g. when loading multiple kernel +modules which are linked to the same object file. As a result, loading +such kernel modules will result in incorrect gcov results while unloading +will cause a null-pointer dereference. + +This patch fixes these problems by changing the gcov-kernel infrastructure +so that multiple profiling data sets can be associated with one debugfs +entry. It applies to 2.6.36-rc1. + +Signed-off-by: Peter Oberparleiter +Reported-by: Werner Spies +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/gcov/fs.c | 244 ++++++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 180 insertions(+), 64 deletions(-) + +--- a/kernel/gcov/fs.c ++++ b/kernel/gcov/fs.c +@@ -33,10 +33,11 @@ + * @children: child nodes + * @all: list head for list of all nodes + * @parent: parent node +- * @info: associated profiling data structure if not a directory +- * @ghost: when an object file containing profiling data is unloaded we keep a +- * copy of the profiling data here to allow collecting coverage data +- * for cleanup code. Such a node is called a "ghost". ++ * @loaded_info: array of pointers to profiling data sets for loaded object ++ * files. ++ * @num_loaded: number of profiling data sets for loaded object files. ++ * @unloaded_info: accumulated copy of profiling data sets for unloaded ++ * object files. Used only when gcov_persist=1. + * @dentry: main debugfs entry, either a directory or data file + * @links: associated symbolic links + * @name: data file basename +@@ -51,10 +52,11 @@ struct gcov_node { + struct list_head children; + struct list_head all; + struct gcov_node *parent; +- struct gcov_info *info; +- struct gcov_info *ghost; ++ struct gcov_info **loaded_info; ++ struct gcov_info *unloaded_info; + struct dentry *dentry; + struct dentry **links; ++ int num_loaded; + char name[0]; + }; + +@@ -136,16 +138,37 @@ static const struct seq_operations gcov_ + }; + + /* +- * Return the profiling data set for a given node. This can either be the +- * original profiling data structure or a duplicate (also called "ghost") +- * in case the associated object file has been unloaded. ++ * Return a profiling data set associated with the given node. This is ++ * either a data set for a loaded object file or a data set copy in case ++ * all associated object files have been unloaded. + */ + static struct gcov_info *get_node_info(struct gcov_node *node) + { +- if (node->info) +- return node->info; ++ if (node->num_loaded > 0) ++ return node->loaded_info[0]; + +- return node->ghost; ++ return node->unloaded_info; ++} ++ ++/* ++ * Return a newly allocated profiling data set which contains the sum of ++ * all profiling data associated with the given node. ++ */ ++static struct gcov_info *get_accumulated_info(struct gcov_node *node) ++{ ++ struct gcov_info *info; ++ int i = 0; ++ ++ if (node->unloaded_info) ++ info = gcov_info_dup(node->unloaded_info); ++ else ++ info = gcov_info_dup(node->loaded_info[i++]); ++ if (!info) ++ return NULL; ++ for (; i < node->num_loaded; i++) ++ gcov_info_add(info, node->loaded_info[i]); ++ ++ return info; + } + + /* +@@ -163,9 +186,10 @@ static int gcov_seq_open(struct inode *i + mutex_lock(&node_lock); + /* + * Read from a profiling data copy to minimize reference tracking +- * complexity and concurrent access. ++ * complexity and concurrent access and to keep accumulating multiple ++ * profiling data sets associated with one node simple. + */ +- info = gcov_info_dup(get_node_info(node)); ++ info = get_accumulated_info(node); + if (!info) + goto out_unlock; + iter = gcov_iter_new(info); +@@ -225,12 +249,25 @@ static struct gcov_node *get_node_by_nam + return NULL; + } + ++/* ++ * Reset all profiling data associated with the specified node. ++ */ ++static void reset_node(struct gcov_node *node) ++{ ++ int i; ++ ++ if (node->unloaded_info) ++ gcov_info_reset(node->unloaded_info); ++ for (i = 0; i < node->num_loaded; i++) ++ gcov_info_reset(node->loaded_info[i]); ++} ++ + static void remove_node(struct gcov_node *node); + + /* + * write() implementation for gcov data files. Reset profiling data for the +- * associated file. If the object file has been unloaded (i.e. this is +- * a "ghost" node), remove the debug fs node as well. ++ * corresponding file. If all associated object files have been unloaded, ++ * remove the debug fs node as well. + */ + static ssize_t gcov_seq_write(struct file *file, const char __user *addr, + size_t len, loff_t *pos) +@@ -245,10 +282,10 @@ static ssize_t gcov_seq_write(struct fil + node = get_node_by_name(info->filename); + if (node) { + /* Reset counts or remove node for unloaded modules. */ +- if (node->ghost) ++ if (node->num_loaded == 0) + remove_node(node); + else +- gcov_info_reset(node->info); ++ reset_node(node); + } + /* Reset counts for open file. */ + gcov_info_reset(info); +@@ -378,7 +415,10 @@ static void init_node(struct gcov_node * + INIT_LIST_HEAD(&node->list); + INIT_LIST_HEAD(&node->children); + INIT_LIST_HEAD(&node->all); +- node->info = info; ++ if (node->loaded_info) { ++ node->loaded_info[0] = info; ++ node->num_loaded = 1; ++ } + node->parent = parent; + if (name) + strcpy(node->name, name); +@@ -394,9 +434,13 @@ static struct gcov_node *new_node(struct + struct gcov_node *node; + + node = kzalloc(sizeof(struct gcov_node) + strlen(name) + 1, GFP_KERNEL); +- if (!node) { +- pr_warning("out of memory\n"); +- return NULL; ++ if (!node) ++ goto err_nomem; ++ if (info) { ++ node->loaded_info = kcalloc(1, sizeof(struct gcov_info *), ++ GFP_KERNEL); ++ if (!node->loaded_info) ++ goto err_nomem; + } + init_node(node, info, name, parent); + /* Differentiate between gcov data file nodes and directory nodes. */ +@@ -416,6 +460,11 @@ static struct gcov_node *new_node(struct + list_add(&node->all, &all_head); + + return node; ++ ++err_nomem: ++ kfree(node); ++ pr_warning("out of memory\n"); ++ return NULL; + } + + /* Remove symbolic links associated with node. */ +@@ -441,8 +490,9 @@ static void release_node(struct gcov_nod + list_del(&node->all); + debugfs_remove(node->dentry); + remove_links(node); +- if (node->ghost) +- gcov_info_free(node->ghost); ++ kfree(node->loaded_info); ++ if (node->unloaded_info) ++ gcov_info_free(node->unloaded_info); + kfree(node); + } + +@@ -477,7 +527,7 @@ static struct gcov_node *get_child_by_na + + /* + * write() implementation for reset file. Reset all profiling data to zero +- * and remove ghost nodes. ++ * and remove nodes for which all associated object files are unloaded. + */ + static ssize_t reset_write(struct file *file, const char __user *addr, + size_t len, loff_t *pos) +@@ -487,8 +537,8 @@ static ssize_t reset_write(struct file * + mutex_lock(&node_lock); + restart: + list_for_each_entry(node, &all_head, all) { +- if (node->info) +- gcov_info_reset(node->info); ++ if (node->num_loaded > 0) ++ reset_node(node); + else if (list_empty(&node->children)) { + remove_node(node); + /* Several nodes may have gone - restart loop. */ +@@ -564,37 +614,115 @@ err_remove: + } + + /* +- * The profiling data set associated with this node is being unloaded. Store a +- * copy of the profiling data and turn this node into a "ghost". ++ * Associate a profiling data set with an existing node. Needs to be called ++ * with node_lock held. + */ +-static int ghost_node(struct gcov_node *node) ++static void add_info(struct gcov_node *node, struct gcov_info *info) + { +- node->ghost = gcov_info_dup(node->info); +- if (!node->ghost) { +- pr_warning("could not save data for '%s' (out of memory)\n", +- node->info->filename); +- return -ENOMEM; ++ struct gcov_info **loaded_info; ++ int num = node->num_loaded; ++ ++ /* ++ * Prepare new array. This is done first to simplify cleanup in ++ * case the new data set is incompatible, the node only contains ++ * unloaded data sets and there's not enough memory for the array. ++ */ ++ loaded_info = kcalloc(num + 1, sizeof(struct gcov_info *), GFP_KERNEL); ++ if (!loaded_info) { ++ pr_warning("could not add '%s' (out of memory)\n", ++ info->filename); ++ return; ++ } ++ memcpy(loaded_info, node->loaded_info, ++ num * sizeof(struct gcov_info *)); ++ loaded_info[num] = info; ++ /* Check if the new data set is compatible. */ ++ if (num == 0) { ++ /* ++ * A module was unloaded, modified and reloaded. The new ++ * data set replaces the copy of the last one. ++ */ ++ if (!gcov_info_is_compatible(node->unloaded_info, info)) { ++ pr_warning("discarding saved data for %s " ++ "(incompatible version)\n", info->filename); ++ gcov_info_free(node->unloaded_info); ++ node->unloaded_info = NULL; ++ } ++ } else { ++ /* ++ * Two different versions of the same object file are loaded. ++ * The initial one takes precedence. ++ */ ++ if (!gcov_info_is_compatible(node->loaded_info[0], info)) { ++ pr_warning("could not add '%s' (incompatible " ++ "version)\n", info->filename); ++ kfree(loaded_info); ++ return; ++ } + } +- node->info = NULL; ++ /* Overwrite previous array. */ ++ kfree(node->loaded_info); ++ node->loaded_info = loaded_info; ++ node->num_loaded = num + 1; ++} + +- return 0; ++/* ++ * Return the index of a profiling data set associated with a node. ++ */ ++static int get_info_index(struct gcov_node *node, struct gcov_info *info) ++{ ++ int i; ++ ++ for (i = 0; i < node->num_loaded; i++) { ++ if (node->loaded_info[i] == info) ++ return i; ++ } ++ return -ENOENT; + } + + /* +- * Profiling data for this node has been loaded again. Add profiling data +- * from previous instantiation and turn this node into a regular node. ++ * Save the data of a profiling data set which is being unloaded. + */ +-static void revive_node(struct gcov_node *node, struct gcov_info *info) ++static void save_info(struct gcov_node *node, struct gcov_info *info) + { +- if (gcov_info_is_compatible(node->ghost, info)) +- gcov_info_add(info, node->ghost); ++ if (node->unloaded_info) ++ gcov_info_add(node->unloaded_info, info); + else { +- pr_warning("discarding saved data for '%s' (version changed)\n", ++ node->unloaded_info = gcov_info_dup(info); ++ if (!node->unloaded_info) { ++ pr_warning("could not save data for '%s' " ++ "(out of memory)\n", info->filename); ++ } ++ } ++} ++ ++/* ++ * Disassociate a profiling data set from a node. Needs to be called with ++ * node_lock held. ++ */ ++static void remove_info(struct gcov_node *node, struct gcov_info *info) ++{ ++ int i; ++ ++ i = get_info_index(node, info); ++ if (i < 0) { ++ pr_warning("could not remove '%s' (not found)\n", + info->filename); ++ return; + } +- gcov_info_free(node->ghost); +- node->ghost = NULL; +- node->info = info; ++ if (gcov_persist) ++ save_info(node, info); ++ /* Shrink array. */ ++ node->loaded_info[i] = node->loaded_info[node->num_loaded - 1]; ++ node->num_loaded--; ++ if (node->num_loaded > 0) ++ return; ++ /* Last loaded data set was removed. */ ++ kfree(node->loaded_info); ++ node->loaded_info = NULL; ++ node->num_loaded = 0; ++ if (!node->unloaded_info) ++ remove_node(node); + } + + /* +@@ -609,30 +737,18 @@ void gcov_event(enum gcov_action action, + node = get_node_by_name(info->filename); + switch (action) { + case GCOV_ADD: +- /* Add new node or revive ghost. */ +- if (!node) { ++ if (node) ++ add_info(node, info); ++ else + add_node(info); +- break; +- } +- if (gcov_persist) +- revive_node(node, info); +- else { +- pr_warning("could not add '%s' (already exists)\n", +- info->filename); +- } + break; + case GCOV_REMOVE: +- /* Remove node or turn into ghost. */ +- if (!node) { ++ if (node) ++ remove_info(node, info); ++ else { + pr_warning("could not remove '%s' (not found)\n", + info->filename); +- break; + } +- if (gcov_persist) { +- if (!ghost_node(node)) +- break; +- } +- remove_node(node); + break; + } + mutex_unlock(&node_lock); diff --git a/queue-2.6.35/hid-set-report-id-properly-for-output-reports-on-the-control-endpoint.patch b/queue-2.6.35/hid-set-report-id-properly-for-output-reports-on-the-control-endpoint.patch new file mode 100644 index 00000000000..d70e9e16a20 --- /dev/null +++ b/queue-2.6.35/hid-set-report-id-properly-for-output-reports-on-the-control-endpoint.patch @@ -0,0 +1,40 @@ +From c29771c2d8ceb907ed45eb8c7fc0450308140aca Mon Sep 17 00:00:00 2001 +From: Alan Ott +Date: Tue, 17 Aug 2010 00:44:04 -0400 +Subject: HID: Set Report ID properly for Output reports on the Control endpoint. + +From: Alan Ott + +commit c29771c2d8ceb907ed45eb8c7fc0450308140aca upstream. + +When I made commit 29129a98e6fc89 ("HID: Send Report ID when numbered +reports are sent over the control endpoint"), I didn't account for *buf +not being the report ID anymore, as buf is incremented. + +Signed-off-by: Alan Ott +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hid/usbhid/hid-core.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -828,6 +828,7 @@ static int usbhid_output_raw_report(stru + } + } else { + int skipped_report_id = 0; ++ int report_id = buf[0]; + if (buf[0] == 0x0) { + /* Don't send the Report ID */ + buf++; +@@ -837,7 +838,7 @@ static int usbhid_output_raw_report(stru + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + HID_REQ_SET_REPORT, + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, +- ((report_type + 1) << 8) | *buf, ++ ((report_type + 1) << 8) | report_id, + interface->desc.bInterfaceNumber, buf, count, + USB_CTRL_SET_TIMEOUT); + /* count also the report id, if this was a numbered report. */ diff --git a/queue-2.6.35/hp_accel-add-quirks-for-hp-probook-532x-and-hp-mini-5102.patch b/queue-2.6.35/hp_accel-add-quirks-for-hp-probook-532x-and-hp-mini-5102.patch new file mode 100644 index 00000000000..217c1551b54 --- /dev/null +++ b/queue-2.6.35/hp_accel-add-quirks-for-hp-probook-532x-and-hp-mini-5102.patch @@ -0,0 +1,32 @@ +From 4e70598c3b56e6fec551454c495d4d4025834749 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 9 Sep 2010 16:37:31 -0700 +Subject: hp_accel: add quirks for HP ProBook 532x and HP Mini 5102 + +From: Takashi Iwai + +commit 4e70598c3b56e6fec551454c495d4d4025834749 upstream. + +Added missing axis-mapping for HP ProBook 532x and HP Mini 5102. + +Signed-off-by: Takashi Iwai +Cc: Eric Piel +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hwmon/hp_accel.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/hwmon/hp_accel.c ++++ b/drivers/hwmon/hp_accel.c +@@ -221,6 +221,8 @@ static struct dmi_system_id lis3lv02d_dm + AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left), + AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted), + AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap), ++ AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted), ++ AXIS_DMI_MATCH("Mini5102", "HP Mini 5102", xy_rotated_left_usd), + { NULL, } + /* Laptop models without axis info (yet): + * "NC6910" "HP Compaq 6910" diff --git a/queue-2.6.35/irda-off-by-one.patch b/queue-2.6.35/irda-off-by-one.patch new file mode 100644 index 00000000000..8932ac8d3f5 --- /dev/null +++ b/queue-2.6.35/irda-off-by-one.patch @@ -0,0 +1,33 @@ +From cf9b94f88bdbe8a02015fc30d7c232b2d262d4ad Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Sat, 4 Sep 2010 03:14:35 +0000 +Subject: irda: off by one + +From: Dan Carpenter + +commit cf9b94f88bdbe8a02015fc30d7c232b2d262d4ad upstream. + +This is an off by one. We would go past the end when we NUL terminate +the "value" string at end of the function. The "value" buffer is +allocated in irlan_client_parse_response() or +irlan_provider_parse_command(). + +CC: stable@kernel.org +Signed-off-by: Dan Carpenter +Signed-off-by: David S. Miller + +--- + net/irda/irlan/irlan_common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/irda/irlan/irlan_common.c ++++ b/net/irda/irlan/irlan_common.c +@@ -1102,7 +1102,7 @@ int irlan_extract_param(__u8 *buf, char + memcpy(&val_len, buf+n, 2); /* To avoid alignment problems */ + le16_to_cpus(&val_len); n+=2; + +- if (val_len > 1016) { ++ if (val_len >= 1016) { + IRDA_DEBUG(2, "%s(), parameter length to long\n", __func__ ); + return -RSP_INVALID_COMMAND_FORMAT; + } diff --git a/queue-2.6.35/libata-pata_via-revert-ata_wait_idle-removal-from-ata_sff-via_tf_load.patch b/queue-2.6.35/libata-pata_via-revert-ata_wait_idle-removal-from-ata_sff-via_tf_load.patch new file mode 100644 index 00000000000..c67cb1daee8 --- /dev/null +++ b/queue-2.6.35/libata-pata_via-revert-ata_wait_idle-removal-from-ata_sff-via_tf_load.patch @@ -0,0 +1,58 @@ +From 40c6023031369ae5573e622ca54fa3ffe89fb865 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Thu, 9 Sep 2010 17:13:31 +0200 +Subject: libata,pata_via: revert ata_wait_idle() removal from ata_sff/via_tf_load() + +From: Tejun Heo + +commit 40c6023031369ae5573e622ca54fa3ffe89fb865 upstream. + +Commit 978c0666 (libata: Remove excess delay in the tf_load path) +removed ata_wait_idle() from ata_sff_tf_load() and via_tf_load(). +This caused obscure detection problems in sata_sil. + + https://bugzilla.kernel.org/show_bug.cgi?id=16606 + +The commit was pure performance optimization. Revert it for now. + +Reported-by: Dieter Plaetinck +Reported-by: Jan Beulich +Bisected-by: gianluca +Signed-off-by: Jeff Garzik +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/ata/libata-sff.c | 3 +++ + drivers/ata/pata_via.c | 2 ++ + 2 files changed, 5 insertions(+) + +--- a/drivers/ata/libata-sff.c ++++ b/drivers/ata/libata-sff.c +@@ -418,6 +418,7 @@ void ata_sff_tf_load(struct ata_port *ap + if (ioaddr->ctl_addr) + iowrite8(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; ++ ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { +@@ -453,6 +454,8 @@ void ata_sff_tf_load(struct ata_port *ap + iowrite8(tf->device, ioaddr->device_addr); + VPRINTK("device 0x%X\n", tf->device); + } ++ ++ ata_wait_idle(ap); + } + EXPORT_SYMBOL_GPL(ata_sff_tf_load); + +--- a/drivers/ata/pata_via.c ++++ b/drivers/ata/pata_via.c +@@ -417,6 +417,8 @@ static void via_tf_load(struct ata_port + tf->lbam, + tf->lbah); + } ++ ++ ata_wait_idle(ap); + } + + static int via_port_start(struct ata_port *ap) diff --git a/queue-2.6.35/libata-skip-eh-autopsy-and-recovery-during-suspend.patch b/queue-2.6.35/libata-skip-eh-autopsy-and-recovery-during-suspend.patch new file mode 100644 index 00000000000..f76bb9df434 --- /dev/null +++ b/queue-2.6.35/libata-skip-eh-autopsy-and-recovery-during-suspend.patch @@ -0,0 +1,78 @@ +From e2f3d75fc0e4a0d03c61872bad39ffa2e74a04ff Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Tue, 7 Sep 2010 14:05:31 +0200 +Subject: libata: skip EH autopsy and recovery during suspend + +From: Tejun Heo + +commit e2f3d75fc0e4a0d03c61872bad39ffa2e74a04ff upstream. + +For some mysterious reason, certain hardware reacts badly to usual EH +actions while the system is going for suspend. As the devices won't +be needed until the system is resumed, ask EH to skip usual autopsy +and recovery and proceed directly to suspend. + +Signed-off-by: Tejun Heo +Tested-by: Stephan Diestelhorst +Signed-off-by: Jeff Garzik +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/ata/libata-core.c | 14 +++++++++++++- + drivers/ata/libata-eh.c | 4 ++++ + include/linux/libata.h | 1 + + 3 files changed, 18 insertions(+), 1 deletion(-) + +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -5434,6 +5434,7 @@ static int ata_host_request_pm(struct at + */ + int ata_host_suspend(struct ata_host *host, pm_message_t mesg) + { ++ unsigned int ehi_flags = ATA_EHI_QUIET; + int rc; + + /* +@@ -5442,7 +5443,18 @@ int ata_host_suspend(struct ata_host *ho + */ + ata_lpm_enable(host); + +- rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1); ++ /* ++ * On some hardware, device fails to respond after spun down ++ * for suspend. As the device won't be used before being ++ * resumed, we don't need to touch the device. Ask EH to skip ++ * the usual stuff and proceed directly to suspend. ++ * ++ * http://thread.gmane.org/gmane.linux.ide/46764 ++ */ ++ if (mesg.event == PM_EVENT_SUSPEND) ++ ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY; ++ ++ rc = ata_host_request_pm(host, mesg, 0, ehi_flags, 1); + if (rc == 0) + host->dev->power.power_state = mesg; + return rc; +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -3234,6 +3234,10 @@ static int ata_eh_skip_recovery(struct a + if (link->flags & ATA_LFLAG_DISABLED) + return 1; + ++ /* skip if explicitly requested */ ++ if (ehc->i.flags & ATA_EHI_NO_RECOVERY) ++ return 1; ++ + /* thaw frozen port and recover failed devices */ + if ((ap->pflags & ATA_PFLAG_FROZEN) || ata_link_nr_enabled(link)) + return 0; +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -335,6 +335,7 @@ enum { + ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ + ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ + ATA_EHI_QUIET = (1 << 3), /* be quiet */ ++ ATA_EHI_NO_RECOVERY = (1 << 4), /* no recovery */ + + ATA_EHI_DID_SOFTRESET = (1 << 16), /* already soft-reset this port */ + ATA_EHI_DID_HARDRESET = (1 << 17), /* already soft-reset this port */ diff --git a/queue-2.6.35/minix-fix-regression-in-minix_mkdir.patch b/queue-2.6.35/minix-fix-regression-in-minix_mkdir.patch new file mode 100644 index 00000000000..060c708e1a9 --- /dev/null +++ b/queue-2.6.35/minix-fix-regression-in-minix_mkdir.patch @@ -0,0 +1,36 @@ +From eee743fd7eac9f2ea69ad06d093dfb5a12538fe5 Mon Sep 17 00:00:00 2001 +From: Jorge Boncompte [DTI2] +Date: Thu, 9 Sep 2010 16:38:19 -0700 +Subject: minix: fix regression in minix_mkdir() + +From: Jorge Boncompte [DTI2] + +commit eee743fd7eac9f2ea69ad06d093dfb5a12538fe5 upstream. + +Commit 9eed1fb721c ("minix: replace inode uid,gid,mode init with helper") +broke directory creation on minix filesystems. + +Fix it by passing the needed mode flag to inode init helper. + +Signed-off-by: Jorge Boncompte [DTI2] +Cc: Dmitry Monakhov +Cc: Al Viro +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/minix/namei.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/minix/namei.c ++++ b/fs/minix/namei.c +@@ -115,7 +115,7 @@ static int minix_mkdir(struct inode * di + + inode_inc_link_count(dir); + +- inode = minix_new_inode(dir, mode, &err); ++ inode = minix_new_inode(dir, S_IFDIR | mode, &err); + if (!inode) + goto out_dir; + diff --git a/queue-2.6.35/mmc-build-fix-mmc_pm_notify-is-only-available-with-config_pm-y.patch b/queue-2.6.35/mmc-build-fix-mmc_pm_notify-is-only-available-with-config_pm-y.patch new file mode 100644 index 00000000000..906afe4b626 --- /dev/null +++ b/queue-2.6.35/mmc-build-fix-mmc_pm_notify-is-only-available-with-config_pm-y.patch @@ -0,0 +1,42 @@ +From 81ca03a0e2ea0207b2df80e0edcf4c775c07a505 Mon Sep 17 00:00:00 2001 +From: Uwe Kleine-König +Date: Wed, 18 Aug 2010 09:25:38 -0700 +Subject: mmc: build fix: mmc_pm_notify is only available with CONFIG_PM=y +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +commit 81ca03a0e2ea0207b2df80e0edcf4c775c07a505 upstream. + +This fixes a build breakage introduced by commit 4c2ef25fe0b8 ("mmc: fix +all hangs related to mmc/sd card insert/removal during suspend/resume") + +Cc: David Brownell +Cc: Alan Stern +Cc: linux-mmc@vger.kernel.org +Cc: Andrew Morton +Signed-off-by: Uwe Kleine-König +Acked-by: Kukjin Kim +Acked-by: Maxim Levitsky +Acked-by: Randy Dunlap +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/mmc/core/host.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/mmc/core/host.c ++++ b/drivers/mmc/core/host.c +@@ -86,7 +86,9 @@ struct mmc_host *mmc_alloc_host(int extr + init_waitqueue_head(&host->wq); + INIT_DELAYED_WORK(&host->detect, mmc_rescan); + INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable); ++#ifdef CONFIG_PM + host->pm_notify.notifier_call = mmc_pm_notify; ++#endif + + /* + * By default, hosts do not support SGIO or large requests. diff --git a/queue-2.6.35/mmc-fix-all-hangs-related-to-mmc-sd-card-insert-removal-during-suspend-resume.patch b/queue-2.6.35/mmc-fix-all-hangs-related-to-mmc-sd-card-insert-removal-during-suspend-resume.patch new file mode 100644 index 00000000000..219142ea306 --- /dev/null +++ b/queue-2.6.35/mmc-fix-all-hangs-related-to-mmc-sd-card-insert-removal-during-suspend-resume.patch @@ -0,0 +1,217 @@ +From 4c2ef25fe0b847d2ae818f74758ddb0be1c27d8e Mon Sep 17 00:00:00 2001 +From: Maxim Levitsky +Date: Tue, 10 Aug 2010 18:01:41 -0700 +Subject: mmc: fix all hangs related to mmc/sd card insert/removal during suspend/resume + +From: Maxim Levitsky + +commit 4c2ef25fe0b847d2ae818f74758ddb0be1c27d8e upstream. + +If you don't use CONFIG_MMC_UNSAFE_RESUME, as soon as you attempt to +suspend, the card will be removed, therefore this patch doesn't change the +behavior of this option. + +However the removal will be done by pm notifier, which runs while +userspace is still not frozen and thus can freely use del_gendisk, without +the risk of deadlock which would happen otherwise. + +Card detect workqueue is now disabled while userspace is frozen, Therefore +if you do use CONFIG_MMC_UNSAFE_RESUME, and remove the card during +suspend, the removal will be detected as soon as userspace is unfrozen, +again at the moment it is safe to call del_gendisk. + +Tested with and without CONFIG_MMC_UNSAFE_RESUME with suspend and hibernate. + +[akpm@linux-foundation.org: clean up function prototype] +[akpm@linux-foundation.org: fix CONFIG_PM-n linkage, small cleanups] +[akpm@linux-foundation.org: coding-style fixes] +Signed-off-by: Maxim Levitsky +Cc: David Brownell +Cc: Alan Stern +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Lee Jones +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/mmc/core/core.c | 83 ++++++++++++++++++++++++++++++++--------------- + drivers/mmc/core/host.c | 4 ++ + include/linux/mmc/host.h | 3 + + 3 files changed, 64 insertions(+), 26 deletions(-) + +--- a/drivers/mmc/core/core.c ++++ b/drivers/mmc/core/core.c +@@ -1057,6 +1057,17 @@ void mmc_rescan(struct work_struct *work + container_of(work, struct mmc_host, detect.work); + u32 ocr; + int err; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ if (host->rescan_disable) { ++ spin_unlock_irqrestore(&host->lock, flags); ++ return; ++ } ++ ++ spin_unlock_irqrestore(&host->lock, flags); ++ + + mmc_bus_get(host); + +@@ -1266,19 +1277,6 @@ int mmc_suspend_host(struct mmc_host *ho + if (host->bus_ops && !host->bus_dead) { + if (host->bus_ops->suspend) + err = host->bus_ops->suspend(host); +- if (err == -ENOSYS || !host->bus_ops->resume) { +- /* +- * We simply "remove" the card in this case. +- * It will be redetected on resume. +- */ +- if (host->bus_ops->remove) +- host->bus_ops->remove(host); +- mmc_claim_host(host); +- mmc_detach_bus(host); +- mmc_release_host(host); +- host->pm_flags = 0; +- err = 0; +- } + } + mmc_bus_put(host); + +@@ -1310,28 +1308,61 @@ int mmc_resume_host(struct mmc_host *hos + printk(KERN_WARNING "%s: error %d during resume " + "(card was removed?)\n", + mmc_hostname(host), err); +- if (host->bus_ops->remove) +- host->bus_ops->remove(host); +- mmc_claim_host(host); +- mmc_detach_bus(host); +- mmc_release_host(host); +- /* no need to bother upper layers */ + err = 0; + } + } + mmc_bus_put(host); + +- /* +- * We add a slight delay here so that resume can progress +- * in parallel. +- */ +- mmc_detect_change(host, 1); +- + return err; + } +- + EXPORT_SYMBOL(mmc_resume_host); + ++/* Do the card removal on suspend if card is assumed removeable ++ * Do that in pm notifier while userspace isn't yet frozen, so we will be able ++ to sync the card. ++*/ ++int mmc_pm_notify(struct notifier_block *notify_block, ++ unsigned long mode, void *unused) ++{ ++ struct mmc_host *host = container_of( ++ notify_block, struct mmc_host, pm_notify); ++ unsigned long flags; ++ ++ ++ switch (mode) { ++ case PM_HIBERNATION_PREPARE: ++ case PM_SUSPEND_PREPARE: ++ ++ spin_lock_irqsave(&host->lock, flags); ++ host->rescan_disable = 1; ++ spin_unlock_irqrestore(&host->lock, flags); ++ cancel_delayed_work_sync(&host->detect); ++ ++ if (!host->bus_ops || host->bus_ops->suspend) ++ break; ++ ++ mmc_claim_host(host); ++ ++ if (host->bus_ops->remove) ++ host->bus_ops->remove(host); ++ ++ mmc_detach_bus(host); ++ mmc_release_host(host); ++ host->pm_flags = 0; ++ break; ++ ++ case PM_POST_SUSPEND: ++ case PM_POST_HIBERNATION: ++ ++ spin_lock_irqsave(&host->lock, flags); ++ host->rescan_disable = 0; ++ spin_unlock_irqrestore(&host->lock, flags); ++ mmc_detect_change(host, 0); ++ ++ } ++ ++ return 0; ++} + #endif + + static int __init mmc_init(void) +--- a/drivers/mmc/core/host.c ++++ b/drivers/mmc/core/host.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include + +@@ -85,6 +86,7 @@ struct mmc_host *mmc_alloc_host(int extr + init_waitqueue_head(&host->wq); + INIT_DELAYED_WORK(&host->detect, mmc_rescan); + INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable); ++ host->pm_notify.notifier_call = mmc_pm_notify; + + /* + * By default, hosts do not support SGIO or large requests. +@@ -133,6 +135,7 @@ int mmc_add_host(struct mmc_host *host) + #endif + + mmc_start_host(host); ++ register_pm_notifier(&host->pm_notify); + + return 0; + } +@@ -149,6 +152,7 @@ EXPORT_SYMBOL(mmc_add_host); + */ + void mmc_remove_host(struct mmc_host *host) + { ++ unregister_pm_notifier(&host->pm_notify); + mmc_stop_host(host); + + #ifdef CONFIG_DEBUG_FS +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -124,6 +124,7 @@ struct mmc_host { + unsigned int f_min; + unsigned int f_max; + u32 ocr_avail; ++ struct notifier_block pm_notify; + + #define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */ + #define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ +@@ -183,6 +184,7 @@ struct mmc_host { + + /* Only used with MMC_CAP_DISABLE */ + int enabled; /* host is enabled */ ++ int rescan_disable; /* disable card detection */ + int nesting_cnt; /* "enable" nesting count */ + int en_dis_recurs; /* detect recursion */ + unsigned int disable_delay; /* disable delay in msecs */ +@@ -257,6 +259,7 @@ int mmc_card_can_sleep(struct mmc_host * + int mmc_host_enable(struct mmc_host *host); + int mmc_host_disable(struct mmc_host *host); + int mmc_host_lazy_disable(struct mmc_host *host); ++int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *); + + static inline void mmc_set_disable_delay(struct mmc_host *host, + unsigned int disable_delay) diff --git a/queue-2.6.35/mmc-fix-the-use-of-kunmap_atomic-in-tmio_mmc.h.patch b/queue-2.6.35/mmc-fix-the-use-of-kunmap_atomic-in-tmio_mmc.h.patch new file mode 100644 index 00000000000..ceca7d2256d --- /dev/null +++ b/queue-2.6.35/mmc-fix-the-use-of-kunmap_atomic-in-tmio_mmc.h.patch @@ -0,0 +1,84 @@ +From 5600efb1bc2745d93ae0bc08130117a84f2b9d69 Mon Sep 17 00:00:00 2001 +From: Guennadi Liakhovetski +Date: Thu, 9 Sep 2010 16:37:43 -0700 +Subject: mmc: fix the use of kunmap_atomic() in tmio_mmc.h + +From: Guennadi Liakhovetski + +commit 5600efb1bc2745d93ae0bc08130117a84f2b9d69 upstream. + +kunmap_atomic() takes the cookie, returned by the kmap_atomic() as its +argument and not the page address, used as an argument to kmap_atomic(). +This patch fixes the compile error: + +In file included from drivers/mmc/host/tmio_mmc.c:37: +drivers/mmc/host/tmio_mmc.h: In function 'tmio_mmc_kunmap_atomic': +drivers/mmc/host/tmio_mmc.h:192: error: negative width in bit-field '' + +Signed-off-by: Guennadi Liakhovetski +Acked-by: Eric Miao +Tested-by: Magnus Damm +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/mmc/host/tmio_mmc.c | 7 ++++--- + drivers/mmc/host/tmio_mmc.h | 8 +++----- + 2 files changed, 7 insertions(+), 8 deletions(-) + +--- a/drivers/mmc/host/tmio_mmc.c ++++ b/drivers/mmc/host/tmio_mmc.c +@@ -164,6 +164,7 @@ tmio_mmc_start_command(struct tmio_mmc_h + static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) + { + struct mmc_data *data = host->data; ++ void *sg_virt; + unsigned short *buf; + unsigned int count; + unsigned long flags; +@@ -173,8 +174,8 @@ static void tmio_mmc_pio_irq(struct tmio + return; + } + +- buf = (unsigned short *)(tmio_mmc_kmap_atomic(host, &flags) + +- host->sg_off); ++ sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags); ++ buf = (unsigned short *)(sg_virt + host->sg_off); + + count = host->sg_ptr->length - host->sg_off; + if (count > data->blksz) +@@ -191,7 +192,7 @@ static void tmio_mmc_pio_irq(struct tmio + + host->sg_off += count; + +- tmio_mmc_kunmap_atomic(host, &flags); ++ tmio_mmc_kunmap_atomic(sg_virt, &flags); + + if (host->sg_off == host->sg_ptr->length) + tmio_mmc_next_sg(host); +--- a/drivers/mmc/host/tmio_mmc.h ++++ b/drivers/mmc/host/tmio_mmc.h +@@ -174,19 +174,17 @@ static inline int tmio_mmc_next_sg(struc + return --host->sg_len; + } + +-static inline char *tmio_mmc_kmap_atomic(struct tmio_mmc_host *host, ++static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, + unsigned long *flags) + { +- struct scatterlist *sg = host->sg_ptr; +- + local_irq_save(*flags); + return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; + } + +-static inline void tmio_mmc_kunmap_atomic(struct tmio_mmc_host *host, ++static inline void tmio_mmc_kunmap_atomic(void *virt, + unsigned long *flags) + { +- kunmap_atomic(sg_page(host->sg_ptr), KM_BIO_SRC_IRQ); ++ kunmap_atomic(virt, KM_BIO_SRC_IRQ); + local_irq_restore(*flags); + } + diff --git a/queue-2.6.35/o_direct-fix-the-splitting-up-of-contiguous-i-o.patch b/queue-2.6.35/o_direct-fix-the-splitting-up-of-contiguous-i-o.patch new file mode 100644 index 00000000000..abb9edd67eb --- /dev/null +++ b/queue-2.6.35/o_direct-fix-the-splitting-up-of-contiguous-i-o.patch @@ -0,0 +1,62 @@ +From 7a801ac6f5067539ceb5fad0fe90ec49fc156e47 Mon Sep 17 00:00:00 2001 +From: Jeff Moyer +Date: Thu, 9 Sep 2010 16:37:33 -0700 +Subject: O_DIRECT: fix the splitting up of contiguous I/O + +From: Jeff Moyer + +commit 7a801ac6f5067539ceb5fad0fe90ec49fc156e47 upstream. + +commit c2c6ca4 (direct-io: do not merge logically non-contiguous requests) +introduced a bug whereby all O_DIRECT I/Os were submitted a page at a time +to the block layer. The problem is that the code expected +dio->block_in_file to correspond to the current page in the dio. In fact, +it corresponds to the previous page submitted via submit_page_section. +This was purely an oversight, as the dio->cur_page_fs_offset field was +introduced for just this purpose. This patch simply uses the correct +variable when calculating whether there is a mismatch between contiguous +logical blocks and contiguous physical blocks (as described in the +comments). + +I also switched the if conditional following this check to an else if, to +ensure that we never call dio_bio_submit twice for the same dio (in +theory, this should not happen, anyway). + +I've tested this by running blktrace and verifying that a 64KB I/O was +submitted as a single I/O. I also ran the patched kernel through +xfstests' aio tests using xfs, ext4 (with 1k and 4k block sizes) and btrfs +and verified that there were no regressions as compared to an unpatched +kernel. + +Signed-off-by: Jeff Moyer +Acked-by: Josef Bacik +Cc: Christoph Hellwig +Cc: Chris Mason +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/direct-io.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/direct-io.c ++++ b/fs/direct-io.c +@@ -634,7 +634,7 @@ static int dio_send_cur_page(struct dio + int ret = 0; + + if (dio->bio) { +- loff_t cur_offset = dio->block_in_file << dio->blkbits; ++ loff_t cur_offset = dio->cur_page_fs_offset; + loff_t bio_next_offset = dio->logical_offset_in_bio + + dio->bio->bi_size; + +@@ -659,7 +659,7 @@ static int dio_send_cur_page(struct dio + * Submit now if the underlying fs is about to perform a + * metadata read + */ +- if (dio->boundary) ++ else if (dio->boundary) + dio_bio_submit(dio); + } + diff --git a/queue-2.6.35/oprofile-fix-crash-when-accessing-freed-task-structs.patch b/queue-2.6.35/oprofile-fix-crash-when-accessing-freed-task-structs.patch new file mode 100644 index 00000000000..96d453947fc --- /dev/null +++ b/queue-2.6.35/oprofile-fix-crash-when-accessing-freed-task-structs.patch @@ -0,0 +1,132 @@ +From 750d857c682f4db60d14722d430c7ccc35070962 Mon Sep 17 00:00:00 2001 +From: Robert Richter +Date: Fri, 13 Aug 2010 16:29:04 +0200 +Subject: oprofile: fix crash when accessing freed task structs + +From: Robert Richter + +commit 750d857c682f4db60d14722d430c7ccc35070962 upstream. + +This patch fixes a crash during shutdown reported below. The crash is +caused by accessing already freed task structs. The fix changes the +order for registering and unregistering notifier callbacks. + +All notifiers must be initialized before buffers start working. To +stop buffer synchronization we cancel all workqueues, unregister the +notifier callback and then flush all buffers. After all of this we +finally can free all tasks listed. + +This should avoid accessing freed tasks. + +On 22.07.10 01:14:40, Benjamin Herrenschmidt wrote: + +> So the initial observation is a spinlock bad magic followed by a crash +> in the spinlock debug code: +> +> [ 1541.586531] BUG: spinlock bad magic on CPU#5, events/5/136 +> [ 1541.597564] Unable to handle kernel paging request for data at address 0x6b6b6b6b6b6b6d03 +> +> Backtrace looks like: +> +> spin_bug+0x74/0xd4 +> ._raw_spin_lock+0x48/0x184 +> ._spin_lock+0x10/0x24 +> .get_task_mm+0x28/0x8c +> .sync_buffer+0x1b4/0x598 +> .wq_sync_buffer+0xa0/0xdc +> .worker_thread+0x1d8/0x2a8 +> .kthread+0xa8/0xb4 +> .kernel_thread+0x54/0x70 +> +> So we are accessing a freed task struct in the work queue when +> processing the samples. + +Reported-by: Benjamin Herrenschmidt +Signed-off-by: Robert Richter +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/oprofile/buffer_sync.c | 27 ++++++++++++++------------- + drivers/oprofile/cpu_buffer.c | 2 -- + 2 files changed, 14 insertions(+), 15 deletions(-) + +--- a/drivers/oprofile/buffer_sync.c ++++ b/drivers/oprofile/buffer_sync.c +@@ -141,16 +141,6 @@ static struct notifier_block module_load + .notifier_call = module_load_notify, + }; + +- +-static void end_sync(void) +-{ +- end_cpu_work(); +- /* make sure we don't leak task structs */ +- process_task_mortuary(); +- process_task_mortuary(); +-} +- +- + int sync_start(void) + { + int err; +@@ -158,7 +148,7 @@ int sync_start(void) + if (!zalloc_cpumask_var(&marked_cpus, GFP_KERNEL)) + return -ENOMEM; + +- start_cpu_work(); ++ mutex_lock(&buffer_mutex); + + err = task_handoff_register(&task_free_nb); + if (err) +@@ -173,7 +163,10 @@ int sync_start(void) + if (err) + goto out4; + ++ start_cpu_work(); ++ + out: ++ mutex_unlock(&buffer_mutex); + return err; + out4: + profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); +@@ -182,7 +175,6 @@ out3: + out2: + task_handoff_unregister(&task_free_nb); + out1: +- end_sync(); + free_cpumask_var(marked_cpus); + goto out; + } +@@ -190,11 +182,20 @@ out1: + + void sync_stop(void) + { ++ /* flush buffers */ ++ mutex_lock(&buffer_mutex); ++ end_cpu_work(); + unregister_module_notifier(&module_load_nb); + profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); + profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); + task_handoff_unregister(&task_free_nb); +- end_sync(); ++ mutex_unlock(&buffer_mutex); ++ flush_scheduled_work(); ++ ++ /* make sure we don't leak task structs */ ++ process_task_mortuary(); ++ process_task_mortuary(); ++ + free_cpumask_var(marked_cpus); + } + +--- a/drivers/oprofile/cpu_buffer.c ++++ b/drivers/oprofile/cpu_buffer.c +@@ -120,8 +120,6 @@ void end_cpu_work(void) + + cancel_delayed_work(&b->work); + } +- +- flush_scheduled_work(); + } + + /* diff --git a/queue-2.6.35/oprofile-x86-fix-init_sysfs-error-handling.patch b/queue-2.6.35/oprofile-x86-fix-init_sysfs-error-handling.patch new file mode 100644 index 00000000000..aa3211bfc28 --- /dev/null +++ b/queue-2.6.35/oprofile-x86-fix-init_sysfs-error-handling.patch @@ -0,0 +1,59 @@ +From 10f0412f57f2a76a90eff4376f59cbb0a39e4e18 Mon Sep 17 00:00:00 2001 +From: Robert Richter +Date: Mon, 30 Aug 2010 10:56:18 +0200 +Subject: oprofile, x86: fix init_sysfs error handling + +From: Robert Richter + +commit 10f0412f57f2a76a90eff4376f59cbb0a39e4e18 upstream. + +On failure init_sysfs() might not properly free resources. The error +code of the function is not checked. And, when reinitializing the exit +function might be called twice. This patch fixes all this. + +Signed-off-by: Robert Richter +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/oprofile/nmi_int.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +--- a/arch/x86/oprofile/nmi_int.c ++++ b/arch/x86/oprofile/nmi_int.c +@@ -568,8 +568,13 @@ static int __init init_sysfs(void) + int error; + + error = sysdev_class_register(&oprofile_sysclass); +- if (!error) +- error = sysdev_register(&device_oprofile); ++ if (error) ++ return error; ++ ++ error = sysdev_register(&device_oprofile); ++ if (error) ++ sysdev_class_unregister(&oprofile_sysclass); ++ + return error; + } + +@@ -695,6 +700,8 @@ int __init op_nmi_init(struct oprofile_o + char *cpu_type = NULL; + int ret = 0; + ++ using_nmi = 0; ++ + if (!cpu_has_apic) + return -ENODEV; + +@@ -774,7 +781,10 @@ int __init op_nmi_init(struct oprofile_o + + mux_init(ops); + +- init_sysfs(); ++ ret = init_sysfs(); ++ if (ret) ++ return ret; ++ + using_nmi = 1; + printk(KERN_INFO "oprofile: using NMI interrupt.\n"); + return 0; diff --git a/queue-2.6.35/oprofile-x86-fix-init_sysfs-function-stub.patch b/queue-2.6.35/oprofile-x86-fix-init_sysfs-function-stub.patch new file mode 100644 index 00000000000..78e2ad4cd7a --- /dev/null +++ b/queue-2.6.35/oprofile-x86-fix-init_sysfs-function-stub.patch @@ -0,0 +1,48 @@ +From 269f45c25028c75fe10e6d9be86e7202ab461fbc Mon Sep 17 00:00:00 2001 +From: Robert Richter +Date: Wed, 1 Sep 2010 14:50:50 +0200 +Subject: oprofile, x86: fix init_sysfs() function stub +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Robert Richter + +commit 269f45c25028c75fe10e6d9be86e7202ab461fbc upstream. + +The use of the return value of init_sysfs() with commit + + 10f0412 oprofile, x86: fix init_sysfs error handling + +discovered the following build error for !CONFIG_PM: + + .../linux/arch/x86/oprofile/nmi_int.c: In function ‘op_nmi_init’: + .../linux/arch/x86/oprofile/nmi_int.c:784: error: expected expression before ‘do’ + make[2]: *** [arch/x86/oprofile/nmi_int.o] Error 1 + make[1]: *** [arch/x86/oprofile] Error 2 + +This patch fixes this. + +Reported-by: Ingo Molnar +Signed-off-by: Robert Richter +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/oprofile/nmi_int.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/arch/x86/oprofile/nmi_int.c ++++ b/arch/x86/oprofile/nmi_int.c +@@ -585,8 +585,10 @@ static void exit_sysfs(void) + } + + #else +-#define init_sysfs() do { } while (0) +-#define exit_sysfs() do { } while (0) ++ ++static inline int init_sysfs(void) { return 0; } ++static inline void exit_sysfs(void) { } ++ + #endif /* CONFIG_PM */ + + static int __init p4_init(char **cpu_type) diff --git a/queue-2.6.35/series b/queue-2.6.35/series index 3ab238e77d5..c5b452efbb4 100644 --- a/queue-2.6.35/series +++ b/queue-2.6.35/series @@ -62,3 +62,24 @@ alsa-hda-patch_nvhdmi.c-add-missing-codec-ids-unify-names.patch swap-prevent-reuse-during-hibernation.patch swap-discard-while-swapping-only-if-swap_flag_discard.patch swap-do-not-send-discards-as-barriers.patch +sysfs-checking-for-null-instead-of-err_ptr.patch +oprofile-fix-crash-when-accessing-freed-task-structs.patch +oprofile-x86-fix-init_sysfs-error-handling.patch +oprofile-x86-fix-init_sysfs-function-stub.patch +hid-set-report-id-properly-for-output-reports-on-the-control-endpoint.patch +libata-skip-eh-autopsy-and-recovery-during-suspend.patch +libata-pata_via-revert-ata_wait_idle-removal-from-ata_sff-via_tf_load.patch +ahci-fix-hang-on-failed-softreset.patch +o_direct-fix-the-splitting-up-of-contiguous-i-o.patch +tracing-fix-a-race-in-function-profile.patch +tracing-do-not-allow-llseek-to-set_ftrace_filter.patch +tracing-t_start-reset-ftrace_iter_hash-in-case-of-seek-pread.patch +irda-off-by-one.patch +hp_accel-add-quirks-for-hp-probook-532x-and-hp-mini-5102.patch +gcov-fix-null-pointer-dereference-for-certain-module-types.patch +tmio_mmc-don-t-clear-unhandled-pending-interrupts.patch +mmc-fix-the-use-of-kunmap_atomic-in-tmio_mmc.h.patch +mmc-fix-all-hangs-related-to-mmc-sd-card-insert-removal-during-suspend-resume.patch +mmc-build-fix-mmc_pm_notify-is-only-available-with-config_pm-y.patch +statfs-gives-estale-error.patch +minix-fix-regression-in-minix_mkdir.patch diff --git a/queue-2.6.35/statfs-gives-estale-error.patch b/queue-2.6.35/statfs-gives-estale-error.patch new file mode 100644 index 00000000000..0d5a67b472a --- /dev/null +++ b/queue-2.6.35/statfs-gives-estale-error.patch @@ -0,0 +1,52 @@ +From fbf3fdd2443965d9ba6fb4b5fecd1f6e0847218f Mon Sep 17 00:00:00 2001 +From: Menyhart Zoltan +Date: Sun, 12 Sep 2010 19:55:26 -0400 +Subject: statfs() gives ESTALE error + +From: Menyhart Zoltan + +commit fbf3fdd2443965d9ba6fb4b5fecd1f6e0847218f upstream. + +Hi, + +An NFS client executes a statfs("file", &buff) call. +"file" exists / existed, the client has read / written it, +but it has already closed it. + +user_path(pathname, &path) looks up "file" successfully in the +directory-cache and restarts the aging timer of the directory-entry. +Even if "file" has already been removed from the server, because the +lookupcache=positive option I use, keeps the entries valid for a while. + +nfs_statfs() returns ESTALE if "file" has already been removed from the +server. + +If the user application repeats the statfs("file", &buff) call, we +are stuck: "file" remains young forever in the directory-cache. + +Signed-off-by: Zoltan Menyhart +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/super.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/fs/nfs/super.c ++++ b/fs/nfs/super.c +@@ -431,7 +431,15 @@ static int nfs_statfs(struct dentry *den + goto out_err; + + error = server->nfs_client->rpc_ops->statfs(server, fh, &res); ++ if (unlikely(error == -ESTALE)) { ++ struct dentry *pd_dentry; + ++ pd_dentry = dget_parent(dentry); ++ if (pd_dentry != NULL) { ++ nfs_zap_caches(pd_dentry->d_inode); ++ dput(pd_dentry); ++ } ++ } + nfs_free_fattr(res.fattr); + if (error < 0) + goto out_err; diff --git a/queue-2.6.35/sysfs-checking-for-null-instead-of-err_ptr.patch b/queue-2.6.35/sysfs-checking-for-null-instead-of-err_ptr.patch new file mode 100644 index 00000000000..55173648ad8 --- /dev/null +++ b/queue-2.6.35/sysfs-checking-for-null-instead-of-err_ptr.patch @@ -0,0 +1,30 @@ +From 57f9bdac2510cd7fda58e4a111d250861eb1ebeb Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Wed, 25 Aug 2010 09:12:29 +0200 +Subject: sysfs: checking for NULL instead of ERR_PTR + +From: Dan Carpenter + +commit 57f9bdac2510cd7fda58e4a111d250861eb1ebeb upstream. + +d_path() returns an ERR_PTR and it doesn't return NULL. + +Signed-off-by: Dan Carpenter +Reviewed-by: "Eric W. Biederman" +Signed-off-by: Greg Kroah-Hartman + +--- + fs/sysfs/file.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/sysfs/file.c ++++ b/fs/sysfs/file.c +@@ -340,7 +340,7 @@ static int sysfs_open_file(struct inode + char *p; + + p = d_path(&file->f_path, last_sysfs_file, sizeof(last_sysfs_file)); +- if (p) ++ if (!IS_ERR(p)) + memmove(last_sysfs_file, p, strlen(p) + 1); + + /* need attr_sd for attr and ops, its parent for kobj */ diff --git a/queue-2.6.35/tmio_mmc-don-t-clear-unhandled-pending-interrupts.patch b/queue-2.6.35/tmio_mmc-don-t-clear-unhandled-pending-interrupts.patch new file mode 100644 index 00000000000..dfde0166b8e --- /dev/null +++ b/queue-2.6.35/tmio_mmc-don-t-clear-unhandled-pending-interrupts.patch @@ -0,0 +1,53 @@ +From b78d6c5f51935ba89df8db33a57bacb547aa7325 Mon Sep 17 00:00:00 2001 +From: Yusuke Goda +Date: Thu, 9 Sep 2010 16:37:39 -0700 +Subject: tmio_mmc: don't clear unhandled pending interrupts + +From: Yusuke Goda + +commit b78d6c5f51935ba89df8db33a57bacb547aa7325 upstream. + +Previously, it was possible for ack_mmc_irqs() to clear pending interrupt +bits in the CTL_STATUS register, even though the interrupt handler had not +been called. This was because of a race that existed when doing a +read-modify-write sequence on CTL_STATUS. After the read step in this +sequence, if an interrupt occurred (causing one of the bits in CTL_STATUS +to be set) the write step would inadvertently clear it. + +Observed with the TMIO_STAT_RXRDY bit together with CMD53 on AR6002 and +BCM4318 SDIO cards in polled mode. + +This patch eliminates this race by only writing to CTL_STATUS and clearing +the interrupts that were passed as an argument to ack_mmc_irqs()." + +[matt@console-pimps.org: rewrote changelog] +Signed-off-by: Yusuke Goda +Acked-by: Magnus Damm " +Tested-by: Arnd Hannemann " +Acked-by: Ian Molton +Cc: Matt Fleming +Cc: Samuel Ortiz +Cc: Paul Mundt +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/mmc/host/tmio_mmc.h | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- a/drivers/mmc/host/tmio_mmc.h ++++ b/drivers/mmc/host/tmio_mmc.h +@@ -82,10 +82,7 @@ + + #define ack_mmc_irqs(host, i) \ + do { \ +- u32 mask;\ +- mask = sd_ctrl_read32((host), CTL_STATUS); \ +- mask &= ~((i) & TMIO_MASK_IRQ); \ +- sd_ctrl_write32((host), CTL_STATUS, mask); \ ++ sd_ctrl_write32((host), CTL_STATUS, ~(i)); \ + } while (0) + + diff --git a/queue-2.6.35/tracing-do-not-allow-llseek-to-set_ftrace_filter.patch b/queue-2.6.35/tracing-do-not-allow-llseek-to-set_ftrace_filter.patch new file mode 100644 index 00000000000..57336fc4c32 --- /dev/null +++ b/queue-2.6.35/tracing-do-not-allow-llseek-to-set_ftrace_filter.patch @@ -0,0 +1,54 @@ +From 9c55cb12c1c172e2d51e85fbb5a4796ca86b77e7 Mon Sep 17 00:00:00 2001 +From: Steven Rostedt +Date: Wed, 8 Sep 2010 11:20:37 -0400 +Subject: tracing: Do not allow llseek to set_ftrace_filter + +From: Steven Rostedt + +commit 9c55cb12c1c172e2d51e85fbb5a4796ca86b77e7 upstream. + +Reading the file set_ftrace_filter does three things. + +1) shows whether or not filters are set for the function tracer +2) shows what functions are set for the function tracer +3) shows what triggers are set on any functions + +3 is independent from 1 and 2. + +The way this file currently works is that it is a state machine, +and as you read it, it may change state. But this assumption breaks +when you use lseek() on the file. The state machine gets out of sync +and the t_show() may use the wrong pointer and cause a kernel oops. + +Luckily, this will only kill the app that does the lseek, but the app +dies while holding a mutex. This prevents anyone else from using the +set_ftrace_filter file (or any other function tracing file for that matter). + +A real fix for this is to rewrite the code, but that is too much for +a -rc release or stable. This patch simply disables llseek on the +set_ftrace_filter() file for now, and we can do the proper fix for the +next major release. + +Reported-by: Robert Swiecki +Cc: Chris Wright +Cc: Tavis Ormandy +Cc: Eugene Teo +Cc: vendor-sec@lst.de +Signed-off-by: Steven Rostedt +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/trace/ftrace.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -2417,7 +2417,7 @@ static const struct file_operations ftra + .open = ftrace_filter_open, + .read = seq_read, + .write = ftrace_filter_write, +- .llseek = ftrace_regex_lseek, ++ .llseek = no_llseek, + .release = ftrace_filter_release, + }; + diff --git a/queue-2.6.35/tracing-fix-a-race-in-function-profile.patch b/queue-2.6.35/tracing-fix-a-race-in-function-profile.patch new file mode 100644 index 00000000000..d46dfabb1b1 --- /dev/null +++ b/queue-2.6.35/tracing-fix-a-race-in-function-profile.patch @@ -0,0 +1,76 @@ +From 3aaba20f26f58843e8f20611e5c0b1c06954310f Mon Sep 17 00:00:00 2001 +From: Li Zefan +Date: Mon, 23 Aug 2010 16:50:12 +0800 +Subject: tracing: Fix a race in function profile + +From: Li Zefan + +commit 3aaba20f26f58843e8f20611e5c0b1c06954310f upstream. + +While we are reading trace_stat/functionX and someone just +disabled function_profile at that time, we can trigger this: + + divide error: 0000 [#1] PREEMPT SMP + ... + EIP is at function_stat_show+0x90/0x230 + ... + +This fix just takes the ftrace_profile_lock and checks if +rec->counter is 0. If it's 0, we know the profile buffer +has been reset. + +Signed-off-by: Li Zefan +LKML-Reference: <4C723644.4040708@cn.fujitsu.com> +Signed-off-by: Steven Rostedt +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/trace/ftrace.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -381,12 +381,19 @@ static int function_stat_show(struct seq + { + struct ftrace_profile *rec = v; + char str[KSYM_SYMBOL_LEN]; ++ int ret = 0; + #ifdef CONFIG_FUNCTION_GRAPH_TRACER +- static DEFINE_MUTEX(mutex); + static struct trace_seq s; + unsigned long long avg; + unsigned long long stddev; + #endif ++ mutex_lock(&ftrace_profile_lock); ++ ++ /* we raced with function_profile_reset() */ ++ if (unlikely(rec->counter == 0)) { ++ ret = -EBUSY; ++ goto out; ++ } + + kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); + seq_printf(m, " %-30.30s %10lu", str, rec->counter); +@@ -408,7 +415,6 @@ static int function_stat_show(struct seq + do_div(stddev, (rec->counter - 1) * 1000); + } + +- mutex_lock(&mutex); + trace_seq_init(&s); + trace_print_graph_duration(rec->time, &s); + trace_seq_puts(&s, " "); +@@ -416,11 +422,12 @@ static int function_stat_show(struct seq + trace_seq_puts(&s, " "); + trace_print_graph_duration(stddev, &s); + trace_print_seq(m, &s); +- mutex_unlock(&mutex); + #endif + seq_putc(m, '\n'); ++out: ++ mutex_unlock(&ftrace_profile_lock); + +- return 0; ++ return ret; + } + + static void ftrace_profile_reset(struct ftrace_profile_stat *stat) diff --git a/queue-2.6.35/tracing-t_start-reset-ftrace_iter_hash-in-case-of-seek-pread.patch b/queue-2.6.35/tracing-t_start-reset-ftrace_iter_hash-in-case-of-seek-pread.patch new file mode 100644 index 00000000000..dce5c6b0577 --- /dev/null +++ b/queue-2.6.35/tracing-t_start-reset-ftrace_iter_hash-in-case-of-seek-pread.patch @@ -0,0 +1,36 @@ +From df09162550fbb53354f0c88e85b5d0e6129ee9cc Mon Sep 17 00:00:00 2001 +From: Chris Wright +Date: Thu, 9 Sep 2010 16:34:59 -0700 +Subject: tracing: t_start: reset FTRACE_ITER_HASH in case of seek/pread + +From: Chris Wright + +commit df09162550fbb53354f0c88e85b5d0e6129ee9cc upstream. + +Be sure to avoid entering t_show() with FTRACE_ITER_HASH set without +having properly started the iterator to iterate the hash. This case is +degenerate and, as discovered by Robert Swiecki, can cause t_hash_show() +to misuse a pointer. This causes a NULL ptr deref with possible security +implications. Tracked as CVE-2010-3079. + +Cc: Robert Swiecki +Cc: Eugene Teo +Signed-off-by: Chris Wright +Signed-off-by: Steven Rostedt +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/trace/ftrace.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -1510,6 +1510,8 @@ static void *t_start(struct seq_file *m, + if (*pos > 0) + return t_hash_start(m, pos); + iter->flags |= FTRACE_ITER_PRINTALL; ++ /* reset in case of seek/pread */ ++ iter->flags &= ~FTRACE_ITER_HASH; + return iter; + } +