block: use normal I/O path for discard requests
prepare_discard_fn() was being called in a place where memory allocation was effectively impossible. This makes it inappropriate for all but the most trivial translations of Linux's DISCARD operation to the block command set. Additionally adding a payload there makes the ownership of the bio backing unclear as it's now allocated by the device driver and not the submitter as usual. It is replaced with QUEUE_FLAG_DISCARD which is used to indicate whether the queue supports discard operations or not. blkdev_issue_discard now allocates a one-page, sector-length payload which is the right thing for the common ATA and SCSI implementations. The mtd implementation of prepare_discard_fn() is replaced with simply checking for the request being a discard. Largely based on a previous patch from Matthew Wilcox <matthew@wil.cx> which did the prepare_discard_fn but not the different payload allocation yet. Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
committed by
Jens Axboe
parent
3bd0f0c763
commit
1122a26f2a
@ -32,14 +32,6 @@ struct mtd_blkcore_priv {
|
||||
spinlock_t queue_lock;
|
||||
};
|
||||
|
||||
static int blktrans_discard_request(struct request_queue *q,
|
||||
struct request *req)
|
||||
{
|
||||
req->cmd_type = REQ_TYPE_LINUX_BLOCK;
|
||||
req->cmd[0] = REQ_LB_OP_DISCARD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_blktrans_request(struct mtd_blktrans_ops *tr,
|
||||
struct mtd_blktrans_dev *dev,
|
||||
struct request *req)
|
||||
@ -52,10 +44,6 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
|
||||
|
||||
buf = req->buffer;
|
||||
|
||||
if (req->cmd_type == REQ_TYPE_LINUX_BLOCK &&
|
||||
req->cmd[0] == REQ_LB_OP_DISCARD)
|
||||
return tr->discard(dev, block, nsect);
|
||||
|
||||
if (!blk_fs_request(req))
|
||||
return -EIO;
|
||||
|
||||
@ -63,6 +51,9 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
|
||||
get_capacity(req->rq_disk))
|
||||
return -EIO;
|
||||
|
||||
if (blk_discard_rq(req))
|
||||
return tr->discard(dev, block, nsect);
|
||||
|
||||
switch(rq_data_dir(req)) {
|
||||
case READ:
|
||||
for (; nsect > 0; nsect--, block++, buf += tr->blksize)
|
||||
@ -380,8 +371,8 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
|
||||
tr->blkcore_priv->rq->queuedata = tr;
|
||||
blk_queue_logical_block_size(tr->blkcore_priv->rq, tr->blksize);
|
||||
if (tr->discard)
|
||||
blk_queue_set_discard(tr->blkcore_priv->rq,
|
||||
blktrans_discard_request);
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD,
|
||||
tr->blkcore_priv->rq);
|
||||
|
||||
tr->blkshift = ffs(tr->blksize) - 1;
|
||||
|
||||
|
Reference in New Issue
Block a user