Use __blk_end_request() in zvol_request() to avoid ZVOL deadlock.
The unlocked version of blk_end_request() should be used in the zvol_request() error handling to avoid deadlocking the request_queue queue_lock. Things get a little more complicated for older kernel APIs but the compat layer has been updated as well to reflect this.
This commit is contained in:
parent
cdd590f8b9
commit
94655e1c30
|
@ -61,9 +61,8 @@ blk_requeue_request(request_queue_t *q, struct request *req)
|
|||
|
||||
#ifndef HAVE_BLK_END_REQUEST
|
||||
static inline bool
|
||||
blk_end_request(struct request *req, int error, unsigned int nr_bytes)
|
||||
__blk_end_request(struct request *req, int error, unsigned int nr_bytes)
|
||||
{
|
||||
struct request_queue *q = req->q;
|
||||
LIST_HEAD(list);
|
||||
|
||||
/*
|
||||
|
@ -79,14 +78,23 @@ blk_end_request(struct request *req, int error, unsigned int nr_bytes)
|
|||
* entire request partial requests are not supported.
|
||||
*/
|
||||
req->hard_cur_sectors = nr_bytes >> 9;
|
||||
|
||||
|
||||
spin_lock_irq(q->queue_lock);
|
||||
end_request(req, ((error == 0) ? 1 : error));
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
blk_end_request(struct request *req, int error, unsigned int nr_bytes)
|
||||
{
|
||||
struct request_queue *q = req->q;
|
||||
bool rc;
|
||||
|
||||
spin_lock_irq(q->queue_lock);
|
||||
rc = __blk_end_request(req, error, nr_bytes);
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#else
|
||||
# ifdef HAVE_BLK_END_REQUEST_GPL_ONLY
|
||||
/*
|
||||
|
@ -94,25 +102,34 @@ blk_end_request(struct request *req, int error, unsigned int nr_bytes)
|
|||
* GPL-only version of the helper. As of 2.6.31 the helper is available
|
||||
* to non-GPL modules and is not explicitly exported GPL-only.
|
||||
*/
|
||||
# define blk_end_request ___blk_end_request
|
||||
static inline bool
|
||||
___blk_end_request(struct request *req, int error, unsigned int nr_bytes)
|
||||
{
|
||||
struct request_queue *q = req->q;
|
||||
# define __blk_end_request __blk_end_request_x
|
||||
# define blk_end_request blk_end_request_x
|
||||
|
||||
static inline bool
|
||||
__blk_end_request_x(struct request *req, int error, unsigned int nr_bytes)
|
||||
{
|
||||
/*
|
||||
* The old API required the driver to end each segment and not
|
||||
* the entire request. In our case we always need to end the
|
||||
* entire request partial requests are not supported.
|
||||
*/
|
||||
req->hard_cur_sectors = nr_bytes >> 9;
|
||||
|
||||
spin_lock_irq(q->queue_lock);
|
||||
end_request(req, ((error == 0) ? 1 : error));
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static inline bool
|
||||
blk_end_request_x(struct request *req, int error, unsigned int nr_bytes)
|
||||
{
|
||||
struct request_queue *q = req->q;
|
||||
bool rc;
|
||||
|
||||
spin_lock_irq(q->queue_lock);
|
||||
__blk_end_request_x(req, error, nr_bytes);
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
# endif /* HAVE_BLK_END_REQUEST_GPL_ONLY */
|
||||
#endif /* HAVE_BLK_END_REQUEST */
|
||||
|
||||
|
|
|
@ -626,14 +626,14 @@ zvol_request(struct request_queue *q)
|
|||
req->rq_disk->disk_name,
|
||||
(long long unsigned)blk_rq_pos(req),
|
||||
(long unsigned)blk_rq_sectors(req));
|
||||
blk_end_request(req, -EIO, size);
|
||||
__blk_end_request(req, -EIO, size);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!blk_fs_request(req)) {
|
||||
printk(KERN_INFO "%s: non-fs cmd\n",
|
||||
req->rq_disk->disk_name);
|
||||
blk_end_request(req, -EIO, size);
|
||||
__blk_end_request(req, -EIO, size);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -642,8 +642,9 @@ zvol_request(struct request_queue *q)
|
|||
zvol_dispatch(zvol_read, req);
|
||||
break;
|
||||
case WRITE:
|
||||
if (unlikely(get_disk_ro(zv->zv_disk))) {
|
||||
blk_end_request(req, -EROFS, size);
|
||||
if (unlikely(get_disk_ro(zv->zv_disk)) ||
|
||||
unlikely(zv->zv_mode & DS_MODE_READONLY)) {
|
||||
__blk_end_request(req, -EROFS, size);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -652,7 +653,7 @@ zvol_request(struct request_queue *q)
|
|||
default:
|
||||
printk(KERN_INFO "%s: unknown cmd: %d\n",
|
||||
req->rq_disk->disk_name, (int)rq_data_dir(req));
|
||||
blk_end_request(req, -EIO, size);
|
||||
__blk_end_request(req, -EIO, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue