From 45316a86a67934ab499dcfac44c91aa8f39c4c78 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 4 Nov 2008 16:35:06 +0100 Subject: [SCSI] zfcp: fix req_list_locking. The per adapter req_list_lock must be held with interrupts disabled, otherwise we might end up with nice deadlocks as lockdep tells us (see below). zfcp 0.0.1804: QDIO problem occurred. ========================================================= [ INFO: possible irq lock inversion dependency detected ] 2.6.27-rc8-00035-g4a77035-dirty #86 --------------------------------------------------------- swapper/0 just changed the state of lock: (&adapter->erp_lock){++..}, at: [<00000000002c82ae>] zfcp_erp_adapter_reopen+0x4e/0x8c but this lock took another, hard-irq-unsafe lock in the past: (&adapter->req_list_lock){-+..} and interrupts could create inverse lock ordering between them. [tons of backtraces, but only the interesting part follows] the second lock's dependencies: -> (&adapter->req_list_lock){-+..} ops: 2280627634176 { initial-use at: [<0000000000071f10>] __lock_acquire+0x504/0x18bc [<000000000007335c>] lock_acquire+0x94/0xbc [<00000000003d7224>] _spin_lock_irqsave+0x6c/0xb0 [<00000000002cf684>] zfcp_fsf_req_dismiss_all+0x50/0x140 [<00000000002c87ee>] zfcp_erp_adapter_strategy_generic+0x66/0x3d0 [<00000000002c9498>] zfcp_erp_thread+0x88c/0x1318 [<000000000001b0d2>] kernel_thread_starter+0x6/0xc [<000000000001b0cc>] kernel_thread_starter+0x0/0xc in-softirq-W at: [<0000000000072172>] __lock_acquire+0x766/0x18bc [<000000000007335c>] lock_acquire+0x94/0xbc [<00000000003d7224>] _spin_lock_irqsave+0x6c/0xb0 [<00000000002ca73e>] zfcp_qdio_int_resp+0xbe/0x2ac [<000000000027a1d6>] qdio_kick_inbound_handler+0x82/0xa0 [<000000000027daba>] tiqdio_inbound_processing+0x62/0xf8 [<0000000000047ba4>] tasklet_action+0x100/0x1f4 [<0000000000048b5a>] __do_softirq+0xae/0x154 [<0000000000021e4a>] do_softirq+0xea/0xf0 [<00000000000485de>] irq_exit+0xde/0xe8 [<0000000000268c64>] do_IRQ+0x160/0x1fc [<00000000000261a2>] io_return+0x0/0x8 [<000000000001b8f8>] cpu_idle+0x17c/0x224 hardirq-on-W at: [<0000000000072190>] __lock_acquire+0x784/0x18bc [<000000000007335c>] lock_acquire+0x94/0xbc [<00000000003d702c>] _spin_lock+0x5c/0x9c [<00000000002caff6>] zfcp_fsf_req_send+0x3e/0x158 [<00000000002ce7fe>] zfcp_fsf_exchange_config_data+0x106/0x124 [<00000000002c8948>] zfcp_erp_adapter_strategy_generic+0x1c0/0x3d0 [<00000000002c98ea>] zfcp_erp_thread+0xcde/0x1318 [<000000000001b0d2>] kernel_thread_starter+0x6/0xc [<000000000001b0cc>] kernel_thread_starter+0x0/0xc } ... key at: [<0000000000e356c8>] __key.26629+0x0/0x8 Signed-off-by: Heiko Carstens Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fsf.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/s390/scsi/zfcp_fsf.c') diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 5ae1d497e5ed..694d9c9ea7cc 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -770,13 +770,14 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; struct zfcp_qdio_queue *req_q = &adapter->req_q; + unsigned long flags; int idx; /* put allocated FSF request into hash table */ - spin_lock(&adapter->req_list_lock); + spin_lock_irqsave(&adapter->req_list_lock, flags); idx = zfcp_reqlist_hash(req->req_id); list_add_tail(&req->list, &adapter->req_list[idx]); - spin_unlock(&adapter->req_list_lock); + spin_unlock_irqrestore(&adapter->req_list_lock, flags); req->qdio_outb_usage = atomic_read(&req_q->count); req->issued = get_clock(); -- cgit v1.2.2 From 88f2a977870af655296a682fe2a58c822cd25bb2 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 4 Nov 2008 16:35:07 +0100 Subject: [SCSI] zfcp: fix mempool usage for status_read requests When allocating fsf requests without qtcb, store the pointer to the mempool in the fsf requests for later call to mempool_free. This codepath is only used by the status_read requests. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fsf.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/s390/scsi/zfcp_fsf.c') diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 694d9c9ea7cc..5e8517fc8b62 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -683,6 +683,7 @@ static struct zfcp_fsf_req *zfcp_fsf_alloc_noqtcb(mempool_t *pool) if (!req) return NULL; memset(req, 0, sizeof(*req)); + req->pool = pool; return req; } -- cgit v1.2.2 From 3765138ae946e6e29b22bf15a9647c600c232639 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 4 Nov 2008 16:35:08 +0100 Subject: [SCSI] zfcp: Fix request list handling in error path Fix the handling of the request list in the error path: - Use irqsave for the lock as in the good path. - Before removing the request, check if it is still in the list, a call to dismiss_all might have changed the list in between. - zfcp_qdio_send does not change the queue counters on failure, trying revert something is wrong, so remove this. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fsf.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers/s390/scsi/zfcp_fsf.c') diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 5e8517fc8b62..d024442ee128 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -770,7 +770,6 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; - struct zfcp_qdio_queue *req_q = &adapter->req_q; unsigned long flags; int idx; @@ -780,19 +779,15 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) list_add_tail(&req->list, &adapter->req_list[idx]); spin_unlock_irqrestore(&adapter->req_list_lock, flags); - req->qdio_outb_usage = atomic_read(&req_q->count); + req->qdio_outb_usage = atomic_read(&adapter->req_q.count); req->issued = get_clock(); if (zfcp_qdio_send(req)) { - /* Queues are down..... */ del_timer(&req->timer); - spin_lock(&adapter->req_list_lock); - zfcp_reqlist_remove(adapter, req); - spin_unlock(&adapter->req_list_lock); - /* undo changes in request queue made for this request */ - atomic_add(req->sbal_number, &req_q->count); - req_q->first -= req->sbal_number; - req_q->first += QDIO_MAX_BUFFERS_PER_Q; - req_q->first %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */ + spin_lock_irqsave(&adapter->req_list_lock, flags); + /* lookup request again, list might have changed */ + if (zfcp_reqlist_find_safe(adapter, req)) + zfcp_reqlist_remove(adapter, req); + spin_unlock_irqrestore(&adapter->req_list_lock, flags); zfcp_erp_adapter_reopen(adapter, 0, 116, req); return -EIO; } -- cgit v1.2.2