Skip to content

Commit

Permalink
block: introduce Anxiety I/O scheduler
Browse files Browse the repository at this point in the history
Anxiety is a minimal scheduler based on noop. It uses a simple algorithm
prioritizing synchronous requests as they are blocking, and reads over
writes. Requests are stored in compact FIFO queues composed of doubly
linked lists. Latency is the #1 priority.

[kdrag0n: squash initial version & add description]
Co-authored-by: kdrag0n <[email protected]>
Signed-off-by: kdrag0n <[email protected]>
Signed-off-by: Michael <[email protected]>
  • Loading branch information
tytydraco authored and milouk committed Jul 15, 2021
1 parent 0511d65 commit 225472a
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 0 deletions.
11 changes: 11 additions & 0 deletions block/Kconfig.iosched
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ config IOSCHED_CFQ

This is the default I/O scheduler.

config IOSCHED_ANXIETY
tristate "Anxiety I/O scheduler"
default y
---help---
The Anxiety I/O scheduler prioritizes latency over everything
else. When a request comes in, it will use a lighweight
selection algorithm to swiftly process the current pending task.

config CFQ_GROUP_IOSCHED
bool "CFQ Group Scheduling support"
depends on IOSCHED_CFQ && BLK_CGROUP
Expand Down Expand Up @@ -66,11 +74,14 @@ choice
config DEFAULT_TRIPNDROID
bool "TD" if IOSCHED_TRIPNDROID=y

config DEFAULT_ANXIETY
bool "Anxiety" if IOSCHED_ANXIETY=y
endchoice

config DEFAULT_IOSCHED
string
default "deadline" if DEFAULT_DEADLINE
default "anxiety" if DEFAULT_ANXIETY
default "cfq" if DEFAULT_CFQ
default "noop" if DEFAULT_NOOP
default "tripndroid" if DEFAULT_TRIPNDROID
Expand Down
1 change: 1 addition & 0 deletions block/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ obj-$(CONFIG_BLK_DEV_THROTTLING) += blk-throttle.o
obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o
obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o
obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o
obj-$(CONFIG_IOSCHED_ANXIETY) += anxiety-iosched.o
obj-$(CONFIG_IOSCHED_TRIPNDROID) += tripndroid-iosched.o

obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o
Expand Down
141 changes: 141 additions & 0 deletions block/anxiety-iosched.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Anxiety I/O scheduler
* Copywrite (C) 2018 Draco (Tyler Nijmeh) <[email protected]>
*/
#include <linux/blkdev.h>
#include <linux/elevator.h>
#include <linux/bio.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>

#define MAX_WRITES_STARVED 12

enum {ASYNC, SYNC};

struct anxiety_data {
struct list_head queue[2][2];
size_t writes_starved;
};

static void anxiety_merged_requests(struct request_queue *q, struct request *rq, struct request *next) {
rq_fifo_clear(next);
}

static __always_inline struct request *anxiety_choose_request(struct anxiety_data *mdata) {
// ensure that reads will always take priority unless writes are exceedingly starved
bool starved = (mdata->writes_starved > MAX_WRITES_STARVED);

// sync read
if (!starved && !list_empty(&mdata->queue[SYNC][READ])) {
mdata->writes_starved++;
return rq_entry_fifo(mdata->queue[SYNC][READ].next);
}

// sync write
if (!list_empty(&mdata->queue[SYNC][WRITE])) {
mdata->writes_starved = 0;
return rq_entry_fifo(mdata->queue[SYNC][WRITE].next);
}

// async read
if (!starved && !list_empty(&mdata->queue[ASYNC][READ])) {
mdata->writes_starved++;
return rq_entry_fifo(mdata->queue[ASYNC][READ].next);
}

// async write
if (!list_empty(&mdata->queue[ASYNC][WRITE])) {
mdata->writes_starved = 0;
return rq_entry_fifo(mdata->queue[ASYNC][WRITE].next);
}

// all requests are finished
mdata->writes_starved = 0;
return NULL;
}

static int anxiety_dispatch(struct request_queue *q, int force) {
struct request *rq = anxiety_choose_request(q->elevator->elevator_data);
if (!rq)
return 0;

rq_fifo_clear(rq);
elv_dispatch_add_tail(rq->q, rq);
return 1;
}

static void anxiety_add_request(struct request_queue *q, struct request *rq) {
const uint8_t sync = rq_is_sync(rq);
const uint8_t read = rq_data_dir(rq);
list_add_tail(&rq->queuelist, &((struct anxiety_data *) q->elevator->elevator_data)->queue[sync][read]);
}

static struct request *anxiety_former_request(struct request_queue *q, struct request *rq) {
const uint8_t sync = rq_is_sync(rq);
const uint8_t read = rq_data_dir(rq);
if (rq->queuelist.prev == &((struct anxiety_data *) q->elevator->elevator_data)->queue[sync][read])
return NULL;
return list_prev_entry(rq, queuelist);
}

static struct request *anxiety_latter_request(struct request_queue *q, struct request *rq) {
const uint8_t sync = rq_is_sync(rq);
const uint8_t read = rq_data_dir(rq);
if (rq->queuelist.next == &((struct anxiety_data *) q->elevator->elevator_data)->queue[sync][read])
return NULL;
return list_next_entry(rq, queuelist);
}

static int anxiety_init_queue(struct request_queue *q, struct elevator_type *e) {
struct anxiety_data *nd;
struct elevator_queue *eq = elevator_alloc(q, e);
if (!eq)
return -ENOMEM;

nd = kmalloc_node(sizeof(*nd), GFP_KERNEL, q->node);
if (!nd) {
kobject_put(&eq->kobj);
return -ENOMEM;
}
eq->elevator_data = nd;

INIT_LIST_HEAD(&nd->queue[SYNC][READ]);
INIT_LIST_HEAD(&nd->queue[SYNC][WRITE]);
INIT_LIST_HEAD(&nd->queue[ASYNC][READ]);
INIT_LIST_HEAD(&nd->queue[ASYNC][WRITE]);
nd->writes_starved = 0;

spin_lock_irq(q->queue_lock);
q->elevator = eq;
spin_unlock_irq(q->queue_lock);
return 0;
}

static struct elevator_type elevator_anxiety = {
.ops = {
.elevator_merge_req_fn = anxiety_merged_requests,
.elevator_dispatch_fn = anxiety_dispatch,
.elevator_add_req_fn = anxiety_add_request,
.elevator_former_req_fn = anxiety_former_request,
.elevator_latter_req_fn = anxiety_latter_request,
.elevator_init_fn = anxiety_init_queue,
},
.elevator_name = "anxiety",
.elevator_owner = THIS_MODULE,
};

static int __init anxiety_init(void) {
return elv_register(&elevator_anxiety);
}

static void __exit anxiety_exit(void) {
elv_unregister(&elevator_anxiety);
}

module_init(anxiety_init);
module_exit(anxiety_exit);

MODULE_AUTHOR("Draco (Tyler Nijmeh)");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Anxiety IO scheduler");

0 comments on commit 225472a

Please sign in to comment.