Skip to content

Commit

Permalink
[PATCH] cfq-iosched: don't allow sync merges across queues
Browse files Browse the repository at this point in the history
Currently we allow any merge, even if the io originates from different
processes. This can cause really bad starvation and unfairness, if those
ios happen to be synchronous (reads or direct writes).

So add a allow_merge hook to the io scheduler ops, so an io scheduler can
help decide whether a bio/process combination may be merged with an
existing request.

Signed-off-by: Jens Axboe <[email protected]>
  • Loading branch information
Jens Axboe committed Dec 20, 2006
1 parent 8e5cfc4 commit da77526
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 4 deletions.
33 changes: 33 additions & 0 deletions block/cfq-iosched.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,38 @@ cfq_merged_requests(request_queue_t *q, struct request *rq,
cfq_remove_request(next);
}

static int cfq_allow_merge(request_queue_t *q, struct request *rq,
struct bio *bio)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
const int rw = bio_data_dir(bio);
struct cfq_queue *cfqq;
pid_t key;

/*
* If bio is async or a write, always allow merge
*/
if (!bio_sync(bio) || rw == WRITE)
return 1;

/*
* bio is sync. if request is not, disallow.
*/
if (!rq_is_sync(rq))
return 0;

/*
* Ok, both bio and request are sync. Allow merge if they are
* from the same queue.
*/
key = cfq_queue_pid(current, rw, 1);
cfqq = cfq_find_cfq_hash(cfqd, key, current->ioprio);
if (cfqq != RQ_CFQQ(rq))
return 0;

return 1;
}

static inline void
__cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
Expand Down Expand Up @@ -2125,6 +2157,7 @@ static struct elevator_type iosched_cfq = {
.elevator_merge_fn = cfq_merge,
.elevator_merged_fn = cfq_merged_request,
.elevator_merge_req_fn = cfq_merged_requests,
.elevator_allow_merge_fn = cfq_allow_merge,
.elevator_dispatch_fn = cfq_dispatch_requests,
.elevator_add_req_fn = cfq_insert_request,
.elevator_activate_req_fn = cfq_activate_request,
Expand Down
26 changes: 22 additions & 4 deletions block/elevator.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,21 @@ static const int elv_hash_shift = 6;
#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors)
#define ELV_ON_HASH(rq) (!hlist_unhashed(&(rq)->hash))

/*
* Query io scheduler to see if the current process issuing bio may be
* merged with rq.
*/
static int elv_iosched_allow_merge(struct request *rq, struct bio *bio)
{
request_queue_t *q = rq->q;
elevator_t *e = q->elevator;

if (e->ops->elevator_allow_merge_fn)
return e->ops->elevator_allow_merge_fn(q, rq, bio);

return 1;
}

/*
* can we safely merge with this request?
*/
Expand All @@ -65,12 +80,15 @@ inline int elv_rq_merge_ok(struct request *rq, struct bio *bio)
return 0;

/*
* same device and no special stuff set, merge is ok
* must be same device and not a special request
*/
if (rq->rq_disk == bio->bi_bdev->bd_disk && !rq->special)
return 1;
if (rq->rq_disk != bio->bi_bdev->bd_disk || !rq->special)
return 0;

return 0;
if (!elv_iosched_allow_merge(rq, bio))
return 0;

return 1;
}
EXPORT_SYMBOL(elv_rq_merge_ok);

Expand Down
3 changes: 3 additions & 0 deletions include/linux/elevator.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struc

typedef void (elevator_merged_fn) (request_queue_t *, struct request *, int);

typedef int (elevator_allow_merge_fn) (request_queue_t *, struct request *, struct bio *);

typedef int (elevator_dispatch_fn) (request_queue_t *, int);

typedef void (elevator_add_req_fn) (request_queue_t *, struct request *);
Expand All @@ -33,6 +35,7 @@ struct elevator_ops
elevator_merge_fn *elevator_merge_fn;
elevator_merged_fn *elevator_merged_fn;
elevator_merge_req_fn *elevator_merge_req_fn;
elevator_allow_merge_fn *elevator_allow_merge_fn;

elevator_dispatch_fn *elevator_dispatch_fn;
elevator_add_req_fn *elevator_add_req_fn;
Expand Down

0 comments on commit da77526

Please sign in to comment.