From: Chris Wright Date: Mon, 19 Jun 2006 19:24:27 +0000 (-0700) Subject: i2o fixes, fwd from akpm X-Git-Tag: v2.6.16.21~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cc5156c9f7bf7a249ded0eabb8f7737190435d34;p=thirdparty%2Fkernel%2Fstable-queue.git i2o fixes, fwd from akpm --- diff --git a/queue-2.6.16/i2o-bugfixes-to-get-i2o-working-again.patch b/queue-2.6.16/i2o-bugfixes-to-get-i2o-working-again.patch new file mode 100644 index 00000000000..9bcc617ad0d --- /dev/null +++ b/queue-2.6.16/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 + +- 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 +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Chris Wright +--- + + 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.20.orig/drivers/message/i2o/exec-osm.c ++++ linux-2.6.16.20/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.20.orig/drivers/message/i2o/iop.c ++++ linux-2.6.16.20/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.20.orig/include/linux/i2o.h ++++ linux-2.6.16.20/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/queue-2.6.16/series b/queue-2.6.16/series index 4ac2da9c987..bbe173de015 100644 --- a/queue-2.6.16/series +++ b/queue-2.6.16/series @@ -8,3 +8,4 @@ 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