Commit ac062f74 authored by Jens Axboe's avatar Jens Axboe Committed by Linus Torvalds

[PATCH] dynamic request allocation

This patch adds dynamic allocation of request structures. Right now we
are reserving 256 requests per initialized queue, which adds up to quite
a lot of memory for even a modest number of queues. For the quoted 4000
disk systems, it's a disaster.

Instead, we mempool 4 requests per queue and put an upper limit on the
number of requests that we will put in-flight as well. I've kept the 128
read/write max in-flight limit for now. It is trivial to experiement
with larger queue sizes now, but I want to change one thing at the time
(the truncate scenario doesn't look all that good with a huge number of
requests, for instance).

Patch has been in -mm for a while, I'm running it here against stock 2.5
as well. Additionally, it actually kills quite a bit of code as well
parent 0975ab2a
......@@ -71,6 +71,8 @@ struct deadline_data {
int fifo_batch;
int writes_starved;
int front_merges;
mempool_t *drq_pool;
};
/*
......@@ -690,28 +692,11 @@ deadline_latter_request(request_queue_t *q, struct request *rq)
static void deadline_exit(request_queue_t *q, elevator_t *e)
{
struct deadline_data *dd = e->elevator_data;
struct deadline_rq *drq;
struct request *rq;
int i;
BUG_ON(!list_empty(&dd->fifo_list[READ]));
BUG_ON(!list_empty(&dd->fifo_list[WRITE]));
for (i = READ; i <= WRITE; i++) {
struct request_list *rl = &q->rq[i];
struct list_head *entry;
list_for_each(entry, &rl->free) {
rq = list_entry_rq(entry);
if ((drq = RQ_DATA(rq)) == NULL)
continue;
rq->elevator_private = NULL;
kmem_cache_free(drq_pool, drq);
}
}
mempool_destroy(dd->drq_pool);
kfree(dd->hash);
kfree(dd);
}
......@@ -723,9 +708,7 @@ static void deadline_exit(request_queue_t *q, elevator_t *e)
static int deadline_init(request_queue_t *q, elevator_t *e)
{
struct deadline_data *dd;
struct deadline_rq *drq;
struct request *rq;
int i, ret = 0;
int i;
if (!drq_pool)
return -ENOMEM;
......@@ -741,6 +724,13 @@ static int deadline_init(request_queue_t *q, elevator_t *e)
return -ENOMEM;
}
dd->drq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, drq_pool);
if (!dd->drq_pool) {
kfree(dd->hash);
kfree(dd);
return -ENOMEM;
}
for (i = 0; i < DL_HASH_ENTRIES; i++)
INIT_LIST_HEAD(&dd->hash[i]);
......@@ -756,33 +746,41 @@ static int deadline_init(request_queue_t *q, elevator_t *e)
dd->front_merges = 1;
dd->fifo_batch = fifo_batch;
e->elevator_data = dd;
return 0;
}
for (i = READ; i <= WRITE; i++) {
struct request_list *rl = &q->rq[i];
struct list_head *entry;
static void deadline_put_request(request_queue_t *q, struct request *rq)
{
struct deadline_data *dd = q->elevator.elevator_data;
struct deadline_rq *drq = RQ_DATA(rq);
list_for_each(entry, &rl->free) {
rq = list_entry_rq(entry);
if (drq) {
mempool_free(drq, dd->drq_pool);
rq->elevator_private = NULL;
}
}
drq = kmem_cache_alloc(drq_pool, GFP_KERNEL);
if (!drq) {
ret = -ENOMEM;
break;
}
static int
deadline_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
{
struct deadline_data *dd = q->elevator.elevator_data;
struct deadline_rq *drq;
memset(drq, 0, sizeof(*drq));
INIT_LIST_HEAD(&drq->fifo);
INIT_LIST_HEAD(&drq->hash);
RB_CLEAR(&drq->rb_node);
drq->request = rq;
rq->elevator_private = drq;
}
}
drq = mempool_alloc(dd->drq_pool, gfp_mask);
if (drq) {
RB_CLEAR(&drq->rb_node);
drq->request = rq;
if (ret)
deadline_exit(q, e);
INIT_LIST_HEAD(&drq->hash);
drq->hash_valid_count = 0;
return ret;
INIT_LIST_HEAD(&drq->fifo);
rq->elevator_private = drq;
return 0;
}
return 1;
}
/*
......@@ -933,6 +931,8 @@ elevator_t iosched_deadline = {
.elevator_queue_empty_fn = deadline_queue_empty,
.elevator_former_req_fn = deadline_former_request,
.elevator_latter_req_fn = deadline_latter_request,
.elevator_set_req_fn = deadline_set_request,
.elevator_put_req_fn = deadline_put_request,
.elevator_init_fn = deadline_init,
.elevator_exit_fn = deadline_exit,
......
......@@ -408,6 +408,25 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq)
return NULL;
}
int elv_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
{
elevator_t *e = &q->elevator;
if (e->elevator_set_req_fn)
return e->elevator_set_req_fn(q, rq, gfp_mask);
rq->elevator_private = NULL;
return 0;
}
void elv_put_request(request_queue_t *q, struct request *rq)
{
elevator_t *e = &q->elevator;
if (e->elevator_put_req_fn)
e->elevator_put_req_fn(q, rq);
}
int elv_register_queue(struct gendisk *disk)
{
request_queue_t *q = disk->queue;
......
This diff is collapsed.
......@@ -10,6 +10,7 @@
#include <linux/pagemap.h>
#include <linux/backing-dev.h>
#include <linux/wait.h>
#include <linux/mempool.h>
#include <asm/scatterlist.h>
......@@ -18,10 +19,12 @@ typedef struct request_queue request_queue_t;
struct elevator_s;
typedef struct elevator_s elevator_t;
#define BLKDEV_MIN_RQ 4
#define BLKDEV_MAX_RQ 128
struct request_list {
unsigned int count;
struct list_head free;
wait_queue_head_t wait;
int count[2];
mempool_t *rq_pool;
};
/*
......@@ -180,7 +183,7 @@ struct request_queue
/*
* the queue request freelist, one for reads and one for writes
*/
struct request_list rq[2];
struct request_list rq;
request_fn_proc *request_fn;
merge_request_fn *back_merge_fn;
......@@ -329,7 +332,6 @@ extern void blk_put_request(struct request *);
extern void blk_attempt_remerge(request_queue_t *, struct request *);
extern void __blk_attempt_remerge(request_queue_t *, struct request *);
extern struct request *blk_get_request(request_queue_t *, int, int);
extern struct request *__blk_get_request(request_queue_t *, int);
extern void blk_put_request(struct request *);
extern void blk_insert_request(request_queue_t *, struct request *, int, void *);
extern void blk_plug_device(request_queue_t *);
......
......@@ -15,6 +15,8 @@ typedef int (elevator_queue_empty_fn) (request_queue_t *);
typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *);
typedef struct request *(elevator_request_list_fn) (request_queue_t *, struct request *);
typedef struct list_head *(elevator_get_sort_head_fn) (request_queue_t *, struct request *);
typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, int);
typedef void (elevator_put_req_fn) (request_queue_t *, struct request *);
typedef int (elevator_init_fn) (request_queue_t *, elevator_t *);
typedef void (elevator_exit_fn) (request_queue_t *, elevator_t *);
......@@ -34,6 +36,9 @@ struct elevator_s
elevator_request_list_fn *elevator_former_req_fn;
elevator_request_list_fn *elevator_latter_req_fn;
elevator_set_req_fn *elevator_set_req_fn;
elevator_put_req_fn *elevator_put_req_fn;
elevator_init_fn *elevator_init_fn;
elevator_exit_fn *elevator_exit_fn;
......@@ -59,6 +64,8 @@ extern struct request *elv_former_request(request_queue_t *, struct request *);
extern struct request *elv_latter_request(request_queue_t *, struct request *);
extern int elv_register_queue(struct gendisk *);
extern void elv_unregister_queue(struct gendisk *);
extern int elv_set_request(request_queue_t *, struct request *, int);
extern void elv_put_request(request_queue_t *, struct request *);
#define __elv_add_request_pos(q, rq, pos) \
(q)->elevator.elevator_add_req_fn((q), (rq), (pos))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment