Skip to content

Commit 0d257e6

Browse files
committed
support multiple device limit and add CI
Signed-off-by: YangKeao <[email protected]>
1 parent 15febb7 commit 0d257e6

File tree

3 files changed

+71
-37
lines changed

3 files changed

+71
-37
lines changed

.github/workflows/compile.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Compile Kernel Module
2+
3+
on:
4+
push:
5+
branches: [ "master" ]
6+
pull_request:
7+
branches: [ "master" ]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
fail-fast: true
14+
matrix:
15+
target:
16+
- distribution: ubuntu-generic
17+
kernelVersion: 170
18+
releaseVersion: 4.15.0-162-generic
19+
- distribution: debian
20+
kernelVersion: 1
21+
releaseVersion: 4.19.0-18-amd64
22+
- distribution: centos
23+
kernelVersion: 1
24+
releaseVersion: 3.10.0-1160.49.1.el7.x86_64
25+
26+
steps:
27+
- uses: actions/checkout@v2
28+
29+
- name: Build BuildKit
30+
run: docker build -t buildkit ./buildkit/
31+
32+
- name: Build Kernel
33+
run: docker run -v $(pwd)/driver:/driver buildkit buildkit -t ${{ matrix.target.distribution }} -v ${{ matrix.target.kernelVersion }} -k ${{ matrix.target.releaseVersion }}

driver/comp.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,6 @@
1717

1818
#endif
1919

20-
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0)) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
21-
22-
#define bio_is_device(bio,device) (bio->bi_disk != NULL && disk_devt(bio->bi_disk) == device)
23-
24-
#else
25-
26-
#define bio_is_device(bio,device) (bio->bi_bdev != NULL && bio->bi_bdev->bd_dev == device)
27-
28-
#endif
29-
3020
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
3121

3222
#define ns_inum(n) (n->ns.inum)

driver/ioem.c

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@ struct request;
2020
#include "comp.h"
2121

2222
#define rb_to_rq(rb) rb_entry_safe(rb, struct request, rb_node)
23-
#define rq_rb_first_cached(root) rb_to_rq(rb_first_cached(root))
24-
25-
static void ioem_error_injection(struct request* rq);
23+
#define rq_rb_first(root) rb_to_rq(rb_first(root))
2624

25+
#define IS_RHEL
2726
#define IOEM_MQ_ENABLED ((LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || (defined RHEL_MAJOR && RHEL_MAJOR >= 7 && defined RHEL_MINOR && RHEL_MINOR >= 6))
2827

2928
/**
3029
* struct ioem_data - the main data of ioem
3130
* @root: The rb tree root, which is sorted according to `time_to_send`
3231
* @wait_queue: The wait_queue head, which is used to store the waiting requests for IOPS limitation
32+
* @deivce: The device of current ioem_data
3333
* @lock: The spinlock of the whole structure
3434
* @timer: The timer used to trigger the dispatch after reaching the
3535
* `time_to_send`.
@@ -57,10 +57,12 @@ struct ioem_data {
5757
// which may cause frequent rebalance. As the practice of netem, we should
5858
// add a list to optimize for this situation.
5959
// However, current performance seems fine.
60-
struct rb_root_cached root;
60+
struct rb_root root;
6161

6262
struct list_head wait_queue;
6363

64+
dev_t device;
65+
6466
spinlock_t lock;
6567

6668
struct hrtimer timer;
@@ -81,6 +83,8 @@ struct ioem_data {
8183
#endif
8284
};
8385

86+
static void ioem_error_injection(struct ioem_data* id, struct request* rq);
87+
8488
static bool ioem_limit_should_affect(struct ioem_data* data, struct request* rq);
8589

8690
/**
@@ -249,7 +253,7 @@ static void ioem_data_sync_with_injections(struct ioem_data* data);
249253
static void ioem_erase_head(struct ioem_data *data, struct request *rq)
250254
{
251255
if (ioem_priv(rq)->in_rbtree) {
252-
rb_erase_cached(&rq->rb_node, &data->root);
256+
rb_erase(&rq->rb_node, &data->root);
253257
RB_CLEAR_NODE(&rq->rb_node);
254258

255259
ioem_priv(rq)->in_rbtree = false;
@@ -269,7 +273,7 @@ static void ioem_erase_head(struct ioem_data *data, struct request *rq)
269273
*/
270274
static struct request* ioem_peek_request(struct ioem_data *data)
271275
{
272-
struct request* ioem_rq = rq_rb_first_cached(&data->root);
276+
struct request* ioem_rq = rq_rb_first(&data->root);
273277

274278
return ioem_rq;
275279
}
@@ -293,7 +297,7 @@ static void ioem_data_init(struct ioem_data* data, enum hrtimer_restart (*functi
293297
hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
294298

295299
spin_lock_init(&data->lock);
296-
data->root = RB_ROOT_CACHED;
300+
data->root = RB_ROOT;
297301
INIT_LIST_HEAD(&data->wait_queue);
298302

299303
data->timer.function = function;
@@ -311,8 +315,7 @@ static void ioem_data_init(struct ioem_data* data, enum hrtimer_restart (*functi
311315
*/
312316
static void ioem_enqueue(struct ioem_data *data, struct request *rq)
313317
{
314-
struct rb_node **p = &data->root.rb_root.rb_node, *parent = NULL;
315-
bool leftmost = true;
318+
struct rb_node **p = &data->root.rb_node, *parent = NULL;
316319

317320
while (*p) {
318321
struct request* parent_rq;
@@ -322,14 +325,13 @@ static void ioem_enqueue(struct ioem_data *data, struct request *rq)
322325

323326
if (ioem_priv(rq)->time_to_send > ioem_priv(parent_rq)->time_to_send) {
324327
p = &parent->rb_right;
325-
leftmost = false;
326328
}
327329
else
328330
p = &parent->rb_left;
329331
}
330332

331333
rb_link_node(&rq->rb_node, parent, p);
332-
rb_insert_color_cached(&rq->rb_node, &data->root, leftmost);
334+
rb_insert_color(&rq->rb_node, &data->root);
333335

334336
ioem_priv(rq)->in_rbtree = true;
335337
}
@@ -374,11 +376,11 @@ static struct request* ioem_dequeue(struct ioem_data *data)
374376

375377
// at this time, rq is NULL, and the `time_to_send` is 0, or the next time
376378
// when irl counter will be reset.
377-
if (RB_EMPTY_ROOT(&data->root.rb_root)) {
379+
if (RB_EMPTY_ROOT(&data->root)) {
378380
goto out;
379381
}
380382

381-
while (!RB_EMPTY_ROOT(&data->root.rb_root)) {
383+
while (!RB_EMPTY_ROOT(&data->root)) {
382384
rq = ioem_peek_request(data);
383385
if (time_to_send == 0) {
384386
time_to_send = ioem_priv(rq)->time_to_send;
@@ -522,6 +524,12 @@ static int ioem_mq_init_hctx(struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx)
522524
ioem_data_init(id, ioem_mq_timer, hctx->queue->elevator->elevator_data);
523525
id->hctx = hctx;
524526

527+
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 0, 0)
528+
id->device = hctx->queue->backing_dev_info->dev->devt;
529+
#else
530+
id->device = hctx->queue->backing_dev_info.dev->devt;
531+
#endif
532+
525533
hctx->sched_data = id;
526534
return 0;
527535
}
@@ -575,7 +583,7 @@ static void ioem_mq_insert_requests(struct blk_mq_hw_ctx * hctx, struct list_hea
575583
ioem_priv(rq)->in_list = false;
576584
ioem_priv(rq)->in_rbtree = false;
577585

578-
ioem_error_injection(rq);
586+
ioem_error_injection(id, rq);
579587
ioem_enqueue(id, rq);
580588

581589
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0)) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
@@ -590,7 +598,7 @@ static bool ioem_mq_has_work(struct blk_mq_hw_ctx * hctx)
590598
struct ioem_data *id = hctx->sched_data;
591599
bool has_work = 0;
592600

593-
has_work = !(RB_EMPTY_ROOT(&id->root.rb_root) && list_empty(&id->wait_queue));
601+
has_work = !(RB_EMPTY_ROOT(&id->root) && list_empty(&id->wait_queue));
594602

595603
return has_work;
596604
}
@@ -729,6 +737,7 @@ static int ioem_sq_init_sched(struct request_queue *q, struct elevator_type *e)
729737

730738
ioem_data_init(id, ioem_sq_timer, irl);
731739
id->q = q;
740+
id->device = q->backing_dev_info.dev->devt;
732741
INIT_WORK(&id->unplug_work, ioem_sq_kick_queue);
733742

734743
eq->elevator_data = id;
@@ -744,7 +753,7 @@ static void ioem_sq_exit_sched(struct elevator_queue * e)
744753
{
745754
struct ioem_data *id = e->elevator_data;
746755

747-
BUG_ON(!RB_EMPTY_ROOT(&id->root.rb_root));
756+
BUG_ON(!RB_EMPTY_ROOT(&id->root));
748757
hrtimer_cancel(&id->irl->timer);
749758
kfree(id->irl);
750759
kfree(id);
@@ -756,7 +765,7 @@ static void ioem_sq_insert_request(struct request_queue *q, struct request *rq)
756765

757766
ioem_data_sync_with_injections(id);
758767
ioem_priv(rq)->time_to_send = ktime_get_ns();
759-
ioem_error_injection(rq);
768+
ioem_error_injection(id, rq);
760769

761770
ioem_enqueue(id, rq);
762771

@@ -1066,7 +1075,7 @@ static s64 ioem_random(s64 mu, s32 jitter, struct crndstate *state) {
10661075
* `current` should point to the current process, so that we can get the pid
10671076
* namespace (or other information) of the process.
10681077
*/
1069-
static bool ioem_should_inject(struct request* rq, struct ioem_injection* e) {
1078+
static bool ioem_should_inject(struct ioem_data* id, struct request* rq, struct ioem_injection* e) {
10701079
if (rq->bio == NULL || e == NULL) {
10711080
return 0;
10721081
}
@@ -1075,7 +1084,7 @@ static bool ioem_should_inject(struct request* rq, struct ioem_injection* e) {
10751084
return 0;
10761085
}
10771086

1078-
if (e->arg.device != 0 && !bio_is_device(rq->bio, e->arg.device)) {
1087+
if (e->arg.device != 0 && e->arg.device == id->device) {
10791088
return 0;
10801089
}
10811090

@@ -1093,15 +1102,15 @@ static bool ioem_should_inject(struct request* rq, struct ioem_injection* e) {
10931102
return 1;
10941103
}
10951104

1096-
static void ioem_error_injection(struct request* rq)
1105+
static void ioem_error_injection(struct ioem_data* id, struct request* rq)
10971106
{
10981107
struct ioem_injection* e;
10991108
u64 delay = 0;
11001109

11011110
read_lock(&ioem_injections.lock);
11021111
list_for_each_entry(e, &ioem_injections.list, list)
11031112
{
1104-
if (!ioem_should_inject(rq, e)) {
1113+
if (!ioem_should_inject(id, rq, e)) {
11051114
continue;
11061115
}
11071116

@@ -1125,7 +1134,7 @@ static bool ioem_limit_should_affect(struct ioem_data* data, struct request* rq)
11251134
bool should_affect;
11261135

11271136
read_lock(&ioem_injections.lock);
1128-
should_affect = ioem_should_inject(rq, data->ioem_limit);
1137+
should_affect = ioem_should_inject(data, rq, data->ioem_limit);
11291138
read_unlock(&ioem_injections.lock);
11301139

11311140
return should_affect;
@@ -1160,11 +1169,13 @@ static void ioem_data_sync_with_injections(struct ioem_data* data)
11601169
list_for_each_entry(e, &ioem_injections.list, list)
11611170
{
11621171
if (e->injector_type == IOEM_INJECTOR_TYPE_LIMIT) {
1163-
irl_change(data->irl, e->limit.period_us, e->limit.quota);
1164-
kref_get(&e->refcount);
1165-
data->ioem_limit = e;
1166-
// multiple limit is not supported
1167-
break;
1172+
if (e->arg.device == 0 || data->device == e->arg.device) {
1173+
irl_change(data->irl, e->limit.period_us, e->limit.quota);
1174+
kref_get(&e->refcount);
1175+
data->ioem_limit = e;
1176+
// multiple limit is not supported
1177+
break;
1178+
}
11681179
}
11691180
}
11701181
data->ioem_injection_version = atomic_read(&ioem_injections.version);

0 commit comments

Comments
 (0)