diff options
Diffstat (limited to 'block/blk-ioc.c')
-rw-r--r-- | block/blk-ioc.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/block/blk-ioc.c b/block/blk-ioc.c index 5dbcfa1b872e..57299f860d41 100644 --- a/block/blk-ioc.c +++ b/block/blk-ioc.c @@ -107,9 +107,23 @@ static void ioc_release_fn(struct work_struct *work) ioc_destroy_icq(icq); spin_unlock(&q->queue_lock); } else { - spin_unlock_irq(&ioc->lock); - cpu_relax(); - spin_lock_irq(&ioc->lock); + /* Make sure q and icq cannot be freed. */ + rcu_read_lock(); + + /* Re-acquire the locks in the correct order. */ + spin_unlock(&ioc->lock); + spin_lock(&q->queue_lock); + spin_lock(&ioc->lock); + + /* + * The icq may have been destroyed when the ioc lock + * was released. + */ + if (!(icq->flags & ICQ_DESTROYED)) + ioc_destroy_icq(icq); + + spin_unlock(&q->queue_lock); + rcu_read_unlock(); } } |