1
0
Fork 0

block: allow specifying size for extra command data

This mirrors the blk-mq capabilities to allocate extra drivers-specific
data behind struct request by setting a cmd_size field, as well as having
a constructor / destructor for it.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
hifive-unleashed-5.1
Christoph Hellwig 2017-01-27 09:51:45 -07:00 committed by Jens Axboe
parent 5ea708d15a
commit 6d247d7f71
4 changed files with 61 additions and 17 deletions

View File

@ -606,17 +606,41 @@ void blk_cleanup_queue(struct request_queue *q)
EXPORT_SYMBOL(blk_cleanup_queue); EXPORT_SYMBOL(blk_cleanup_queue);
/* Allocate memory local to the request queue */ /* Allocate memory local to the request queue */
static void *alloc_request_struct(gfp_t gfp_mask, void *data) static void *alloc_request_simple(gfp_t gfp_mask, void *data)
{ {
int nid = (int)(long)data; struct request_queue *q = data;
return kmem_cache_alloc_node(request_cachep, gfp_mask, nid);
return kmem_cache_alloc_node(request_cachep, gfp_mask, q->node);
} }
static void free_request_struct(void *element, void *unused) static void free_request_simple(void *element, void *data)
{ {
kmem_cache_free(request_cachep, element); kmem_cache_free(request_cachep, element);
} }
static void *alloc_request_size(gfp_t gfp_mask, void *data)
{
struct request_queue *q = data;
struct request *rq;
rq = kmalloc_node(sizeof(struct request) + q->cmd_size, gfp_mask,
q->node);
if (rq && q->init_rq_fn && q->init_rq_fn(q, rq, gfp_mask) < 0) {
kfree(rq);
rq = NULL;
}
return rq;
}
static void free_request_size(void *element, void *data)
{
struct request_queue *q = data;
if (q->exit_rq_fn)
q->exit_rq_fn(q, element);
kfree(element);
}
int blk_init_rl(struct request_list *rl, struct request_queue *q, int blk_init_rl(struct request_list *rl, struct request_queue *q,
gfp_t gfp_mask) gfp_t gfp_mask)
{ {
@ -629,10 +653,15 @@ int blk_init_rl(struct request_list *rl, struct request_queue *q,
init_waitqueue_head(&rl->wait[BLK_RW_SYNC]); init_waitqueue_head(&rl->wait[BLK_RW_SYNC]);
init_waitqueue_head(&rl->wait[BLK_RW_ASYNC]); init_waitqueue_head(&rl->wait[BLK_RW_ASYNC]);
rl->rq_pool = mempool_create_node(BLKDEV_MIN_RQ, alloc_request_struct, if (q->cmd_size) {
free_request_struct, rl->rq_pool = mempool_create_node(BLKDEV_MIN_RQ,
(void *)(long)q->node, gfp_mask, alloc_request_size, free_request_size,
q->node); q, gfp_mask, q->node);
} else {
rl->rq_pool = mempool_create_node(BLKDEV_MIN_RQ,
alloc_request_simple, free_request_simple,
q, gfp_mask, q->node);
}
if (!rl->rq_pool) if (!rl->rq_pool)
return -ENOMEM; return -ENOMEM;
@ -846,12 +875,15 @@ static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio);
int blk_init_allocated_queue(struct request_queue *q) int blk_init_allocated_queue(struct request_queue *q)
{ {
q->fq = blk_alloc_flush_queue(q, NUMA_NO_NODE, 0); q->fq = blk_alloc_flush_queue(q, NUMA_NO_NODE, q->cmd_size);
if (!q->fq) if (!q->fq)
return -ENOMEM; return -ENOMEM;
if (q->init_rq_fn && q->init_rq_fn(q, q->fq->flush_rq, GFP_KERNEL))
goto out_free_flush_queue;
if (blk_init_rl(&q->root_rl, q, GFP_KERNEL)) if (blk_init_rl(&q->root_rl, q, GFP_KERNEL))
goto fail; goto out_exit_flush_rq;
INIT_WORK(&q->timeout_work, blk_timeout_work); INIT_WORK(&q->timeout_work, blk_timeout_work);
q->queue_flags |= QUEUE_FLAG_DEFAULT; q->queue_flags |= QUEUE_FLAG_DEFAULT;
@ -869,13 +901,16 @@ int blk_init_allocated_queue(struct request_queue *q)
/* init elevator */ /* init elevator */
if (elevator_init(q, NULL)) { if (elevator_init(q, NULL)) {
mutex_unlock(&q->sysfs_lock); mutex_unlock(&q->sysfs_lock);
goto fail; goto out_exit_flush_rq;
} }
mutex_unlock(&q->sysfs_lock); mutex_unlock(&q->sysfs_lock);
return 0; return 0;
fail: out_exit_flush_rq:
if (q->exit_rq_fn)
q->exit_rq_fn(q, q->fq->flush_rq);
out_free_flush_queue:
blk_free_flush_queue(q->fq); blk_free_flush_queue(q->fq);
wbt_exit(q); wbt_exit(q);
return -ENOMEM; return -ENOMEM;

View File

@ -547,11 +547,10 @@ struct blk_flush_queue *blk_alloc_flush_queue(struct request_queue *q,
if (!fq) if (!fq)
goto fail; goto fail;
if (q->mq_ops) { if (q->mq_ops)
spin_lock_init(&fq->mq_flush_lock); spin_lock_init(&fq->mq_flush_lock);
rq_sz = round_up(rq_sz + cmd_size, cache_line_size());
}
rq_sz = round_up(rq_sz + cmd_size, cache_line_size());
fq->flush_rq = kzalloc_node(rq_sz, GFP_KERNEL, node); fq->flush_rq = kzalloc_node(rq_sz, GFP_KERNEL, node);
if (!fq->flush_rq) if (!fq->flush_rq)
goto fail_rq; goto fail_rq;

View File

@ -814,10 +814,13 @@ static void blk_release_queue(struct kobject *kobj)
if (q->queue_tags) if (q->queue_tags)
__blk_queue_free_tags(q); __blk_queue_free_tags(q);
if (!q->mq_ops) if (!q->mq_ops) {
if (q->exit_rq_fn)
q->exit_rq_fn(q, q->fq->flush_rq);
blk_free_flush_queue(q->fq); blk_free_flush_queue(q->fq);
else } else {
blk_mq_release(q); blk_mq_release(q);
}
blk_trace_shutdown(q); blk_trace_shutdown(q);

View File

@ -273,6 +273,8 @@ typedef void (softirq_done_fn)(struct request *);
typedef int (dma_drain_needed_fn)(struct request *); typedef int (dma_drain_needed_fn)(struct request *);
typedef int (lld_busy_fn) (struct request_queue *q); typedef int (lld_busy_fn) (struct request_queue *q);
typedef int (bsg_job_fn) (struct bsg_job *); typedef int (bsg_job_fn) (struct bsg_job *);
typedef int (init_rq_fn)(struct request_queue *, struct request *, gfp_t);
typedef void (exit_rq_fn)(struct request_queue *, struct request *);
enum blk_eh_timer_return { enum blk_eh_timer_return {
BLK_EH_NOT_HANDLED, BLK_EH_NOT_HANDLED,
@ -408,6 +410,8 @@ struct request_queue {
rq_timed_out_fn *rq_timed_out_fn; rq_timed_out_fn *rq_timed_out_fn;
dma_drain_needed_fn *dma_drain_needed; dma_drain_needed_fn *dma_drain_needed;
lld_busy_fn *lld_busy_fn; lld_busy_fn *lld_busy_fn;
init_rq_fn *init_rq_fn;
exit_rq_fn *exit_rq_fn;
const struct blk_mq_ops *mq_ops; const struct blk_mq_ops *mq_ops;
@ -577,6 +581,9 @@ struct request_queue {
#endif #endif
bool mq_sysfs_init_done; bool mq_sysfs_init_done;
size_t cmd_size;
void *rq_alloc_data;
}; };
#define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */ #define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */