From: Greg Kroah-Hartman Date: Wed, 3 Feb 2010 04:49:18 +0000 (-0800) Subject: more .32 patches X-Git-Tag: v2.6.32.8~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9f2e423132b139b67cf9a13bdb423003d8e2557b;p=thirdparty%2Fkernel%2Fstable-queue.git more .32 patches --- diff --git a/queue-2.6.32/be2net-bug-fix-to-support-newer-generation-of-be-asic.patch b/queue-2.6.32/be2net-bug-fix-to-support-newer-generation-of-be-asic.patch new file mode 100644 index 00000000000..6a86a65027f --- /dev/null +++ b/queue-2.6.32/be2net-bug-fix-to-support-newer-generation-of-be-asic.patch @@ -0,0 +1,104 @@ +From 7b139c83c590d4965259aad8889cbb08104b2891 Mon Sep 17 00:00:00 2001 +From: Ajit Khaparde +Date: Wed, 27 Jan 2010 21:56:44 +0000 +Subject: be2net: Bug fix to support newer generation of BE ASIC + +From: Ajit Khaparde + +commit 7b139c83c590d4965259aad8889cbb08104b2891 upstream. + +Bug fix in be2net for newer generation of BladeEngine ASIC. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/benet/be.h | 5 +++++ + drivers/net/benet/be_cmds.h | 3 ++- + drivers/net/benet/be_main.c | 25 +++++++++++++++++++++++-- + 3 files changed, 30 insertions(+), 3 deletions(-) + +--- a/drivers/net/benet/be.h ++++ b/drivers/net/benet/be.h +@@ -272,8 +272,13 @@ struct be_adapter { + u32 cap; + u32 rx_fc; /* Rx flow control */ + u32 tx_fc; /* Tx flow control */ ++ u8 generation; /* BladeEngine ASIC generation */ + }; + ++/* BladeEngine Generation numbers */ ++#define BE_GEN2 2 ++#define BE_GEN3 3 ++ + extern const struct ethtool_ops be_ethtool_ops; + + #define drvr_stats(adapter) (&adapter->stats.drvr_stats) +--- a/drivers/net/benet/be_cmds.h ++++ b/drivers/net/benet/be_cmds.h +@@ -154,7 +154,8 @@ struct be_cmd_req_hdr { + u8 domain; /* dword 0 */ + u32 timeout; /* dword 1 */ + u32 request_length; /* dword 2 */ +- u32 rsvd; /* dword 3 */ ++ u8 version; /* dword 3 */ ++ u8 rsvd[3]; /* dword 3 */ + }; + + #define RESP_HDR_INFO_OPCODE_SHIFT 0 /* bits 0 - 7 */ +--- a/drivers/net/benet/be_main.c ++++ b/drivers/net/benet/be_main.c +@@ -1944,6 +1944,7 @@ static void be_unmap_pci_bars(struct be_ + static int be_map_pci_bars(struct be_adapter *adapter) + { + u8 __iomem *addr; ++ int pcicfg_reg; + + addr = ioremap_nocache(pci_resource_start(adapter->pdev, 2), + pci_resource_len(adapter->pdev, 2)); +@@ -1957,8 +1958,13 @@ static int be_map_pci_bars(struct be_ada + goto pci_map_err; + adapter->db = addr; + +- addr = ioremap_nocache(pci_resource_start(adapter->pdev, 1), +- pci_resource_len(adapter->pdev, 1)); ++ if (adapter->generation == BE_GEN2) ++ pcicfg_reg = 1; ++ else ++ pcicfg_reg = 0; ++ ++ addr = ioremap_nocache(pci_resource_start(adapter->pdev, pcicfg_reg), ++ pci_resource_len(adapter->pdev, pcicfg_reg)); + if (addr == NULL) + goto pci_map_err; + adapter->pcicfg = addr; +@@ -2028,6 +2034,7 @@ static int be_stats_init(struct be_adapt + cmd->va = pci_alloc_consistent(adapter->pdev, cmd->size, &cmd->dma); + if (cmd->va == NULL) + return -1; ++ memset(cmd->va, cmd->size, 0); + return 0; + } + +@@ -2101,6 +2108,20 @@ static int __devinit be_probe(struct pci + goto rel_reg; + } + adapter = netdev_priv(netdev); ++ ++ switch (pdev->device) { ++ case BE_DEVICE_ID1: ++ case OC_DEVICE_ID1: ++ adapter->generation = BE_GEN2; ++ break; ++ case BE_DEVICE_ID2: ++ case OC_DEVICE_ID2: ++ adapter->generation = BE_GEN3; ++ break; ++ default: ++ adapter->generation = 0; ++ } ++ + adapter->pdev = pdev; + pci_set_drvdata(pdev, adapter); + adapter->netdev = netdev; diff --git a/queue-2.6.32/be2net-fix-memset-arg-ordering.patch b/queue-2.6.32/be2net-fix-memset-arg-ordering.patch new file mode 100644 index 00000000000..e57cf817d6d --- /dev/null +++ b/queue-2.6.32/be2net-fix-memset-arg-ordering.patch @@ -0,0 +1,29 @@ +From d291b9af1a1a12f59a464494900c6e0db26e2ec3 Mon Sep 17 00:00:00 2001 +From: David S. Miller +Date: Thu, 28 Jan 2010 21:36:21 -0800 +Subject: be2net: Fix memset() arg ordering. + +From: David S. Miller + +commit d291b9af1a1a12f59a464494900c6e0db26e2ec3 upstream. + +Noticed by Ben Hutchings. + +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/benet/be_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/benet/be_main.c ++++ b/drivers/net/benet/be_main.c +@@ -2034,7 +2034,7 @@ static int be_stats_init(struct be_adapt + cmd->va = pci_alloc_consistent(adapter->pdev, cmd->size, &cmd->dma); + if (cmd->va == NULL) + return -1; +- memset(cmd->va, cmd->size, 0); ++ memset(cmd->va, 0, cmd->size); + return 0; + } + diff --git a/queue-2.6.32/connector-delete-buggy-notification-code.patch b/queue-2.6.32/connector-delete-buggy-notification-code.patch new file mode 100644 index 00000000000..55b07939b7c --- /dev/null +++ b/queue-2.6.32/connector-delete-buggy-notification-code.patch @@ -0,0 +1,326 @@ +From f98bfbd78c37c5946cc53089da32a5f741efdeb7 Mon Sep 17 00:00:00 2001 +From: Evgeniy Polyakov +Date: Tue, 2 Feb 2010 15:58:48 -0800 +Subject: connector: Delete buggy notification code. + +From: Evgeniy Polyakov + +commit f98bfbd78c37c5946cc53089da32a5f741efdeb7 upstream. + +On Tue, Feb 02, 2010 at 02:57:14PM -0800, Greg KH (gregkh@suse.de) wrote: +> > There are at least two ways to fix it: using a big cannon and a small +> > one. The former way is to disable notification registration, since it is +> > not used by anyone at all. Second way is to check whether calling +> > process is root and its destination group is -1 (kind of priveledged +> > one) before command is dispatched to workqueue. +> +> Well if no one is using it, removing it makes the most sense, right? +> +> No objection from me, care to make up a patch either way for this? + +Getting it is not used, let's drop support for notifications about +(un)registered events from connector. +Another option was to check credentials on receiving, but we can always +restore it without bugs if needed, but genetlink has a wider code base +and none complained, that userspace can not get notification when some +other clients were (un)registered. + +Kudos for Sebastian Krahmer , who found a bug in the +code. + +Signed-off-by: Evgeniy Polyakov +Acked-by: Greg Kroah-Hartman +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/connector/connector.c | 175 ------------------------------------------ + include/linux/connector.h | 32 ------- + 2 files changed, 207 deletions(-) + +--- a/drivers/connector/connector.c ++++ b/drivers/connector/connector.c +@@ -36,17 +36,6 @@ MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Evgeniy Polyakov "); + MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector."); + +-static u32 cn_idx = CN_IDX_CONNECTOR; +-static u32 cn_val = CN_VAL_CONNECTOR; +- +-module_param(cn_idx, uint, 0); +-module_param(cn_val, uint, 0); +-MODULE_PARM_DESC(cn_idx, "Connector's main device idx."); +-MODULE_PARM_DESC(cn_val, "Connector's main device val."); +- +-static DEFINE_MUTEX(notify_lock); +-static LIST_HEAD(notify_list); +- + static struct cn_dev cdev; + + static int cn_already_initialized; +@@ -210,54 +199,6 @@ static void cn_rx_skb(struct sk_buff *__ + } + + /* +- * Notification routing. +- * +- * Gets id and checks if there are notification request for it's idx +- * and val. If there are such requests notify the listeners with the +- * given notify event. +- * +- */ +-static void cn_notify(struct cb_id *id, u32 notify_event) +-{ +- struct cn_ctl_entry *ent; +- +- mutex_lock(¬ify_lock); +- list_for_each_entry(ent, ¬ify_list, notify_entry) { +- int i; +- struct cn_notify_req *req; +- struct cn_ctl_msg *ctl = ent->msg; +- int idx_found, val_found; +- +- idx_found = val_found = 0; +- +- req = (struct cn_notify_req *)ctl->data; +- for (i = 0; i < ctl->idx_notify_num; ++i, ++req) { +- if (id->idx >= req->first && +- id->idx < req->first + req->range) { +- idx_found = 1; +- break; +- } +- } +- +- for (i = 0; i < ctl->val_notify_num; ++i, ++req) { +- if (id->val >= req->first && +- id->val < req->first + req->range) { +- val_found = 1; +- break; +- } +- } +- +- if (idx_found && val_found) { +- struct cn_msg m = { .ack = notify_event, }; +- +- memcpy(&m.id, id, sizeof(m.id)); +- cn_netlink_send(&m, ctl->group, GFP_KERNEL); +- } +- } +- mutex_unlock(¬ify_lock); +-} +- +-/* + * Callback add routing - adds callback with given ID and name. + * If there is registered callback with the same ID it will not be added. + * +@@ -276,8 +217,6 @@ int cn_add_callback(struct cb_id *id, ch + if (err) + return err; + +- cn_notify(id, 0); +- + return 0; + } + EXPORT_SYMBOL_GPL(cn_add_callback); +@@ -295,111 +234,9 @@ void cn_del_callback(struct cb_id *id) + struct cn_dev *dev = &cdev; + + cn_queue_del_callback(dev->cbdev, id); +- cn_notify(id, 1); + } + EXPORT_SYMBOL_GPL(cn_del_callback); + +-/* +- * Checks two connector's control messages to be the same. +- * Returns 1 if they are the same or if the first one is corrupted. +- */ +-static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2) +-{ +- int i; +- struct cn_notify_req *req1, *req2; +- +- if (m1->idx_notify_num != m2->idx_notify_num) +- return 0; +- +- if (m1->val_notify_num != m2->val_notify_num) +- return 0; +- +- if (m1->len != m2->len) +- return 0; +- +- if ((m1->idx_notify_num + m1->val_notify_num) * sizeof(*req1) != +- m1->len) +- return 1; +- +- req1 = (struct cn_notify_req *)m1->data; +- req2 = (struct cn_notify_req *)m2->data; +- +- for (i = 0; i < m1->idx_notify_num; ++i) { +- if (req1->first != req2->first || req1->range != req2->range) +- return 0; +- req1++; +- req2++; +- } +- +- for (i = 0; i < m1->val_notify_num; ++i) { +- if (req1->first != req2->first || req1->range != req2->range) +- return 0; +- req1++; +- req2++; +- } +- +- return 1; +-} +- +-/* +- * Main connector device's callback. +- * +- * Used for notification of a request's processing. +- */ +-static void cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) +-{ +- struct cn_ctl_msg *ctl; +- struct cn_ctl_entry *ent; +- u32 size; +- +- if (msg->len < sizeof(*ctl)) +- return; +- +- ctl = (struct cn_ctl_msg *)msg->data; +- +- size = (sizeof(*ctl) + ((ctl->idx_notify_num + +- ctl->val_notify_num) * +- sizeof(struct cn_notify_req))); +- +- if (msg->len != size) +- return; +- +- if (ctl->len + sizeof(*ctl) != msg->len) +- return; +- +- /* +- * Remove notification. +- */ +- if (ctl->group == 0) { +- struct cn_ctl_entry *n; +- +- mutex_lock(¬ify_lock); +- list_for_each_entry_safe(ent, n, ¬ify_list, notify_entry) { +- if (cn_ctl_msg_equals(ent->msg, ctl)) { +- list_del(&ent->notify_entry); +- kfree(ent); +- } +- } +- mutex_unlock(¬ify_lock); +- +- return; +- } +- +- size += sizeof(*ent); +- +- ent = kzalloc(size, GFP_KERNEL); +- if (!ent) +- return; +- +- ent->msg = (struct cn_ctl_msg *)(ent + 1); +- +- memcpy(ent->msg, ctl, size - sizeof(*ent)); +- +- mutex_lock(¬ify_lock); +- list_add(&ent->notify_entry, ¬ify_list); +- mutex_unlock(¬ify_lock); +-} +- + static int cn_proc_show(struct seq_file *m, void *v) + { + struct cn_queue_dev *dev = cdev.cbdev; +@@ -437,11 +274,8 @@ static const struct file_operations cn_f + static int __devinit cn_init(void) + { + struct cn_dev *dev = &cdev; +- int err; + + dev->input = cn_rx_skb; +- dev->id.idx = cn_idx; +- dev->id.val = cn_val; + + dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR, + CN_NETLINK_USERS + 0xf, +@@ -457,14 +291,6 @@ static int __devinit cn_init(void) + + cn_already_initialized = 1; + +- err = cn_add_callback(&dev->id, "connector", &cn_callback); +- if (err) { +- cn_already_initialized = 0; +- cn_queue_free_dev(dev->cbdev); +- netlink_kernel_release(dev->nls); +- return -EINVAL; +- } +- + proc_net_fops_create(&init_net, "connector", S_IRUGO, &cn_file_ops); + + return 0; +@@ -478,7 +304,6 @@ static void __devexit cn_fini(void) + + proc_net_remove(&init_net, "connector"); + +- cn_del_callback(&dev->id); + cn_queue_free_dev(dev->cbdev); + netlink_kernel_release(dev->nls); + } +--- a/include/linux/connector.h ++++ b/include/linux/connector.h +@@ -24,9 +24,6 @@ + + #include + +-#define CN_IDX_CONNECTOR 0xffffffff +-#define CN_VAL_CONNECTOR 0xffffffff +- + /* + * Process Events connector unique ids -- used for message routing + */ +@@ -73,30 +70,6 @@ struct cn_msg { + __u8 data[0]; + }; + +-/* +- * Notify structure - requests notification about +- * registering/unregistering idx/val in range [first, first+range]. +- */ +-struct cn_notify_req { +- __u32 first; +- __u32 range; +-}; +- +-/* +- * Main notification control message +- * *_notify_num - number of appropriate cn_notify_req structures after +- * this struct. +- * group - notification receiver's idx. +- * len - total length of the attached data. +- */ +-struct cn_ctl_msg { +- __u32 idx_notify_num; +- __u32 val_notify_num; +- __u32 group; +- __u32 len; +- __u8 data[0]; +-}; +- + #ifdef __KERNEL__ + + #include +@@ -149,11 +122,6 @@ struct cn_callback_entry { + u32 seq, group; + }; + +-struct cn_ctl_entry { +- struct list_head notify_entry; +- struct cn_ctl_msg *msg; +-}; +- + struct cn_dev { + struct cb_id id; + diff --git a/queue-2.6.32/idr-fix-a-critical-misallocation-bug.patch b/queue-2.6.32/idr-fix-a-critical-misallocation-bug.patch new file mode 100644 index 00000000000..d02e3104c45 --- /dev/null +++ b/queue-2.6.32/idr-fix-a-critical-misallocation-bug.patch @@ -0,0 +1,148 @@ +From 859ddf09743a8cc680af33f7259ccd0fd36bfe9d Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Tue, 2 Feb 2010 13:43:58 -0800 +Subject: idr: fix a critical misallocation bug + +From: Tejun Heo + +commit 859ddf09743a8cc680af33f7259ccd0fd36bfe9d upstream. + +Eric Paris located a bug in idr. With IDR_BITS of 6, it grows to three +layers when id 4096 is first allocated. When that happens, idr wraps +incorrectly and searches the idr array ignoring the high bits. The +following test code from Eric demonstrates the bug nicely. + +#include +#include +#include + +static DEFINE_IDR(test_idr); + +int init_module(void) +{ + int ret, forty95, forty96; + void *addr; + + /* add 2 entries both with 4095 as the start address */ +again1: + if (!idr_pre_get(&test_idr, GFP_KERNEL)) + return -ENOMEM; + ret = idr_get_new_above(&test_idr, (void *)4095, 4095, &forty95); + if (ret) { + if (ret == -EAGAIN) + goto again1; + return ret; + } + if (forty95 != 4095) + printk(KERN_ERR "hmmm, forty95=%d\n", forty95); + +again2: + if (!idr_pre_get(&test_idr, GFP_KERNEL)) + return -ENOMEM; + ret = idr_get_new_above(&test_idr, (void *)4096, 4095, &forty96); + if (ret) { + if (ret == -EAGAIN) + goto again2; + return ret; + } + if (forty96 != 4096) + printk(KERN_ERR "hmmm, forty96=%d\n", forty96); + + /* try to find the 2 entries, noticing that 4096 broke */ + addr = idr_find(&test_idr, forty95); + if ((int)addr != forty95) + printk(KERN_ERR "hmmm, after find forty95=%d addr=%d\n", forty95, (int)addr); + addr = idr_find(&test_idr, forty96); + if ((int)addr != forty96) + printk(KERN_ERR "hmmm, after find forty96=%d addr=%d\n", forty96, (int)addr); + /* really weird, the entry which should be at 4096 is actually at 0!! */ + addr = idr_find(&test_idr, 0); + if ((int)addr) + printk(KERN_ERR "found an entry at id=0 for addr=%d\n", (int)addr); + + idr_remove(&test_idr, forty95); + idr_remove(&test_idr, forty96); + + return 0; +} + +void cleanup_module(void) +{ +} + +MODULE_AUTHOR("Eric Paris "); +MODULE_DESCRIPTION("Simple idr test"); +MODULE_LICENSE("GPL"); + +This happens because when sub_alloc() back tracks it doesn't always do it +step-by-step while the over-the-limit detection assumes step-by-step +backtracking. The logic in sub_alloc() looks like the following. + + restart: + clear pa[top level + 1] for end cond detection + l = top level + while (true) { + search for empty slot at this level + if (not found) { + push id to the next possible value + l++ +A: if (pa[l] is clear) + failed, return asking caller to grow the tree + if (going up 1 level gives more slots to search) + continue the while loop above with the incremented l + else +C: goto restart + } + adjust id accordingly to the found slot + if (l == 0) + return found id; + create lower level if not there yet + record pa[l] and l-- + } + +Test A is the fail exit condition but this assumes that failure is +propagated upwared one level at a time but the B optimization path breaks +the assumption and restarts the whole thing with a start value which is +above the possible limit with the current layers. sub_alloc() assumes the +start id value is inside the limit when called and test A is the only exit +condition check, so it ends up searching for empty slot while ignoring +high set bit. + +So, for 4095->4096 test, level0 search fails but pa[1] contains a valid +pointer. However, going up 1 level wouldn't give any more empty slot so +it takes C and when the whole thing restarts nobody notices the high bit +set beyond the top level. + +This patch fixes the bug by changing the fail exit condition check to full +id limit check. + +Based-on-patch-from: Eric Paris +Reported-by: Eric Paris +Signed-off-by: Tejun Heo +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- a/lib/idr.c ++++ b/lib/idr.c +@@ -140,8 +140,7 @@ static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa) + id = *starting_id; + restart: + p = idp->top; +- l = idp->layers; +- pa[l--] = NULL; ++ l = p->layer; + while (1) { + /* + * We run around this while until we reach the leaf node... +@@ -155,8 +154,8 @@ static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa) + oid = id; + id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1; + +- /* if already at the top layer, we need to grow */ +- if (!(p = pa[l])) { ++ /* did id go over the limit? */ ++ if (id >= (1 << (idp->layers * IDR_BITS))) { + *starting_id = id; + return IDR_NEED_TO_GROW; + } diff --git a/queue-2.6.32/mac80211-fix-null-pointer-dereference-when-ftrace-is-enabled.patch b/queue-2.6.32/mac80211-fix-null-pointer-dereference-when-ftrace-is-enabled.patch new file mode 100644 index 00000000000..8269ce59309 --- /dev/null +++ b/queue-2.6.32/mac80211-fix-null-pointer-dereference-when-ftrace-is-enabled.patch @@ -0,0 +1,51 @@ +From 3092ad054406f069991ca561adc74f2d9fbb6867 Mon Sep 17 00:00:00 2001 +From: Zhu Yi +Date: Tue, 26 Jan 2010 15:58:57 +0800 +Subject: mac80211: fix NULL pointer dereference when ftrace is enabled + +From: Zhu Yi + +commit 3092ad054406f069991ca561adc74f2d9fbb6867 upstream. + +I got below kernel oops when I try to bring down the network interface if +ftrace is enabled. The root cause is drv_ampdu_action() is passed with a +NULL ssn pointer in the BA session tear down case. We need to check and +avoid dereferencing it in trace entry assignment. + +BUG: unable to handle kernel NULL pointer dereference +Modules linked in: at (null) +IP: [] ftrace_raw_event_drv_ampdu_action+0x10a/0x160 [mac80211] +*pde = 00000000 +Oops: 0000 [#1] SMP DEBUG_PAGEALLOC +[...] +Call Trace: + [] ? ftrace_raw_event_drv_ampdu_action+0x0/0x160 [mac80211] + [] ? __ieee80211_stop_rx_ba_session+0xfc/0x220 [mac80211] + [] ? ieee80211_sta_tear_down_BA_sessions+0x3b/0x50 [mac80211] + [] ? ieee80211_set_disassoc+0xe6/0x230 [mac80211] + [] ? ieee80211_set_disassoc+0x9c/0x230 [mac80211] + [] ? ieee80211_mgd_deauth+0x158/0x170 [mac80211] + [] ? ieee80211_deauth+0x1b/0x20 [mac80211] + [] ? __cfg80211_mlme_deauth+0xe9/0x120 [cfg80211] + [] ? __cfg80211_disconnect+0x170/0x1d0 [cfg80211] + +Cc: Johannes Berg +Signed-off-by: Zhu Yi +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + net/mac80211/driver-trace.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/mac80211/driver-trace.h ++++ b/net/mac80211/driver-trace.h +@@ -655,7 +655,7 @@ TRACE_EVENT(drv_ampdu_action, + __entry->ret = ret; + __entry->action = action; + __entry->tid = tid; +- __entry->ssn = *ssn; ++ __entry->ssn = ssn ? *ssn : 0; + ), + + TP_printk( diff --git a/queue-2.6.32/mm-flush-dcache-before-writing-into-page-to-avoid-alias.patch b/queue-2.6.32/mm-flush-dcache-before-writing-into-page-to-avoid-alias.patch new file mode 100644 index 00000000000..24253271193 --- /dev/null +++ b/queue-2.6.32/mm-flush-dcache-before-writing-into-page-to-avoid-alias.patch @@ -0,0 +1,75 @@ +From 931e80e4b3263db75c8e34f078d22f11bbabd3a3 Mon Sep 17 00:00:00 2001 +From: anfei zhou +Date: Tue, 2 Feb 2010 13:44:02 -0800 +Subject: mm: flush dcache before writing into page to avoid alias + +From: anfei zhou + +commit 931e80e4b3263db75c8e34f078d22f11bbabd3a3 upstream. + +The cache alias problem will happen if the changes of user shared mapping +is not flushed before copying, then user and kernel mapping may be mapped +into two different cache line, it is impossible to guarantee the coherence +after iov_iter_copy_from_user_atomic. So the right steps should be: + + flush_dcache_page(page); + kmap_atomic(page); + write to page; + kunmap_atomic(page); + flush_dcache_page(page); + +More precisely, we might create two new APIs flush_dcache_user_page and +flush_dcache_kern_page to replace the two flush_dcache_page accordingly. + +Here is a snippet tested on omap2430 with VIPT cache, and I think it is +not ARM-specific: + + int val = 0x11111111; + fd = open("abc", O_RDWR); + addr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + *(addr+0) = 0x44444444; + tmp = *(addr+0); + *(addr+1) = 0x77777777; + write(fd, &val, sizeof(int)); + close(fd); + +The results are not always 0x11111111 0x77777777 at the beginning as expected. Sometimes we see 0x44444444 0x77777777. + +Signed-off-by: Anfei +Cc: Russell King +Cc: Miklos Szeredi +Cc: Nick Piggin +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/file.c | 3 +++ + mm/filemap.c | 3 +++ + 2 files changed, 6 insertions(+) + +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -828,6 +828,9 @@ static ssize_t fuse_fill_write_pages(str + if (!page) + break; + ++ if (mapping_writably_mapped(mapping)) ++ flush_dcache_page(page); ++ + pagefault_disable(); + tmp = iov_iter_copy_from_user_atomic(page, ii, offset, bytes); + pagefault_enable(); +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -2253,6 +2253,9 @@ again: + if (unlikely(status)) + break; + ++ if (mapping_writably_mapped(mapping)) ++ flush_dcache_page(page); ++ + pagefault_disable(); + copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes); + pagefault_enable(); diff --git a/queue-2.6.32/series b/queue-2.6.32/series index 01c70402d0b..aef32fc1a4b 100644 --- a/queue-2.6.32/series +++ b/queue-2.6.32/series @@ -58,3 +58,9 @@ random-drop-weird-m_time-a_time-manipulation.patch random-remove-unused-inode-variable.patch block-fix-bugs-in-bio-integrity-mempool-usage.patch usb-r8a66597-hdc-disable-interrupts-fix.patch +connector-delete-buggy-notification-code.patch +be2net-bug-fix-to-support-newer-generation-of-be-asic.patch +be2net-fix-memset-arg-ordering.patch +mm-flush-dcache-before-writing-into-page-to-avoid-alias.patch +idr-fix-a-critical-misallocation-bug.patch +mac80211-fix-null-pointer-dereference-when-ftrace-is-enabled.patch