add patches
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/x86_64 4.9.21 Kernel Configuration
|
||||
# Linux/x86_64 4.9.27 Kernel Configuration
|
||||
#
|
||||
CONFIG_64BIT=y
|
||||
CONFIG_X86_64=y
|
||||
|
||||
Binary file not shown.
+192
-170
@@ -1,9 +1,13 @@
|
||||
From 3e3791c0b4ef3b2067f8454e58001af8e3da3840 Mon Sep 17 00:00:00 2001
|
||||
From 0432a5c7bfc4a11531c1e58f574c733a2552f149 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Valente <paolo.valente@linaro.org>
|
||||
Date: Tue, 17 May 2016 08:28:04 +0200
|
||||
Subject: [PATCH 4/4] Turn into BFQ-v8r6 for 4.9.0
|
||||
Subject: [PATCH 4/4] Turn into BFQ-v8r7 for 4.9.0
|
||||
|
||||
CHANGELOG from v8r4 to v8r6
|
||||
CHANGELOG from v8r4 to v8r7
|
||||
|
||||
BFQ v8r7
|
||||
|
||||
BUGFIX: make BFQ compile also without hierarchical support
|
||||
|
||||
BFQ v8r6
|
||||
|
||||
@@ -125,9 +129,9 @@ Signed-off-by: Paolo Valente <paolo.valente@linaro.org>
|
||||
block/Kconfig.iosched | 18 +-
|
||||
block/bfq-cgroup.c | 501 +++---
|
||||
block/bfq-iosched.c | 3278 ++++++++++++++++++++++-------------
|
||||
block/bfq-sched.c | 1270 +++++++++++---
|
||||
block/bfq-sched.c | 1288 +++++++++++---
|
||||
block/bfq.h | 800 +++++----
|
||||
7 files changed, 4310 insertions(+), 2089 deletions(-)
|
||||
7 files changed, 4320 insertions(+), 2097 deletions(-)
|
||||
create mode 100644 Documentation/block/bfq-iosched.txt
|
||||
|
||||
diff --git a/Documentation/block/00-INDEX b/Documentation/block/00-INDEX
|
||||
@@ -1601,7 +1605,7 @@ index 0367996..bbaecd0 100644
|
||||
|
||||
static struct bfq_group *
|
||||
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
|
||||
index cf3e9b1..0f9cd53 100644
|
||||
index cf3e9b1..2a2c130 100644
|
||||
--- a/block/bfq-iosched.c
|
||||
+++ b/block/bfq-iosched.c
|
||||
@@ -1,5 +1,5 @@
|
||||
@@ -6201,7 +6205,7 @@ index cf3e9b1..0f9cd53 100644
|
||||
-
|
||||
- if (bfq_timeout_async == 0)
|
||||
- bfq_timeout_async = 1;
|
||||
+ char msg[60] = "BFQ I/O-scheduler: v8r6";
|
||||
+ char msg[60] = "BFQ I/O-scheduler: v8r7";
|
||||
|
||||
#ifdef CONFIG_BFQ_GROUP_IOSCHED
|
||||
ret = blkcg_policy_register(&blkcg_policy_bfq);
|
||||
@@ -6265,10 +6269,10 @@ index cf3e9b1..0f9cd53 100644
|
||||
return 0;
|
||||
|
||||
diff --git a/block/bfq-sched.c b/block/bfq-sched.c
|
||||
index a5ed694..4af77f4 100644
|
||||
index a5ed694..797bce7 100644
|
||||
--- a/block/bfq-sched.c
|
||||
+++ b/block/bfq-sched.c
|
||||
@@ -7,28 +7,46 @@
|
||||
@@ -7,28 +7,166 @@
|
||||
* Copyright (C) 2008 Fabio Checconi <fabio@gandalf.sssup.it>
|
||||
* Paolo Valente <paolo.valente@unimore.it>
|
||||
*
|
||||
@@ -6276,8 +6280,8 @@ index a5ed694..4af77f4 100644
|
||||
+ * Copyright (C) 2015 Paolo Valente <paolo.valente@unimore.it>
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Paolo Valente <paolo.valente@linaro.org>
|
||||
*/
|
||||
|
||||
+ */
|
||||
+
|
||||
+static struct bfq_group *bfqq_group(struct bfq_queue *bfqq);
|
||||
+
|
||||
+/**
|
||||
@@ -6292,63 +6296,17 @@ index a5ed694..4af77f4 100644
|
||||
+ return (s64)(a - b) > 0;
|
||||
+}
|
||||
+
|
||||
#ifdef CONFIG_BFQ_GROUP_IOSCHED
|
||||
-#define for_each_entity(entity) \
|
||||
+/* both next loops stop at one of the child entities of the root group */
|
||||
+#define for_each_entity(entity) \
|
||||
for (; entity ; entity = entity->parent)
|
||||
|
||||
#define for_each_entity_safe(entity, parent) \
|
||||
for (; entity && ({ parent = entity->parent; 1; }); entity = parent)
|
||||
|
||||
|
||||
-static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd,
|
||||
- int extract,
|
||||
- struct bfq_data *bfqd);
|
||||
-
|
||||
-static struct bfq_group *bfqq_group(struct bfq_queue *bfqq);
|
||||
+static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd);
|
||||
|
||||
-static void bfq_update_budget(struct bfq_entity *next_in_service)
|
||||
+/*
|
||||
+ * Returns true if this budget changes may let next_in_service->parent
|
||||
+ * become the next_in_service entity for its parent entity.
|
||||
+ */
|
||||
+static bool bfq_update_parent_budget(struct bfq_entity *next_in_service)
|
||||
{
|
||||
struct bfq_entity *bfqg_entity;
|
||||
struct bfq_group *bfqg;
|
||||
struct bfq_sched_data *group_sd;
|
||||
+ bool ret = false;
|
||||
|
||||
BUG_ON(!next_in_service);
|
||||
|
||||
@@ -41,39 +59,134 @@ static void bfq_update_budget(struct bfq_entity *next_in_service)
|
||||
* as it must never become an in-service entity.
|
||||
*/
|
||||
bfqg_entity = bfqg->my_entity;
|
||||
- if (bfqg_entity)
|
||||
+ if (bfqg_entity) {
|
||||
+ if (bfqg_entity->budget > next_in_service->budget)
|
||||
+ ret = true;
|
||||
bfqg_entity->budget = next_in_service->budget;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
-static int bfq_update_next_in_service(struct bfq_sched_data *sd)
|
||||
+static struct bfq_entity *bfq_root_active_entity(struct rb_root *tree)
|
||||
{
|
||||
- struct bfq_entity *next_in_service;
|
||||
+{
|
||||
+ struct rb_node *node = tree->rb_node;
|
||||
|
||||
- if (sd->in_service_entity)
|
||||
- /* will update/requeue at the end of service */
|
||||
- return 0;
|
||||
+
|
||||
+ return rb_entry(node, struct bfq_entity, rb_node);
|
||||
+}
|
||||
+
|
||||
+static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd);
|
||||
+
|
||||
+static bool bfq_update_parent_budget(struct bfq_entity *next_in_service);
|
||||
+
|
||||
+/**
|
||||
+ * bfq_update_next_in_service - update sd->next_in_service
|
||||
+ * @sd: sched_data for which to perform the update.
|
||||
@@ -6371,20 +6329,15 @@ index a5ed694..4af77f4 100644
|
||||
+ * Returns true if sd->next_in_service changes in such a way that
|
||||
+ * entity->parent may become the next_in_service for its parent
|
||||
+ * entity.
|
||||
+ */
|
||||
*/
|
||||
+static bool bfq_update_next_in_service(struct bfq_sched_data *sd,
|
||||
+ struct bfq_entity *new_entity)
|
||||
+{
|
||||
+ struct bfq_entity *next_in_service = sd->next_in_service;
|
||||
+ struct bfq_queue *bfqq;
|
||||
+ bool parent_sched_may_change = false;
|
||||
|
||||
/*
|
||||
- * NOTE: this can be improved in many ways, such as returning
|
||||
- * 1 (and thus propagating upwards the update) only when the
|
||||
- * budget changes, or caching the bfqq that will be scheduled
|
||||
- * next from this subtree. By now we worry more about
|
||||
- * correctness than about performance...
|
||||
+
|
||||
+ /*
|
||||
+ * If this update is triggered by the activation, requeueing
|
||||
+ * or repositiong of an entity that does not coincide with
|
||||
+ * sd->next_in_service, then a full lookup in the active tree
|
||||
@@ -6395,8 +6348,7 @@ index a5ed694..4af77f4 100644
|
||||
+ * finish time than sd->next_in_service. If this compound
|
||||
+ * condition holds, then the new entity becomes the new
|
||||
+ * next_in_service. Otherwise no change is needed.
|
||||
*/
|
||||
- next_in_service = bfq_lookup_next_entity(sd, 0, NULL);
|
||||
+ */
|
||||
+ if (new_entity && new_entity != sd->next_in_service) {
|
||||
+ /*
|
||||
+ * Flag used to decide whether to replace
|
||||
@@ -6445,54 +6397,160 @@ index a5ed694..4af77f4 100644
|
||||
+ bfq_update_parent_budget(next_in_service);
|
||||
+ }
|
||||
+
|
||||
sd->next_in_service = next_in_service;
|
||||
|
||||
- if (next_in_service)
|
||||
- bfq_update_budget(next_in_service);
|
||||
+ sd->next_in_service = next_in_service;
|
||||
+
|
||||
+ if (!next_in_service)
|
||||
+ return parent_sched_may_change;
|
||||
|
||||
- return 1;
|
||||
-}
|
||||
+ bfqq = bfq_entity_to_bfqq(next_in_service);
|
||||
+ if (bfqq)
|
||||
+ bfq_log_bfqq(bfqq->bfqd, bfqq,
|
||||
+ "update_next_in_service: chosen this queue");
|
||||
+#ifdef CONFIG_BFQ_GROUP_IOSCHED
|
||||
#ifdef CONFIG_BFQ_GROUP_IOSCHED
|
||||
-#define for_each_entity(entity) \
|
||||
+ else {
|
||||
+ struct bfq_group *bfqg =
|
||||
+ container_of(next_in_service,
|
||||
+ struct bfq_group, entity);
|
||||
|
||||
-static void bfq_check_next_in_service(struct bfq_sched_data *sd,
|
||||
- struct bfq_entity *entity)
|
||||
-{
|
||||
- BUG_ON(sd->next_in_service != entity);
|
||||
+
|
||||
+ bfq_log_bfqg((struct bfq_data *)bfqg->bfqd, bfqg,
|
||||
+ "update_next_in_service: chosen this entity");
|
||||
+ }
|
||||
+#endif
|
||||
+ return parent_sched_may_change;
|
||||
}
|
||||
+}
|
||||
+
|
||||
#else
|
||||
#define for_each_entity(entity) \
|
||||
for (; entity ; entity = NULL)
|
||||
@@ -86,12 +199,7 @@ static int bfq_update_next_in_service(struct bfq_sched_data *sd)
|
||||
return 0;
|
||||
+#ifdef CONFIG_BFQ_GROUP_IOSCHED
|
||||
+/* both next loops stop at one of the child entities of the root group */
|
||||
+#define for_each_entity(entity) \
|
||||
for (; entity ; entity = entity->parent)
|
||||
|
||||
#define for_each_entity_safe(entity, parent) \
|
||||
for (; entity && ({ parent = entity->parent; 1; }); entity = parent)
|
||||
|
||||
-
|
||||
-static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd,
|
||||
- int extract,
|
||||
- struct bfq_data *bfqd);
|
||||
-
|
||||
-static struct bfq_group *bfqq_group(struct bfq_queue *bfqq);
|
||||
-
|
||||
-static void bfq_update_budget(struct bfq_entity *next_in_service)
|
||||
+/*
|
||||
+ * Returns true if this budget changes may let next_in_service->parent
|
||||
+ * become the next_in_service entity for its parent entity.
|
||||
+ */
|
||||
+static bool bfq_update_parent_budget(struct bfq_entity *next_in_service)
|
||||
{
|
||||
struct bfq_entity *bfqg_entity;
|
||||
struct bfq_group *bfqg;
|
||||
struct bfq_sched_data *group_sd;
|
||||
+ bool ret = false;
|
||||
|
||||
BUG_ON(!next_in_service);
|
||||
|
||||
@@ -41,60 +179,68 @@ static void bfq_update_budget(struct bfq_entity *next_in_service)
|
||||
* as it must never become an in-service entity.
|
||||
*/
|
||||
bfqg_entity = bfqg->my_entity;
|
||||
- if (bfqg_entity)
|
||||
+ if (bfqg_entity) {
|
||||
+ if (bfqg_entity->budget > next_in_service->budget)
|
||||
+ ret = true;
|
||||
bfqg_entity->budget = next_in_service->budget;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
-static int bfq_update_next_in_service(struct bfq_sched_data *sd)
|
||||
+/*
|
||||
+ * This function tells whether entity stops being a candidate for next
|
||||
+ * service, according to the following logic.
|
||||
+ *
|
||||
+ * This function is invoked for an entity that is about to be set in
|
||||
+ * service. If such an entity is a queue, then the entity is no longer
|
||||
+ * a candidate for next service (i.e, a candidate entity to serve
|
||||
+ * after the in-service entity is expired). The function then returns
|
||||
+ * true.
|
||||
+ *
|
||||
+ * In contrast, the entity could stil be a candidate for next service
|
||||
+ * if it is not a queue, and has more than one child. In fact, even if
|
||||
+ * one of its children is about to be set in service, other children
|
||||
+ * may still be the next to serve. As a consequence, a non-queue
|
||||
+ * entity is not a candidate for next-service only if it has only one
|
||||
+ * child. And only if this condition holds, then the function returns
|
||||
+ * true for a non-queue entity.
|
||||
+ */
|
||||
+static bool bfq_no_longer_next_in_service(struct bfq_entity *entity)
|
||||
{
|
||||
- struct bfq_entity *next_in_service;
|
||||
+ struct bfq_group *bfqg;
|
||||
|
||||
- if (sd->in_service_entity)
|
||||
- /* will update/requeue at the end of service */
|
||||
- return 0;
|
||||
+ if (bfq_entity_to_bfqq(entity))
|
||||
+ return true;
|
||||
|
||||
- /*
|
||||
- * NOTE: this can be improved in many ways, such as returning
|
||||
- * 1 (and thus propagating upwards the update) only when the
|
||||
- * budget changes, or caching the bfqq that will be scheduled
|
||||
- * next from this subtree. By now we worry more about
|
||||
- * correctness than about performance...
|
||||
- */
|
||||
- next_in_service = bfq_lookup_next_entity(sd, 0, NULL);
|
||||
- sd->next_in_service = next_in_service;
|
||||
+ bfqg = container_of(entity, struct bfq_group, entity);
|
||||
|
||||
- if (next_in_service)
|
||||
- bfq_update_budget(next_in_service);
|
||||
+ BUG_ON(bfqg == ((struct bfq_data *)(bfqg->bfqd))->root_group);
|
||||
+ BUG_ON(bfqg->active_entities == 0);
|
||||
+ if (bfqg->active_entities == 1)
|
||||
+ return true;
|
||||
|
||||
- return 1;
|
||||
+ return false;
|
||||
}
|
||||
|
||||
-static void bfq_check_next_in_service(struct bfq_sched_data *sd,
|
||||
- struct bfq_entity *entity)
|
||||
-{
|
||||
- BUG_ON(sd->next_in_service != entity);
|
||||
-}
|
||||
-
|
||||
-static void bfq_update_budget(struct bfq_entity *next_in_service)
|
||||
+static void bfq_update_parent_budget(struct bfq_entity *next_in_service)
|
||||
-#else
|
||||
+#else /* CONFIG_BFQ_GROUP_IOSCHED */
|
||||
#define for_each_entity(entity) \
|
||||
for (; entity ; entity = NULL)
|
||||
|
||||
#define for_each_entity_safe(entity, parent) \
|
||||
for (parent = NULL; entity ; entity = parent)
|
||||
|
||||
-static int bfq_update_next_in_service(struct bfq_sched_data *sd)
|
||||
+static bool bfq_update_parent_budget(struct bfq_entity *next_in_service)
|
||||
{
|
||||
- return 0;
|
||||
+ return false;
|
||||
}
|
||||
#endif
|
||||
@@ -105,18 +213,6 @@ static void bfq_update_budget(struct bfq_entity *next_in_service)
|
||||
|
||||
-static void bfq_check_next_in_service(struct bfq_sched_data *sd,
|
||||
- struct bfq_entity *entity)
|
||||
+static bool bfq_no_longer_next_in_service(struct bfq_entity *entity)
|
||||
{
|
||||
+ return true;
|
||||
}
|
||||
|
||||
-static void bfq_update_budget(struct bfq_entity *next_in_service)
|
||||
-{
|
||||
-}
|
||||
-#endif
|
||||
+#endif /* CONFIG_BFQ_GROUP_IOSCHED */
|
||||
|
||||
/*
|
||||
* Shift for timestamp calculations. This actually limits the maximum
|
||||
@@ -105,18 +251,6 @@ static void bfq_update_budget(struct bfq_entity *next_in_service)
|
||||
*/
|
||||
#define WFQ_SERVICE_SHIFT 22
|
||||
|
||||
@@ -6511,7 +6569,7 @@ index a5ed694..4af77f4 100644
|
||||
static struct bfq_queue *bfq_entity_to_bfqq(struct bfq_entity *entity)
|
||||
{
|
||||
struct bfq_queue *bfqq = NULL;
|
||||
@@ -151,20 +247,36 @@ static u64 bfq_delta(unsigned long service, unsigned long weight)
|
||||
@@ -151,20 +285,36 @@ static u64 bfq_delta(unsigned long service, unsigned long weight)
|
||||
static void bfq_calc_finish(struct bfq_entity *entity, unsigned long service)
|
||||
{
|
||||
struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
|
||||
@@ -6550,7 +6608,7 @@ index a5ed694..4af77f4 100644
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,10 +405,26 @@ static void bfq_update_min(struct bfq_entity *entity, struct rb_node *node)
|
||||
@@ -293,10 +443,26 @@ static void bfq_update_min(struct bfq_entity *entity, struct rb_node *node)
|
||||
static void bfq_update_active_node(struct rb_node *node)
|
||||
{
|
||||
struct bfq_entity *entity = rb_entry(node, struct bfq_entity, rb_node);
|
||||
@@ -6577,7 +6635,7 @@ index a5ed694..4af77f4 100644
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -386,8 +514,6 @@ static void bfq_active_insert(struct bfq_service_tree *st,
|
||||
@@ -386,8 +552,6 @@ static void bfq_active_insert(struct bfq_service_tree *st,
|
||||
BUG_ON(!bfqg);
|
||||
BUG_ON(!bfqd);
|
||||
bfqg->active_entities++;
|
||||
@@ -6586,7 +6644,7 @@ index a5ed694..4af77f4 100644
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -399,7 +525,7 @@ static void bfq_active_insert(struct bfq_service_tree *st,
|
||||
@@ -399,7 +563,7 @@ static void bfq_active_insert(struct bfq_service_tree *st,
|
||||
static unsigned short bfq_ioprio_to_weight(int ioprio)
|
||||
{
|
||||
BUG_ON(ioprio < 0 || ioprio >= IOPRIO_BE_NR);
|
||||
@@ -6595,7 +6653,7 @@ index a5ed694..4af77f4 100644
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -422,9 +548,9 @@ static void bfq_get_entity(struct bfq_entity *entity)
|
||||
@@ -422,9 +586,9 @@ static void bfq_get_entity(struct bfq_entity *entity)
|
||||
struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
|
||||
|
||||
if (bfqq) {
|
||||
@@ -6607,7 +6665,7 @@ index a5ed694..4af77f4 100644
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,10 +625,6 @@ static void bfq_active_extract(struct bfq_service_tree *st,
|
||||
@@ -499,10 +663,6 @@ static void bfq_active_extract(struct bfq_service_tree *st,
|
||||
BUG_ON(!bfqd);
|
||||
BUG_ON(!bfqg->active_entities);
|
||||
bfqg->active_entities--;
|
||||
@@ -6618,7 +6676,7 @@ index a5ed694..4af77f4 100644
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -547,12 +669,12 @@ static void bfq_forget_entity(struct bfq_service_tree *st,
|
||||
@@ -547,12 +707,12 @@ static void bfq_forget_entity(struct bfq_service_tree *st,
|
||||
|
||||
BUG_ON(!entity->on_st);
|
||||
|
||||
@@ -6633,7 +6691,7 @@ index a5ed694..4af77f4 100644
|
||||
bfq_put_queue(bfqq);
|
||||
}
|
||||
}
|
||||
@@ -602,7 +724,7 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
|
||||
@@ -602,7 +762,7 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
|
||||
|
||||
if (entity->prio_changed) {
|
||||
struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
|
||||
@@ -6642,7 +6700,7 @@ index a5ed694..4af77f4 100644
|
||||
struct bfq_data *bfqd = NULL;
|
||||
struct rb_root *root;
|
||||
#ifdef CONFIG_BFQ_GROUP_IOSCHED
|
||||
@@ -630,7 +752,10 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
|
||||
@@ -630,7 +790,10 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
|
||||
entity->new_weight > BFQ_MAX_WEIGHT) {
|
||||
pr_crit("update_weight_prio: new_weight %d\n",
|
||||
entity->new_weight);
|
||||
@@ -6654,7 +6712,7 @@ index a5ed694..4af77f4 100644
|
||||
}
|
||||
entity->orig_weight = entity->new_weight;
|
||||
if (bfqq)
|
||||
@@ -661,6 +786,13 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
|
||||
@@ -661,6 +824,13 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
|
||||
* associated with its new weight.
|
||||
*/
|
||||
if (prev_weight != new_weight) {
|
||||
@@ -6668,7 +6726,7 @@ index a5ed694..4af77f4 100644
|
||||
root = bfqq ? &bfqd->queue_weights_tree :
|
||||
&bfqd->group_weights_tree;
|
||||
bfq_weights_tree_remove(bfqd, entity, root);
|
||||
@@ -707,7 +839,7 @@ static void bfq_bfqq_served(struct bfq_queue *bfqq, int served)
|
||||
@@ -707,7 +877,7 @@ static void bfq_bfqq_served(struct bfq_queue *bfqq, int served)
|
||||
st = bfq_entity_service_tree(entity);
|
||||
|
||||
entity->service += served;
|
||||
@@ -6677,7 +6735,7 @@ index a5ed694..4af77f4 100644
|
||||
BUG_ON(st->wsum == 0);
|
||||
|
||||
st->vtime += bfq_delta(served, st->wsum);
|
||||
@@ -716,170 +848,419 @@ static void bfq_bfqq_served(struct bfq_queue *bfqq, int served)
|
||||
@@ -716,170 +886,419 @@ static void bfq_bfqq_served(struct bfq_queue *bfqq, int served)
|
||||
#ifdef CONFIG_BFQ_GROUP_IOSCHED
|
||||
bfqg_stats_set_start_empty_time(bfqq_group(bfqq));
|
||||
#endif
|
||||
@@ -6731,17 +6789,17 @@ index a5ed694..4af77f4 100644
|
||||
+ if (time_ms > 0 && time_ms < timeout_ms)
|
||||
+ tot_serv_to_charge =
|
||||
+ (bfqd->bfq_max_budget * time_ms) / timeout_ms;
|
||||
+
|
||||
|
||||
- bfq_log_bfqq(bfqq->bfqd, bfqq, "charge_full_budget");
|
||||
+ if (tot_serv_to_charge < entity->service)
|
||||
+ tot_serv_to_charge = entity->service;
|
||||
|
||||
- bfq_log_bfqq(bfqq->bfqd, bfqq, "charge_full_budget");
|
||||
- bfq_bfqq_served(bfqq, entity->budget - entity->service);
|
||||
+ bfq_log_bfqq(bfqq->bfqd, bfqq,
|
||||
+ "charge_time: %lu/%u ms, %d/%d/%d sectors",
|
||||
+ time_ms, timeout_ms, entity->service,
|
||||
+ tot_serv_to_charge, entity->budget);
|
||||
|
||||
- bfq_bfqq_served(bfqq, entity->budget - entity->service);
|
||||
+
|
||||
+ /* Increase budget to avoid inconsistencies */
|
||||
+ if (tot_serv_to_charge > entity->budget)
|
||||
+ entity->budget = tot_serv_to_charge;
|
||||
@@ -6948,19 +7006,20 @@ index a5ed694..4af77f4 100644
|
||||
- * @entity: the entity to activate.
|
||||
+ * __bfq_requeue_entity - handle requeueing or repositioning of an entity.
|
||||
+ * @entity: the entity being requeued or repositioned.
|
||||
*
|
||||
- * Activate @entity and all the entities on the path from it to the root.
|
||||
+ *
|
||||
+ * Requeueing is needed if this entity stops being served, which
|
||||
+ * happens if a leaf descendant entity has expired. On the other hand,
|
||||
+ * repositioning is needed if the next_inservice_entity for the child
|
||||
+ * entity has changed. See the comments inside the function for
|
||||
+ * details.
|
||||
+ *
|
||||
*
|
||||
- * Activate @entity and all the entities on the path from it to the root.
|
||||
+ * Basically, this function: 1) removes entity from its active tree if
|
||||
+ * present there, 2) updates the timestamps of entity and 3) inserts
|
||||
+ * entity back into its active tree (in the new, right position for
|
||||
+ * the new values of the timestamps).
|
||||
+ */
|
||||
*/
|
||||
-static void bfq_activate_entity(struct bfq_entity *entity)
|
||||
+static void __bfq_requeue_entity(struct bfq_entity *entity)
|
||||
+{
|
||||
+ struct bfq_sched_data *sd = entity->sched_data;
|
||||
@@ -7065,8 +7124,7 @@ index a5ed694..4af77f4 100644
|
||||
+ * @requeue: true if this is a requeue, which implies that bfqq is
|
||||
+ * being expired; thus ALL its ancestors stop being served and must
|
||||
+ * therefore be requeued
|
||||
*/
|
||||
-static void bfq_activate_entity(struct bfq_entity *entity)
|
||||
+ */
|
||||
+static void bfq_activate_requeue_entity(struct bfq_entity *entity,
|
||||
+ bool non_blocking_wait_rq,
|
||||
+ bool requeue)
|
||||
@@ -7186,7 +7244,7 @@ index a5ed694..4af77f4 100644
|
||||
{
|
||||
struct bfq_sched_data *sd;
|
||||
struct bfq_entity *parent;
|
||||
@@ -887,63 +1268,153 @@ static void bfq_deactivate_entity(struct bfq_entity *entity, int requeue)
|
||||
@@ -887,63 +1306,154 @@ static void bfq_deactivate_entity(struct bfq_entity *entity, int requeue)
|
||||
for_each_entity_safe(entity, parent) {
|
||||
sd = entity->sched_data;
|
||||
|
||||
@@ -7309,7 +7367,8 @@ index a5ed694..4af77f4 100644
|
||||
+ if (!bfq_update_next_in_service(sd, entity) &&
|
||||
+ !expiration)
|
||||
+ /*
|
||||
+ * next_in_service unchanged, and no
|
||||
+ * next_in_service unchanged or not causing
|
||||
+ * any change in entity->parent->sd, and no
|
||||
+ * requeueing needed for expiration: stop
|
||||
+ * here.
|
||||
+ */
|
||||
@@ -7339,13 +7398,13 @@ index a5ed694..4af77f4 100644
|
||||
- struct bfq_entity *entry;
|
||||
- struct rb_node *node = st->active.rb_node;
|
||||
+ struct bfq_entity *root_entity = bfq_root_active_entity(&st->active);
|
||||
+
|
||||
+ if (bfq_gt(root_entity->min_start, st->vtime)) {
|
||||
+ struct bfq_queue *bfqq = bfq_entity_to_bfqq(root_entity);
|
||||
|
||||
- entry = rb_entry(node, struct bfq_entity, rb_node);
|
||||
- if (bfq_gt(entry->min_start, st->vtime)) {
|
||||
- st->vtime = entry->min_start;
|
||||
+ if (bfq_gt(root_entity->min_start, st->vtime)) {
|
||||
+ struct bfq_queue *bfqq = bfq_entity_to_bfqq(root_entity);
|
||||
+
|
||||
+ if (bfqq)
|
||||
+ bfq_log_bfqq(bfqq->bfqd, bfqq,
|
||||
+ "calc_vtime_jump: new value %llu",
|
||||
@@ -7373,7 +7432,7 @@ index a5ed694..4af77f4 100644
|
||||
bfq_forget_idle(st);
|
||||
}
|
||||
}
|
||||
@@ -952,6 +1423,7 @@ static void bfq_update_vtime(struct bfq_service_tree *st)
|
||||
@@ -952,6 +1462,7 @@ static void bfq_update_vtime(struct bfq_service_tree *st)
|
||||
* bfq_first_active_entity - find the eligible entity with
|
||||
* the smallest finish time
|
||||
* @st: the service tree to select from.
|
||||
@@ -7381,7 +7440,7 @@ index a5ed694..4af77f4 100644
|
||||
*
|
||||
* This function searches the first schedulable entity, starting from the
|
||||
* root of the tree and going on the left every time on this side there is
|
||||
@@ -959,7 +1431,8 @@ static void bfq_update_vtime(struct bfq_service_tree *st)
|
||||
@@ -959,7 +1470,8 @@ static void bfq_update_vtime(struct bfq_service_tree *st)
|
||||
* the right is followed only if a) the left subtree contains no eligible
|
||||
* entities and b) no eligible entity has been found yet.
|
||||
*/
|
||||
@@ -7391,7 +7450,7 @@ index a5ed694..4af77f4 100644
|
||||
{
|
||||
struct bfq_entity *entry, *first = NULL;
|
||||
struct rb_node *node = st->active.rb_node;
|
||||
@@ -967,15 +1440,15 @@ static struct bfq_entity *bfq_first_active_entity(struct bfq_service_tree *st)
|
||||
@@ -967,15 +1479,15 @@ static struct bfq_entity *bfq_first_active_entity(struct bfq_service_tree *st)
|
||||
while (node) {
|
||||
entry = rb_entry(node, struct bfq_entity, rb_node);
|
||||
left:
|
||||
@@ -7410,7 +7469,7 @@ index a5ed694..4af77f4 100644
|
||||
node = node->rb_left;
|
||||
goto left;
|
||||
}
|
||||
@@ -993,31 +1466,84 @@ static struct bfq_entity *bfq_first_active_entity(struct bfq_service_tree *st)
|
||||
@@ -993,31 +1505,84 @@ static struct bfq_entity *bfq_first_active_entity(struct bfq_service_tree *st)
|
||||
* __bfq_lookup_next_entity - return the first eligible entity in @st.
|
||||
* @st: the service tree.
|
||||
*
|
||||
@@ -7510,7 +7569,7 @@ index a5ed694..4af77f4 100644
|
||||
|
||||
return entity;
|
||||
}
|
||||
@@ -1025,50 +1551,118 @@ static struct bfq_entity *__bfq_lookup_next_entity(struct bfq_service_tree *st,
|
||||
@@ -1025,50 +1590,81 @@ static struct bfq_entity *__bfq_lookup_next_entity(struct bfq_service_tree *st,
|
||||
/**
|
||||
* bfq_lookup_next_entity - return the first eligible entity in @sd.
|
||||
* @sd: the sched_data.
|
||||
@@ -7620,48 +7679,11 @@ index a5ed694..4af77f4 100644
|
||||
+
|
||||
+ return sd->next_in_service != sd->in_service_entity;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * This function tells whether entity stops being a candidate for next
|
||||
+ * service, according to the following logic.
|
||||
+ *
|
||||
+ * This function is invoked for an entity that is about to be set in
|
||||
+ * service. If such an entity is a queue, then the entity is no longer
|
||||
+ * a candidate for next service (i.e, a candidate entity to serve
|
||||
+ * after the in-service entity is expired). The function then returns
|
||||
+ * true.
|
||||
+ *
|
||||
+ * In contrast, the entity could stil be a candidate for next service
|
||||
+ * if it is not a queue, and has more than one child. In fact, even if
|
||||
+ * one of its children is about to be set in service, other children
|
||||
+ * may still be the next to serve. As a consequence, a non-queue
|
||||
+ * entity is not a candidate for next-service only if it has only one
|
||||
+ * child. And only if this condition holds, then the function returns
|
||||
+ * true for a non-queue entity.
|
||||
+ */
|
||||
+static bool bfq_no_longer_next_in_service(struct bfq_entity *entity)
|
||||
+{
|
||||
+ struct bfq_group *bfqg;
|
||||
+
|
||||
+ if (bfq_entity_to_bfqq(entity))
|
||||
+ return true;
|
||||
+
|
||||
+#ifdef CONFIG_BFQ_GROUP_IOSCHED
|
||||
+ bfqg = container_of(entity, struct bfq_group, entity);
|
||||
+
|
||||
+ BUG_ON(bfqg == ((struct bfq_data *)(bfqg->bfqd))->root_group);
|
||||
+ BUG_ON(bfqg->active_entities == 0);
|
||||
+ if (bfqg->active_entities == 1)
|
||||
+ return true;
|
||||
+#endif
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Get next queue for service.
|
||||
*/
|
||||
@@ -1083,58 +1677,208 @@ static struct bfq_queue *bfq_get_next_queue(struct bfq_data *bfqd)
|
||||
@@ -1083,58 +1679,208 @@ static struct bfq_queue *bfq_get_next_queue(struct bfq_data *bfqd)
|
||||
if (bfqd->busy_queues == 0)
|
||||
return NULL;
|
||||
|
||||
@@ -7883,7 +7905,7 @@ index a5ed694..4af77f4 100644
|
||||
{
|
||||
BUG_ON(!bfq_bfqq_busy(bfqq));
|
||||
BUG_ON(!RB_EMPTY_ROOT(&bfqq->sort_list));
|
||||
@@ -1146,27 +1890,20 @@ static void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq,
|
||||
@@ -1146,27 +1892,20 @@ static void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq,
|
||||
BUG_ON(bfqd->busy_queues == 0);
|
||||
bfqd->busy_queues--;
|
||||
|
||||
@@ -7918,7 +7940,7 @@ index a5ed694..4af77f4 100644
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1184,16 +1921,11 @@ static void bfq_add_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq)
|
||||
@@ -1184,16 +1923,11 @@ static void bfq_add_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq)
|
||||
bfq_mark_bfqq_busy(bfqq);
|
||||
bfqd->busy_queues++;
|
||||
|
||||
@@ -7938,13 +7960,13 @@ index a5ed694..4af77f4 100644
|
||||
bfqd->wr_busy_queues++;
|
||||
}
|
||||
diff --git a/block/bfq.h b/block/bfq.h
|
||||
index fcce855..57ab51d 100644
|
||||
index fcce855..bef8244 100644
|
||||
--- a/block/bfq.h
|
||||
+++ b/block/bfq.h
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
- * BFQ-v7r11 for 4.5.0: data structures and common functions prototypes.
|
||||
+ * BFQ v8r6 for 4.9.0: data structures and common functions prototypes.
|
||||
+ * BFQ v8r7 for 4.9.0: data structures and common functions prototypes.
|
||||
*
|
||||
* Based on ideas and code from CFQ:
|
||||
* Copyright (C) 2003 Jens Axboe <axboe@kernel.dk>
|
||||
@@ -0,0 +1,729 @@
|
||||
block/bfq-cgroup.c | 12 +--
|
||||
block/bfq-iosched.c | 211 +++++++++++++++++++++++++++++++---------------------
|
||||
block/bfq-sched.c | 73 ++++++++++++------
|
||||
block/bfq.h | 4 +-
|
||||
4 files changed, 180 insertions(+), 120 deletions(-)
|
||||
|
||||
diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c
|
||||
index bbaecd0..a66a723 100644
|
||||
--- a/block/bfq-cgroup.c
|
||||
+++ b/block/bfq-cgroup.c
|
||||
@@ -771,7 +771,6 @@ static void bfq_pd_offline(struct blkg_policy_data *pd)
|
||||
|
||||
__bfq_deactivate_entity(entity, false);
|
||||
bfq_put_async_queues(bfqd, bfqg);
|
||||
- BUG_ON(entity->tree);
|
||||
|
||||
/*
|
||||
* @blkg is going offline and will be ignored by
|
||||
@@ -1140,6 +1139,9 @@ static inline void bfqg_stats_update_idle_time(struct bfq_group *bfqg) { }
|
||||
static inline void bfqg_stats_set_start_idle_time(struct bfq_group *bfqg) { }
|
||||
static inline void bfqg_stats_update_avg_queue_size(struct bfq_group *bfqg) { }
|
||||
|
||||
+static void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq,
|
||||
+ struct bfq_group *bfqg) {}
|
||||
+
|
||||
static void bfq_init_entity(struct bfq_entity *entity,
|
||||
struct bfq_group *bfqg)
|
||||
{
|
||||
@@ -1154,13 +1156,7 @@ static void bfq_init_entity(struct bfq_entity *entity,
|
||||
entity->sched_data = &bfqg->sched_data;
|
||||
}
|
||||
|
||||
-static struct bfq_group *
|
||||
-bfq_bic_update_cgroup(struct bfq_io_cq *bic, struct bio *bio)
|
||||
-{
|
||||
- struct bfq_data *bfqd = bic_to_bfqd(bic);
|
||||
-
|
||||
- return bfqd->root_group;
|
||||
-}
|
||||
+static void bfq_bic_update_cgroup(struct bfq_io_cq *bic, struct bio *bio) {}
|
||||
|
||||
static void bfq_end_wr_async(struct bfq_data *bfqd)
|
||||
{
|
||||
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
|
||||
index 78baa07..96b79a0 100644
|
||||
--- a/block/bfq-iosched.c
|
||||
+++ b/block/bfq-iosched.c
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* Copyright (C) 2015 Paolo Valente <paolo.valente@unimore.it>
|
||||
*
|
||||
- * Copyright (C) 2016 Paolo Valente <paolo.valente@linaro.org>
|
||||
+ * Copyright (C) 2017 Paolo Valente <paolo.valente@linaro.org>
|
||||
*
|
||||
* Licensed under the GPL-2 as detailed in the accompanying COPYING.BFQ
|
||||
* file.
|
||||
@@ -107,7 +107,7 @@ static const int bfq_async_charge_factor = 10;
|
||||
/* Default timeout values, in jiffies, approximating CFQ defaults. */
|
||||
static const int bfq_timeout = (HZ / 8);
|
||||
|
||||
-struct kmem_cache *bfq_pool;
|
||||
+static struct kmem_cache *bfq_pool;
|
||||
|
||||
/* Below this threshold (in ns), we consider thinktime immediate. */
|
||||
#define BFQ_MIN_TT (2 * NSEC_PER_MSEC)
|
||||
@@ -483,6 +483,22 @@ static void bfq_weights_tree_add(struct bfq_data *bfqd,
|
||||
|
||||
entity->weight_counter = kzalloc(sizeof(struct bfq_weight_counter),
|
||||
GFP_ATOMIC);
|
||||
+
|
||||
+ /*
|
||||
+ * In the unlucky event of an allocation failure, we just
|
||||
+ * exit. This will cause the weight of entity to not be
|
||||
+ * considered in bfq_differentiated_weights, which, in its
|
||||
+ * turn, causes the scenario to be deemed wrongly symmetric in
|
||||
+ * case entity's weight would have been the only weight making
|
||||
+ * the scenario asymmetric. On the bright side, no unbalance
|
||||
+ * will however occur when entity becomes inactive again (the
|
||||
+ * invocation of this function is triggered by an activation
|
||||
+ * of entity). In fact, bfq_weights_tree_remove does nothing
|
||||
+ * if !entity->weight_counter.
|
||||
+ */
|
||||
+ if (unlikely(!entity->weight_counter))
|
||||
+ return;
|
||||
+
|
||||
entity->weight_counter->weight = entity->weight;
|
||||
rb_link_node(&entity->weight_counter->weights_node, parent, new);
|
||||
rb_insert_color(&entity->weight_counter->weights_node, root);
|
||||
@@ -519,13 +535,45 @@ static void bfq_weights_tree_remove(struct bfq_data *bfqd,
|
||||
entity->weight_counter = NULL;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Return expired entry, or NULL to just start from scratch in rbtree.
|
||||
+ */
|
||||
+static struct request *bfq_check_fifo(struct bfq_queue *bfqq,
|
||||
+ struct request *last)
|
||||
+{
|
||||
+ struct request *rq;
|
||||
+
|
||||
+ if (bfq_bfqq_fifo_expire(bfqq))
|
||||
+ return NULL;
|
||||
+
|
||||
+ bfq_mark_bfqq_fifo_expire(bfqq);
|
||||
+
|
||||
+ rq = rq_entry_fifo(bfqq->fifo.next);
|
||||
+
|
||||
+ if (rq == last || ktime_get_ns() < rq->fifo_time)
|
||||
+ return NULL;
|
||||
+
|
||||
+ bfq_log_bfqq(bfqq->bfqd, bfqq, "check_fifo: returned %p", rq);
|
||||
+ BUG_ON(RB_EMPTY_NODE(&rq->rb_node));
|
||||
+ return rq;
|
||||
+}
|
||||
+
|
||||
static struct request *bfq_find_next_rq(struct bfq_data *bfqd,
|
||||
struct bfq_queue *bfqq,
|
||||
struct request *last)
|
||||
{
|
||||
struct rb_node *rbnext = rb_next(&last->rb_node);
|
||||
struct rb_node *rbprev = rb_prev(&last->rb_node);
|
||||
- struct request *next = NULL, *prev = NULL;
|
||||
+ struct request *next, *prev = NULL;
|
||||
+
|
||||
+ BUG_ON(list_empty(&bfqq->fifo));
|
||||
+
|
||||
+ /* Follow expired path, else get first next available. */
|
||||
+ next = bfq_check_fifo(bfqq, last);
|
||||
+ if (next) {
|
||||
+ BUG_ON(next == last);
|
||||
+ return next;
|
||||
+ }
|
||||
|
||||
BUG_ON(RB_EMPTY_NODE(&last->rb_node));
|
||||
|
||||
@@ -1359,7 +1407,6 @@ static void bfq_bfqq_handle_idle_busy_switch(struct bfq_data *bfqd,
|
||||
|
||||
bfq_bfqq_expire(bfqd, bfqd->in_service_queue,
|
||||
false, BFQ_BFQQ_PREEMPTED);
|
||||
- BUG_ON(in_serv->entity.budget < 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1523,12 +1570,15 @@ static void bfq_remove_request(struct request *rq)
|
||||
elv_rb_del(&bfqq->sort_list, rq);
|
||||
|
||||
if (RB_EMPTY_ROOT(&bfqq->sort_list)) {
|
||||
+ bfqq->next_rq = NULL;
|
||||
+
|
||||
BUG_ON(bfqq->entity.budget < 0);
|
||||
|
||||
if (bfq_bfqq_busy(bfqq) && bfqq != bfqd->in_service_queue) {
|
||||
+ BUG_ON(bfqq->ref < 2); /* referred by rq and on tree */
|
||||
bfq_del_bfqq_busy(bfqd, bfqq, false);
|
||||
-
|
||||
- /* bfqq emptied. In normal operation, when
|
||||
+ /*
|
||||
+ * bfqq emptied. In normal operation, when
|
||||
* bfqq is empty, bfqq->entity.service and
|
||||
* bfqq->entity.budget must contain,
|
||||
* respectively, the service received and the
|
||||
@@ -1537,7 +1587,8 @@ static void bfq_remove_request(struct request *rq)
|
||||
* this last removal occurred while bfqq is
|
||||
* not in service. To avoid inconsistencies,
|
||||
* reset both bfqq->entity.service and
|
||||
- * bfqq->entity.budget.
|
||||
+ * bfqq->entity.budget, if bfqq has still a
|
||||
+ * process that may issue I/O requests to it.
|
||||
*/
|
||||
bfqq->entity.budget = bfqq->entity.service = 0;
|
||||
}
|
||||
@@ -1868,7 +1919,7 @@ static bool bfq_may_be_close_cooperator(struct bfq_queue *bfqq,
|
||||
* positives. In case bfqq is weight-raised, such false positives
|
||||
* would evidently degrade latency guarantees for bfqq.
|
||||
*/
|
||||
-bool wr_from_too_long(struct bfq_queue *bfqq)
|
||||
+static bool wr_from_too_long(struct bfq_queue *bfqq)
|
||||
{
|
||||
return bfqq->wr_coeff > 1 &&
|
||||
time_is_before_jiffies(bfqq->last_wr_start_finish +
|
||||
@@ -2029,7 +2080,8 @@ bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic,
|
||||
new_bfqq->wr_coeff = bfqq->wr_coeff;
|
||||
new_bfqq->wr_cur_max_time = bfqq->wr_cur_max_time;
|
||||
new_bfqq->last_wr_start_finish = bfqq->last_wr_start_finish;
|
||||
- new_bfqq->wr_start_at_switch_to_srt = bfqq->wr_start_at_switch_to_srt;
|
||||
+ new_bfqq->wr_start_at_switch_to_srt =
|
||||
+ bfqq->wr_start_at_switch_to_srt;
|
||||
if (bfq_bfqq_busy(new_bfqq))
|
||||
bfqd->wr_busy_queues++;
|
||||
new_bfqq->entity.prio_changed = 1;
|
||||
@@ -2072,6 +2124,7 @@ bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic,
|
||||
*/
|
||||
new_bfqq->bic = NULL;
|
||||
bfqq->bic = NULL;
|
||||
+ /* release process reference to bfqq */
|
||||
bfq_put_queue(bfqq);
|
||||
}
|
||||
|
||||
@@ -2298,7 +2351,7 @@ static unsigned long bfq_calc_max_budget(struct bfq_data *bfqd)
|
||||
* function of the estimated peak rate. See comments on
|
||||
* bfq_calc_max_budget(), and on T_slow and T_fast arrays.
|
||||
*/
|
||||
-void update_thr_responsiveness_params(struct bfq_data *bfqd)
|
||||
+static void update_thr_responsiveness_params(struct bfq_data *bfqd)
|
||||
{
|
||||
int dev_type = blk_queue_nonrot(bfqd->queue);
|
||||
|
||||
@@ -2333,7 +2386,7 @@ void update_thr_responsiveness_params(struct bfq_data *bfqd)
|
||||
BFQ_RATE_SHIFT);
|
||||
}
|
||||
|
||||
-void bfq_reset_rate_computation(struct bfq_data *bfqd, struct request *rq)
|
||||
+static void bfq_reset_rate_computation(struct bfq_data *bfqd, struct request *rq)
|
||||
{
|
||||
if (rq != NULL) { /* new rq dispatch now, reset accordingly */
|
||||
bfqd->last_dispatch = bfqd->first_dispatch = ktime_get_ns() ;
|
||||
@@ -2350,7 +2403,7 @@ void bfq_reset_rate_computation(struct bfq_data *bfqd, struct request *rq)
|
||||
bfqd->tot_sectors_dispatched);
|
||||
}
|
||||
|
||||
-void bfq_update_rate_reset(struct bfq_data *bfqd, struct request *rq)
|
||||
+static void bfq_update_rate_reset(struct bfq_data *bfqd, struct request *rq)
|
||||
{
|
||||
u32 rate, weight, divisor;
|
||||
|
||||
@@ -2400,7 +2453,7 @@ void bfq_update_rate_reset(struct bfq_data *bfqd, struct request *rq)
|
||||
* total, and rate is below the current estimated peak rate
|
||||
* - rate is unreasonably high (> 20M sectors/sec)
|
||||
*/
|
||||
- if ((bfqd->peak_rate_samples > (3 * bfqd->sequential_samples)>>2 &&
|
||||
+ if ((bfqd->sequential_samples < (3 * bfqd->peak_rate_samples)>>2 &&
|
||||
rate <= bfqd->peak_rate) ||
|
||||
rate > 20<<BFQ_RATE_SHIFT) {
|
||||
bfq_log(bfqd,
|
||||
@@ -2515,7 +2568,7 @@ void bfq_update_rate_reset(struct bfq_data *bfqd, struct request *rq)
|
||||
* of the observed dispatch rate. The function assumes to be invoked
|
||||
* on every request dispatch.
|
||||
*/
|
||||
-void bfq_update_peak_rate(struct bfq_data *bfqd, struct request *rq)
|
||||
+static void bfq_update_peak_rate(struct bfq_data *bfqd, struct request *rq)
|
||||
{
|
||||
u64 now_ns = ktime_get_ns();
|
||||
|
||||
@@ -2616,29 +2669,6 @@ static void bfq_dispatch_insert(struct request_queue *q, struct request *rq)
|
||||
elv_dispatch_sort(q, rq);
|
||||
}
|
||||
|
||||
-/*
|
||||
- * Return expired entry, or NULL to just start from scratch in rbtree.
|
||||
- */
|
||||
-static struct request *bfq_check_fifo(struct bfq_queue *bfqq)
|
||||
-{
|
||||
- struct request *rq = NULL;
|
||||
-
|
||||
- if (bfq_bfqq_fifo_expire(bfqq))
|
||||
- return NULL;
|
||||
-
|
||||
- bfq_mark_bfqq_fifo_expire(bfqq);
|
||||
-
|
||||
- if (list_empty(&bfqq->fifo))
|
||||
- return NULL;
|
||||
-
|
||||
- rq = rq_entry_fifo(bfqq->fifo.next);
|
||||
-
|
||||
- if (ktime_get_ns() < rq->fifo_time)
|
||||
- return NULL;
|
||||
-
|
||||
- return rq;
|
||||
-}
|
||||
-
|
||||
static void __bfq_bfqq_expire(struct bfq_data *bfqd, struct bfq_queue *bfqq)
|
||||
{
|
||||
BUG_ON(bfqq != bfqd->in_service_queue);
|
||||
@@ -2904,8 +2934,8 @@ static bool bfq_bfqq_is_slow(struct bfq_data *bfqd, struct bfq_queue *bfqq,
|
||||
delta_ktime = ktime_sub(delta_ktime, bfqd->last_budget_start);
|
||||
delta_usecs = ktime_to_us(delta_ktime);
|
||||
|
||||
- /* don't trust short/unrealistic values. */
|
||||
- if (delta_usecs < 1000 || delta_usecs >= LONG_MAX) {
|
||||
+ /* don't use too short time intervals */
|
||||
+ if (delta_usecs < 1000) {
|
||||
if (blk_queue_nonrot(bfqd->queue))
|
||||
/*
|
||||
* give same worst-case guarantees as idling
|
||||
@@ -2915,7 +2945,7 @@ static bool bfq_bfqq_is_slow(struct bfq_data *bfqd, struct bfq_queue *bfqq,
|
||||
else /* charge at least one seek */
|
||||
*delta_ms = bfq_slice_idle / NSEC_PER_MSEC;
|
||||
|
||||
- bfq_log(bfqd, "bfq_bfqq_is_slow: unrealistic %u", delta_usecs);
|
||||
+ bfq_log(bfqd, "bfq_bfqq_is_slow: too short %u", delta_usecs);
|
||||
|
||||
return slow;
|
||||
}
|
||||
@@ -3067,6 +3097,7 @@ static void bfq_bfqq_expire(struct bfq_data *bfqd,
|
||||
bool slow;
|
||||
unsigned long delta = 0;
|
||||
struct bfq_entity *entity = &bfqq->entity;
|
||||
+ int ref;
|
||||
|
||||
BUG_ON(bfqq != bfqd->in_service_queue);
|
||||
|
||||
@@ -3174,12 +3205,15 @@ static void bfq_bfqq_expire(struct bfq_data *bfqd,
|
||||
__bfq_bfqq_recalc_budget(bfqd, bfqq, reason);
|
||||
BUG_ON(bfqq->next_rq == NULL &&
|
||||
bfqq->entity.budget < bfqq->entity.service);
|
||||
+ ref = bfqq->ref;
|
||||
__bfq_bfqq_expire(bfqd, bfqq);
|
||||
|
||||
- BUG_ON(!bfq_bfqq_busy(bfqq) && reason == BFQ_BFQQ_BUDGET_EXHAUSTED &&
|
||||
+ BUG_ON(ref > 1 &&
|
||||
+ !bfq_bfqq_busy(bfqq) && reason == BFQ_BFQQ_BUDGET_EXHAUSTED &&
|
||||
!bfq_class_idle(bfqq));
|
||||
|
||||
- if (!bfq_bfqq_busy(bfqq) &&
|
||||
+ /* mark bfqq as waiting a request only if a bic still points to it */
|
||||
+ if (ref > 1 && !bfq_bfqq_busy(bfqq) &&
|
||||
reason != BFQ_BFQQ_BUDGET_TIMEOUT &&
|
||||
reason != BFQ_BFQQ_BUDGET_EXHAUSTED)
|
||||
bfq_mark_bfqq_non_blocking_wait_rq(bfqq);
|
||||
@@ -3504,14 +3538,29 @@ static struct bfq_queue *bfq_select_queue(struct bfq_data *bfqd)
|
||||
!bfq_bfqq_must_idle(bfqq))
|
||||
goto expire;
|
||||
|
||||
+check_queue:
|
||||
+ /*
|
||||
+ * This loop is rarely executed more than once. Even when it
|
||||
+ * happens, it is much more convenient to re-execute this loop
|
||||
+ * than to return NULL and trigger a new dispatch to get a
|
||||
+ * request served.
|
||||
+ */
|
||||
next_rq = bfqq->next_rq;
|
||||
/*
|
||||
* If bfqq has requests queued and it has enough budget left to
|
||||
* serve them, keep the queue, otherwise expire it.
|
||||
*/
|
||||
if (next_rq) {
|
||||
+ BUG_ON(RB_EMPTY_ROOT(&bfqq->sort_list));
|
||||
+
|
||||
if (bfq_serv_to_charge(next_rq, bfqq) >
|
||||
bfq_bfqq_budget_left(bfqq)) {
|
||||
+ /*
|
||||
+ * Expire the queue for budget exhaustion,
|
||||
+ * which makes sure that the next budget is
|
||||
+ * enough to serve the next request, even if
|
||||
+ * it comes from the fifo expired path.
|
||||
+ */
|
||||
reason = BFQ_BFQQ_BUDGET_EXHAUSTED;
|
||||
goto expire;
|
||||
} else {
|
||||
@@ -3559,9 +3608,16 @@ static struct bfq_queue *bfq_select_queue(struct bfq_data *bfqd)
|
||||
bfq_bfqq_expire(bfqd, bfqq, false, reason);
|
||||
new_queue:
|
||||
bfqq = bfq_set_in_service_queue(bfqd);
|
||||
- bfq_log(bfqd, "select_queue: new queue %d returned",
|
||||
- bfqq ? bfqq->pid : 0);
|
||||
+ if (bfqq) {
|
||||
+ bfq_log_bfqq(bfqd, bfqq, "select_queue: checking new queue");
|
||||
+ goto check_queue;
|
||||
+ }
|
||||
keep_queue:
|
||||
+ if (bfqq)
|
||||
+ bfq_log_bfqq(bfqd, bfqq, "select_queue: returned this queue");
|
||||
+ else
|
||||
+ bfq_log(bfqd, "select_queue: no queue returned");
|
||||
+
|
||||
return bfqq;
|
||||
}
|
||||
|
||||
@@ -3627,45 +3683,17 @@ static int bfq_dispatch_request(struct bfq_data *bfqd,
|
||||
struct bfq_queue *bfqq)
|
||||
{
|
||||
int dispatched = 0;
|
||||
- struct request *rq;
|
||||
+ struct request *rq = bfqq->next_rq;
|
||||
unsigned long service_to_charge;
|
||||
|
||||
BUG_ON(RB_EMPTY_ROOT(&bfqq->sort_list));
|
||||
-
|
||||
- /* Follow expired path, else get first next available. */
|
||||
- rq = bfq_check_fifo(bfqq);
|
||||
- if (!rq)
|
||||
- rq = bfqq->next_rq;
|
||||
+ BUG_ON(!rq);
|
||||
service_to_charge = bfq_serv_to_charge(rq, bfqq);
|
||||
|
||||
- if (service_to_charge > bfq_bfqq_budget_left(bfqq)) {
|
||||
- /*
|
||||
- * This may happen if the next rq is chosen in fifo order
|
||||
- * instead of sector order. The budget is properly
|
||||
- * dimensioned to be always sufficient to serve the next
|
||||
- * request only if it is chosen in sector order. The reason
|
||||
- * is that it would be quite inefficient and little useful
|
||||
- * to always make sure that the budget is large enough to
|
||||
- * serve even the possible next rq in fifo order.
|
||||
- * In fact, requests are seldom served in fifo order.
|
||||
- *
|
||||
- * Expire the queue for budget exhaustion, and make sure
|
||||
- * that the next act_budget is enough to serve the next
|
||||
- * request, even if it comes from the fifo expired path.
|
||||
- */
|
||||
- bfqq->next_rq = rq;
|
||||
- /*
|
||||
- * Since this dispatch is failed, make sure that
|
||||
- * a new one will be performed
|
||||
- */
|
||||
- if (!bfqd->rq_in_driver)
|
||||
- bfq_schedule_dispatch(bfqd);
|
||||
- BUG_ON(bfqq->entity.budget < bfqq->entity.service);
|
||||
- goto expire;
|
||||
- }
|
||||
+ BUG_ON(service_to_charge > bfq_bfqq_budget_left(bfqq));
|
||||
|
||||
BUG_ON(bfqq->entity.budget < bfqq->entity.service);
|
||||
- /* Finally, insert request into driver dispatch list. */
|
||||
+
|
||||
bfq_bfqq_served(bfqq, service_to_charge);
|
||||
|
||||
BUG_ON(bfqq->entity.budget < bfqq->entity.service);
|
||||
@@ -3805,7 +3833,8 @@ static int bfq_dispatch_requests(struct request_queue *q, int force)
|
||||
* Task holds one reference to the queue, dropped when task exits. Each rq
|
||||
* in-flight on this queue also holds a reference, dropped when rq is freed.
|
||||
*
|
||||
- * Queue lock must be held here.
|
||||
+ * Queue lock must be held here. Recall not to use bfqq after calling
|
||||
+ * this function on it.
|
||||
*/
|
||||
static void bfq_put_queue(struct bfq_queue *bfqq)
|
||||
{
|
||||
@@ -3874,7 +3903,7 @@ static void bfq_exit_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq)
|
||||
|
||||
bfq_put_cooperator(bfqq);
|
||||
|
||||
- bfq_put_queue(bfqq);
|
||||
+ bfq_put_queue(bfqq); /* release process reference */
|
||||
}
|
||||
|
||||
static void bfq_init_icq(struct io_cq *icq)
|
||||
@@ -3973,6 +4002,7 @@ static void bfq_check_ioprio_change(struct bfq_io_cq *bic, struct bio *bio)
|
||||
|
||||
bfqq = bic_to_bfqq(bic, false);
|
||||
if (bfqq) {
|
||||
+ /* release process reference on this queue */
|
||||
bfq_put_queue(bfqq);
|
||||
bfqq = bfq_get_queue(bfqd, bio, BLK_RW_ASYNC, bic);
|
||||
bic_set_bfqq(bic, bfqq, false);
|
||||
@@ -4093,14 +4123,20 @@ static struct bfq_queue *bfq_get_queue(struct bfq_data *bfqd,
|
||||
* prune it.
|
||||
*/
|
||||
if (async_bfqq) {
|
||||
- bfqq->ref++;
|
||||
+ bfqq->ref++; /*
|
||||
+ * Extra group reference, w.r.t. sync
|
||||
+ * queue. This extra reference is removed
|
||||
+ * only if bfqq->bfqg disappears, to
|
||||
+ * guarantee that this queue is not freed
|
||||
+ * until its group goes away.
|
||||
+ */
|
||||
bfq_log_bfqq(bfqd, bfqq, "get_queue, bfqq not in async: %p, %d",
|
||||
bfqq, bfqq->ref);
|
||||
*async_bfqq = bfqq;
|
||||
}
|
||||
|
||||
out:
|
||||
- bfqq->ref++;
|
||||
+ bfqq->ref++; /* get a process reference to this queue */
|
||||
bfq_log_bfqq(bfqd, bfqq, "get_queue, at end: %p, %d", bfqq, bfqq->ref);
|
||||
rcu_read_unlock();
|
||||
return bfqq;
|
||||
@@ -4274,10 +4310,14 @@ static void bfq_insert_request(struct request_queue *q, struct request *rq)
|
||||
bfqq->allocated[rq_data_dir(rq)]--;
|
||||
new_bfqq->ref++;
|
||||
bfq_clear_bfqq_just_created(bfqq);
|
||||
- bfq_put_queue(bfqq);
|
||||
if (bic_to_bfqq(RQ_BIC(rq), 1) == bfqq)
|
||||
bfq_merge_bfqqs(bfqd, RQ_BIC(rq),
|
||||
bfqq, new_bfqq);
|
||||
+ /*
|
||||
+ * rq is about to be enqueued into new_bfqq,
|
||||
+ * release rq reference on bfqq
|
||||
+ */
|
||||
+ bfq_put_queue(bfqq);
|
||||
rq->elv.priv[1] = new_bfqq;
|
||||
bfqq = new_bfqq;
|
||||
}
|
||||
@@ -4697,9 +4737,8 @@ static void bfq_shutdown_timer_wq(struct bfq_data *bfqd)
|
||||
cancel_work_sync(&bfqd->unplug_work);
|
||||
}
|
||||
|
||||
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
|
||||
static void __bfq_put_async_bfqq(struct bfq_data *bfqd,
|
||||
- struct bfq_queue **bfqq_ptr)
|
||||
+ struct bfq_queue **bfqq_ptr)
|
||||
{
|
||||
struct bfq_group *root_group = bfqd->root_group;
|
||||
struct bfq_queue *bfqq = *bfqq_ptr;
|
||||
@@ -4730,7 +4769,6 @@ static void bfq_put_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg)
|
||||
|
||||
__bfq_put_async_bfqq(bfqd, &bfqg->async_idle_bfqq);
|
||||
}
|
||||
-#endif
|
||||
|
||||
static void bfq_exit_queue(struct elevator_queue *e)
|
||||
{
|
||||
@@ -4755,6 +4793,7 @@ static void bfq_exit_queue(struct elevator_queue *e)
|
||||
#ifdef CONFIG_BFQ_GROUP_IOSCHED
|
||||
blkcg_deactivate_policy(q, &blkcg_policy_bfq);
|
||||
#else
|
||||
+ bfq_put_async_queues(bfqd, bfqd->root_group);
|
||||
kfree(bfqd->root_group);
|
||||
#endif
|
||||
|
||||
@@ -5229,7 +5268,7 @@ static struct blkcg_policy blkcg_policy_bfq = {
|
||||
static int __init bfq_init(void)
|
||||
{
|
||||
int ret;
|
||||
- char msg[60] = "BFQ I/O-scheduler: v8r7";
|
||||
+ char msg[60] = "BFQ I/O-scheduler: v8r10";
|
||||
|
||||
#ifdef CONFIG_BFQ_GROUP_IOSCHED
|
||||
ret = blkcg_policy_register(&blkcg_policy_bfq);
|
||||
@@ -5255,7 +5294,7 @@ static int __init bfq_init(void)
|
||||
* be run for a long time.
|
||||
*/
|
||||
T_slow[0] = msecs_to_jiffies(3500); /* actually 4 sec */
|
||||
- T_slow[1] = msecs_to_jiffies(1000); /* actually 1.5 sec */
|
||||
+ T_slow[1] = msecs_to_jiffies(6000); /* actually 6.5 sec */
|
||||
T_fast[0] = msecs_to_jiffies(7000); /* actually 8 sec */
|
||||
T_fast[1] = msecs_to_jiffies(2500); /* actually 3 sec */
|
||||
|
||||
diff --git a/block/bfq-sched.c b/block/bfq-sched.c
|
||||
index 797bce7..70aac56 100644
|
||||
--- a/block/bfq-sched.c
|
||||
+++ b/block/bfq-sched.c
|
||||
@@ -154,7 +154,13 @@ static bool bfq_update_next_in_service(struct bfq_sched_data *sd,
|
||||
#define for_each_entity(entity) \
|
||||
for (; entity ; entity = entity->parent)
|
||||
|
||||
-#define for_each_entity_safe(entity, parent) \
|
||||
+/*
|
||||
+ * For each iteration, compute parent in advance, so as to be safe if
|
||||
+ * entity is deallocated during the iteration. Such a deallocation may
|
||||
+ * happen as a consequence of a bfq_put_queue that frees the bfq_queue
|
||||
+ * containing entity.
|
||||
+ */
|
||||
+#define for_each_entity_safe(entity, parent) \
|
||||
for (; entity && ({ parent = entity->parent; 1; }); entity = parent)
|
||||
|
||||
/*
|
||||
@@ -691,27 +697,31 @@ static void bfq_idle_insert(struct bfq_service_tree *st,
|
||||
}
|
||||
|
||||
/**
|
||||
- * bfq_forget_entity - remove an entity from the wfq trees.
|
||||
+ * bfq_forget_entity - do not consider entity any longer for scheduling
|
||||
* @st: the service tree.
|
||||
* @entity: the entity being removed.
|
||||
+ * @is_in_service: true if entity is currently the in-service entity.
|
||||
*
|
||||
- * Update the device status and forget everything about @entity, putting
|
||||
- * the device reference to it, if it is a queue. Entities belonging to
|
||||
- * groups are not refcounted.
|
||||
+ * Forget everything about @entity. In addition, if entity represents
|
||||
+ * a queue, and the latter is not in service, then release the service
|
||||
+ * reference to the queue (the one taken through bfq_get_entity). In
|
||||
+ * fact, in this case, there is really no more service reference to
|
||||
+ * the queue, as the latter is also outside any service tree. If,
|
||||
+ * instead, the queue is in service, then __bfq_bfqd_reset_in_service
|
||||
+ * will take care of putting the reference when the queue finally
|
||||
+ * stops being served.
|
||||
*/
|
||||
static void bfq_forget_entity(struct bfq_service_tree *st,
|
||||
- struct bfq_entity *entity)
|
||||
+ struct bfq_entity *entity,
|
||||
+ bool is_in_service)
|
||||
{
|
||||
struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
|
||||
- struct bfq_sched_data *sd;
|
||||
-
|
||||
BUG_ON(!entity->on_st);
|
||||
|
||||
entity->on_st = false;
|
||||
st->wsum -= entity->weight;
|
||||
- if (bfqq) {
|
||||
- sd = entity->sched_data;
|
||||
- bfq_log_bfqq(bfqq->bfqd, bfqq, "forget_entity: %p %d",
|
||||
+ if (bfqq && !is_in_service) {
|
||||
+ bfq_log_bfqq(bfqq->bfqd, bfqq, "forget_entity (before): %p %d",
|
||||
bfqq, bfqq->ref);
|
||||
bfq_put_queue(bfqq);
|
||||
}
|
||||
@@ -726,7 +736,8 @@ static void bfq_put_idle_entity(struct bfq_service_tree *st,
|
||||
struct bfq_entity *entity)
|
||||
{
|
||||
bfq_idle_extract(st, entity);
|
||||
- bfq_forget_entity(st, entity);
|
||||
+ bfq_forget_entity(st, entity,
|
||||
+ entity == entity->sched_data->in_service_entity);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1082,6 +1093,12 @@ static void __bfq_activate_entity(struct bfq_entity *entity,
|
||||
*/
|
||||
entity->start = min_vstart;
|
||||
st->wsum += entity->weight;
|
||||
+ /*
|
||||
+ * entity is about to be inserted into a service tree,
|
||||
+ * and then set in service: get a reference to make
|
||||
+ * sure entity does not disappear until it is no
|
||||
+ * longer in service or scheduled for service.
|
||||
+ */
|
||||
bfq_get_entity(entity);
|
||||
|
||||
BUG_ON(entity->on_st && bfqq);
|
||||
@@ -1264,27 +1281,27 @@ static bool __bfq_deactivate_entity(struct bfq_entity *entity,
|
||||
{
|
||||
struct bfq_sched_data *sd = entity->sched_data;
|
||||
struct bfq_service_tree *st = bfq_entity_service_tree(entity);
|
||||
- bool was_in_service = entity == sd->in_service_entity;
|
||||
+ bool is_in_service = entity == sd->in_service_entity;
|
||||
|
||||
if (!entity->on_st) { /* entity never activated, or already inactive */
|
||||
BUG_ON(entity == entity->sched_data->in_service_entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
- BUG_ON(was_in_service && entity->tree && entity->tree != &st->active);
|
||||
+ BUG_ON(is_in_service && entity->tree && entity->tree != &st->active);
|
||||
|
||||
- if (was_in_service)
|
||||
+ if (is_in_service)
|
||||
bfq_calc_finish(entity, entity->service);
|
||||
|
||||
if (entity->tree == &st->active)
|
||||
bfq_active_extract(st, entity);
|
||||
- else if (!was_in_service && entity->tree == &st->idle)
|
||||
+ else if (!is_in_service && entity->tree == &st->idle)
|
||||
bfq_idle_extract(st, entity);
|
||||
else if (entity->tree)
|
||||
BUG();
|
||||
|
||||
if (!ins_into_idle_tree || !bfq_gt(entity->finish, st->vtime))
|
||||
- bfq_forget_entity(st, entity);
|
||||
+ bfq_forget_entity(st, entity, is_in_service);
|
||||
else
|
||||
bfq_idle_insert(st, entity);
|
||||
|
||||
@@ -1301,7 +1318,7 @@ static void bfq_deactivate_entity(struct bfq_entity *entity,
|
||||
bool expiration)
|
||||
{
|
||||
struct bfq_sched_data *sd;
|
||||
- struct bfq_entity *parent;
|
||||
+ struct bfq_entity *parent = NULL;
|
||||
|
||||
for_each_entity_safe(entity, parent) {
|
||||
sd = entity->sched_data;
|
||||
@@ -1320,8 +1337,8 @@ static void bfq_deactivate_entity(struct bfq_entity *entity,
|
||||
|
||||
if (!__bfq_deactivate_entity(entity, ins_into_idle_tree)) {
|
||||
/*
|
||||
- * Entity is not any tree any more, so, this
|
||||
- * deactivation is a no-op, and there is
|
||||
+ * entity is not in any tree any more, so
|
||||
+ * this deactivation is a no-op, and there is
|
||||
* nothing to change for upper-level entities
|
||||
* (in case of expiration, this can never
|
||||
* happen).
|
||||
@@ -1821,14 +1838,16 @@ static struct bfq_queue *bfq_get_next_queue(struct bfq_data *bfqd)
|
||||
|
||||
static void __bfq_bfqd_reset_in_service(struct bfq_data *bfqd)
|
||||
{
|
||||
- struct bfq_entity *entity = &bfqd->in_service_queue->entity;
|
||||
+ struct bfq_queue *in_serv_bfqq = bfqd->in_service_queue;
|
||||
+ struct bfq_entity *in_serv_entity = &in_serv_bfqq->entity;
|
||||
+ struct bfq_entity *entity = in_serv_entity;
|
||||
|
||||
if (bfqd->in_service_bic) {
|
||||
put_io_context(bfqd->in_service_bic->icq.ioc);
|
||||
bfqd->in_service_bic = NULL;
|
||||
}
|
||||
|
||||
- bfq_clear_bfqq_wait_request(bfqd->in_service_queue);
|
||||
+ bfq_clear_bfqq_wait_request(in_serv_bfqq);
|
||||
hrtimer_try_to_cancel(&bfqd->idle_slice_timer);
|
||||
bfqd->in_service_queue = NULL;
|
||||
|
||||
@@ -1840,6 +1859,14 @@ static void __bfq_bfqd_reset_in_service(struct bfq_data *bfqd)
|
||||
*/
|
||||
for_each_entity(entity)
|
||||
entity->sched_data->in_service_entity = NULL;
|
||||
+
|
||||
+ /*
|
||||
+ * in_serv_entity is no longer in service, so, if it is in no
|
||||
+ * service tree either, then release the service reference to
|
||||
+ * the queue it represents (taken with bfq_get_entity).
|
||||
+ */
|
||||
+ if (!in_serv_entity->on_st)
|
||||
+ bfq_put_queue(in_serv_bfqq);
|
||||
}
|
||||
|
||||
static void bfq_deactivate_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq,
|
||||
@@ -1904,8 +1931,6 @@ static void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq,
|
||||
BUG_ON(bfqq->entity.budget < 0);
|
||||
|
||||
bfq_deactivate_bfqq(bfqd, bfqq, true, expiration);
|
||||
-
|
||||
- BUG_ON(bfqq->entity.budget < 0);
|
||||
}
|
||||
|
||||
/*
|
||||
diff --git a/block/bfq.h b/block/bfq.h
|
||||
index a9da002..e3855af 100644
|
||||
--- a/block/bfq.h
|
||||
+++ b/block/bfq.h
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
- * BFQ v8r7 for 4.9.0: data structures and common functions prototypes.
|
||||
+ * BFQ v8r10 for 4.9.0: data structures and common functions prototypes.
|
||||
*
|
||||
* Based on ideas and code from CFQ:
|
||||
* Copyright (C) 2003 Jens Axboe <axboe@kernel.dk>
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* Copyright (C) 2015 Paolo Valente <paolo.valente@unimore.it>
|
||||
*
|
||||
- * Copyright (C) 2016 Paolo Valente <paolo.valente@linaro.org>
|
||||
+ * Copyright (C) 2017 Paolo Valente <paolo.valente@linaro.org>
|
||||
*/
|
||||
|
||||
#ifndef _BFQ_H
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
From: Jan Kara <jack@suse.cz>
|
||||
Subject: [PATCH] jbd2: Fix dbench4 performance regression for 'nobarrier' mounts
|
||||
Date: Fri, 28 Apr 2017 11:59:34 +0200
|
||||
|
||||
Commit b685d3d65ac7 "block: treat REQ_FUA and REQ_PREFLUSH as
|
||||
synchronous" removed REQ_SYNC flag from WRITE_FUA implementation. Since
|
||||
JBD2 strips REQ_FUA and REQ_FLUSH flags from submitted IO when the
|
||||
filesystem is mounted with nobarrier mount option, journal superblock
|
||||
writes ended up being async writes after this patch and that caused
|
||||
heavy performance regression for dbench4 benchmark with high number of
|
||||
processes. In my test setup with HP RAID array with non-volatile write
|
||||
cache and 32 GB ram, dbench4 runs with 8 processes regressed by ~25%.
|
||||
|
||||
Fix the problem by making sure journal superblock writes are always
|
||||
treated as synchronous since they generally block progress of the
|
||||
journalling machinery and thus the whole filesystem.
|
||||
|
||||
Fixes: b685d3d65ac791406e0dfd8779cc9b3707fea5a3
|
||||
CC: stable@vger.kernel.org
|
||||
Signed-off-by: Jan Kara <jack@suse.cz>
|
||||
---
|
||||
fs/jbd2/journal.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
|
||||
index 5adc2fb62b0f..e768126f6a72 100644
|
||||
--- a/fs/jbd2/journal.c
|
||||
+++ b/fs/jbd2/journal.c
|
||||
@@ -1348,7 +1348,7 @@ static int jbd2_write_superblock(journal_t *journal, int write_flags)
|
||||
jbd2_superblock_csum_set(journal, sb);
|
||||
get_bh(bh);
|
||||
bh->b_end_io = end_buffer_write_sync;
|
||||
- ret = submit_bh(REQ_OP_WRITE, write_flags, bh);
|
||||
+ ret = submit_bh(REQ_OP_WRITE, write_flags | REQ_SYNC, bh);
|
||||
wait_on_buffer(bh);
|
||||
if (buffer_write_io_error(bh)) {
|
||||
clear_buffer_write_io_error(bh);
|
||||
--
|
||||
2.12.0
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
From 633ee407b9d15a75ac9740ba9d3338815e1fcb95 Mon Sep 17 00:00:00 2001
|
||||
From: Ilya Dryomov <idryomov@gmail.com>
|
||||
Date: Tue, 21 Mar 2017 13:44:28 +0100
|
||||
Subject: libceph: force GFP_NOIO for socket allocations
|
||||
|
||||
From: Ilya Dryomov <idryomov@gmail.com>
|
||||
|
||||
commit 633ee407b9d15a75ac9740ba9d3338815e1fcb95 upstream.
|
||||
|
||||
sock_alloc_inode() allocates socket+inode and socket_wq with
|
||||
GFP_KERNEL, which is not allowed on the writeback path:
|
||||
|
||||
Workqueue: ceph-msgr con_work [libceph]
|
||||
ffff8810871cb018 0000000000000046 0000000000000000 ffff881085d40000
|
||||
0000000000012b00 ffff881025cad428 ffff8810871cbfd8 0000000000012b00
|
||||
ffff880102fc1000 ffff881085d40000 ffff8810871cb038 ffff8810871cb148
|
||||
Call Trace:
|
||||
[<ffffffff816dd629>] schedule+0x29/0x70
|
||||
[<ffffffff816e066d>] schedule_timeout+0x1bd/0x200
|
||||
[<ffffffff81093ffc>] ? ttwu_do_wakeup+0x2c/0x120
|
||||
[<ffffffff81094266>] ? ttwu_do_activate.constprop.135+0x66/0x70
|
||||
[<ffffffff816deb5f>] wait_for_completion+0xbf/0x180
|
||||
[<ffffffff81097cd0>] ? try_to_wake_up+0x390/0x390
|
||||
[<ffffffff81086335>] flush_work+0x165/0x250
|
||||
[<ffffffff81082940>] ? worker_detach_from_pool+0xd0/0xd0
|
||||
[<ffffffffa03b65b1>] xlog_cil_force_lsn+0x81/0x200 [xfs]
|
||||
[<ffffffff816d6b42>] ? __slab_free+0xee/0x234
|
||||
[<ffffffffa03b4b1d>] _xfs_log_force_lsn+0x4d/0x2c0 [xfs]
|
||||
[<ffffffff811adc1e>] ? lookup_page_cgroup_used+0xe/0x30
|
||||
[<ffffffffa039a723>] ? xfs_reclaim_inode+0xa3/0x330 [xfs]
|
||||
[<ffffffffa03b4dcf>] xfs_log_force_lsn+0x3f/0xf0 [xfs]
|
||||
[<ffffffffa039a723>] ? xfs_reclaim_inode+0xa3/0x330 [xfs]
|
||||
[<ffffffffa03a62c6>] xfs_iunpin_wait+0xc6/0x1a0 [xfs]
|
||||
[<ffffffff810aa250>] ? wake_atomic_t_function+0x40/0x40
|
||||
[<ffffffffa039a723>] xfs_reclaim_inode+0xa3/0x330 [xfs]
|
||||
[<ffffffffa039ac07>] xfs_reclaim_inodes_ag+0x257/0x3d0 [xfs]
|
||||
[<ffffffffa039bb13>] xfs_reclaim_inodes_nr+0x33/0x40 [xfs]
|
||||
[<ffffffffa03ab745>] xfs_fs_free_cached_objects+0x15/0x20 [xfs]
|
||||
[<ffffffff811c0c18>] super_cache_scan+0x178/0x180
|
||||
[<ffffffff8115912e>] shrink_slab_node+0x14e/0x340
|
||||
[<ffffffff811afc3b>] ? mem_cgroup_iter+0x16b/0x450
|
||||
[<ffffffff8115af70>] shrink_slab+0x100/0x140
|
||||
[<ffffffff8115e425>] do_try_to_free_pages+0x335/0x490
|
||||
[<ffffffff8115e7f9>] try_to_free_pages+0xb9/0x1f0
|
||||
[<ffffffff816d56e4>] ? __alloc_pages_direct_compact+0x69/0x1be
|
||||
[<ffffffff81150cba>] __alloc_pages_nodemask+0x69a/0xb40
|
||||
[<ffffffff8119743e>] alloc_pages_current+0x9e/0x110
|
||||
[<ffffffff811a0ac5>] new_slab+0x2c5/0x390
|
||||
[<ffffffff816d71c4>] __slab_alloc+0x33b/0x459
|
||||
[<ffffffff815b906d>] ? sock_alloc_inode+0x2d/0xd0
|
||||
[<ffffffff8164bda1>] ? inet_sendmsg+0x71/0xc0
|
||||
[<ffffffff815b906d>] ? sock_alloc_inode+0x2d/0xd0
|
||||
[<ffffffff811a21f2>] kmem_cache_alloc+0x1a2/0x1b0
|
||||
[<ffffffff815b906d>] sock_alloc_inode+0x2d/0xd0
|
||||
[<ffffffff811d8566>] alloc_inode+0x26/0xa0
|
||||
[<ffffffff811da04a>] new_inode_pseudo+0x1a/0x70
|
||||
[<ffffffff815b933e>] sock_alloc+0x1e/0x80
|
||||
[<ffffffff815ba855>] __sock_create+0x95/0x220
|
||||
[<ffffffff815baa04>] sock_create_kern+0x24/0x30
|
||||
[<ffffffffa04794d9>] con_work+0xef9/0x2050 [libceph]
|
||||
[<ffffffffa04aa9ec>] ? rbd_img_request_submit+0x4c/0x60 [rbd]
|
||||
[<ffffffff81084c19>] process_one_work+0x159/0x4f0
|
||||
[<ffffffff8108561b>] worker_thread+0x11b/0x530
|
||||
[<ffffffff81085500>] ? create_worker+0x1d0/0x1d0
|
||||
[<ffffffff8108b6f9>] kthread+0xc9/0xe0
|
||||
[<ffffffff8108b630>] ? flush_kthread_worker+0x90/0x90
|
||||
[<ffffffff816e1b98>] ret_from_fork+0x58/0x90
|
||||
[<ffffffff8108b630>] ? flush_kthread_worker+0x90/0x90
|
||||
|
||||
Use memalloc_noio_{save,restore}() to temporarily force GFP_NOIO here.
|
||||
|
||||
Link: http://tracker.ceph.com/issues/19309
|
||||
Reported-by: Sergey Jerusalimov <wintchester@gmail.com>
|
||||
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
|
||||
Reviewed-by: Jeff Layton <jlayton@redhat.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
|
||||
---
|
||||
net/ceph/messenger.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
--- a/net/ceph/messenger.c
|
||||
+++ b/net/ceph/messenger.c
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/nsproxy.h>
|
||||
+#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/string.h>
|
||||
@@ -469,11 +470,16 @@ static int ceph_tcp_connect(struct ceph_
|
||||
{
|
||||
struct sockaddr_storage *paddr = &con->peer_addr.in_addr;
|
||||
struct socket *sock;
|
||||
+ unsigned int noio_flag;
|
||||
int ret;
|
||||
|
||||
BUG_ON(con->sock);
|
||||
+
|
||||
+ /* sock_create_kern() allocates with GFP_KERNEL */
|
||||
+ noio_flag = memalloc_noio_save();
|
||||
ret = sock_create_kern(read_pnet(&con->msgr->net), paddr->ss_family,
|
||||
SOCK_STREAM, IPPROTO_TCP, &sock);
|
||||
+ memalloc_noio_restore(noio_flag);
|
||||
if (ret)
|
||||
return ret;
|
||||
sock->sk->sk_allocation = GFP_NOFS;
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
From 5294b83086cc1c35b4efeca03644cf9d12282e5b Mon Sep 17 00:00:00 2001
|
||||
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
|
||||
Date: Tue, 25 Apr 2017 19:08:18 +0200
|
||||
Subject: [PATCH] macsec: dynamically allocate space for sglist
|
||||
|
||||
We call skb_cow_data, which is good anyway to ensure we can actually
|
||||
modify the skb as such (another error from prior). Now that we have the
|
||||
number of fragments required, we can safely allocate exactly that amount
|
||||
of memory.
|
||||
|
||||
Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver")
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Acked-by: Sabrina Dubroca <sd@queasysnail.net>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/macsec.c | 29 ++++++++++++++++++++++-------
|
||||
1 file changed, 22 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
|
||||
index dbab05a..49ce4e9 100644
|
||||
--- a/drivers/net/macsec.c
|
||||
+++ b/drivers/net/macsec.c
|
||||
@@ -617,7 +617,8 @@ static void macsec_encrypt_done(struct crypto_async_request *base, int err)
|
||||
|
||||
static struct aead_request *macsec_alloc_req(struct crypto_aead *tfm,
|
||||
unsigned char **iv,
|
||||
- struct scatterlist **sg)
|
||||
+ struct scatterlist **sg,
|
||||
+ int num_frags)
|
||||
{
|
||||
size_t size, iv_offset, sg_offset;
|
||||
struct aead_request *req;
|
||||
@@ -629,7 +630,7 @@ static struct aead_request *macsec_alloc_req(struct crypto_aead *tfm,
|
||||
|
||||
size = ALIGN(size, __alignof__(struct scatterlist));
|
||||
sg_offset = size;
|
||||
- size += sizeof(struct scatterlist) * (MAX_SKB_FRAGS + 1);
|
||||
+ size += sizeof(struct scatterlist) * num_frags;
|
||||
|
||||
tmp = kmalloc(size, GFP_ATOMIC);
|
||||
if (!tmp)
|
||||
@@ -649,6 +650,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
|
||||
{
|
||||
int ret;
|
||||
struct scatterlist *sg;
|
||||
+ struct sk_buff *trailer;
|
||||
unsigned char *iv;
|
||||
struct ethhdr *eth;
|
||||
struct macsec_eth_header *hh;
|
||||
@@ -723,7 +725,14 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
- req = macsec_alloc_req(tx_sa->key.tfm, &iv, &sg);
|
||||
+ ret = skb_cow_data(skb, 0, &trailer);
|
||||
+ if (unlikely(ret < 0)) {
|
||||
+ macsec_txsa_put(tx_sa);
|
||||
+ kfree_skb(skb);
|
||||
+ return ERR_PTR(ret);
|
||||
+ }
|
||||
+
|
||||
+ req = macsec_alloc_req(tx_sa->key.tfm, &iv, &sg, ret);
|
||||
if (!req) {
|
||||
macsec_txsa_put(tx_sa);
|
||||
kfree_skb(skb);
|
||||
@@ -732,7 +741,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
|
||||
|
||||
macsec_fill_iv(iv, secy->sci, pn);
|
||||
|
||||
- sg_init_table(sg, MAX_SKB_FRAGS + 1);
|
||||
+ sg_init_table(sg, ret);
|
||||
skb_to_sgvec(skb, sg, 0, skb->len);
|
||||
|
||||
if (tx_sc->encrypt) {
|
||||
@@ -917,6 +926,7 @@ static struct sk_buff *macsec_decrypt(struct sk_buff *skb,
|
||||
{
|
||||
int ret;
|
||||
struct scatterlist *sg;
|
||||
+ struct sk_buff *trailer;
|
||||
unsigned char *iv;
|
||||
struct aead_request *req;
|
||||
struct macsec_eth_header *hdr;
|
||||
@@ -927,7 +937,12 @@ static struct sk_buff *macsec_decrypt(struct sk_buff *skb,
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
- req = macsec_alloc_req(rx_sa->key.tfm, &iv, &sg);
|
||||
+ ret = skb_cow_data(skb, 0, &trailer);
|
||||
+ if (unlikely(ret < 0)) {
|
||||
+ kfree_skb(skb);
|
||||
+ return ERR_PTR(ret);
|
||||
+ }
|
||||
+ req = macsec_alloc_req(rx_sa->key.tfm, &iv, &sg, ret);
|
||||
if (!req) {
|
||||
kfree_skb(skb);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
@@ -936,7 +951,7 @@ static struct sk_buff *macsec_decrypt(struct sk_buff *skb,
|
||||
hdr = (struct macsec_eth_header *)skb->data;
|
||||
macsec_fill_iv(iv, sci, ntohl(hdr->packet_number));
|
||||
|
||||
- sg_init_table(sg, MAX_SKB_FRAGS + 1);
|
||||
+ sg_init_table(sg, ret);
|
||||
skb_to_sgvec(skb, sg, 0, skb->len);
|
||||
|
||||
if (hdr->tci_an & MACSEC_TCI_E) {
|
||||
@@ -2716,7 +2731,7 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
#define MACSEC_FEATURES \
|
||||
- (NETIF_F_SG | NETIF_F_HIGHDMA)
|
||||
+ (NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST)
|
||||
static struct lock_class_key macsec_netdev_addr_lock_key;
|
||||
|
||||
static int macsec_dev_init(struct net_device *dev)
|
||||
--
|
||||
2.10.2
|
||||
|
||||
@@ -130,7 +130,8 @@ block-Make-CFQ-default-to-IOPS-mode-on-SSDs.patch
|
||||
block-cgroups-kconfig-build-bits-for-BFQ-v7r11-4.5.0.patch
|
||||
block-introduce-the-BFQ-v7r11-I-O-sched-for-4.5.0.patch
|
||||
block-bfq-add-Early-Queue-Merge-EQM-to-BFQ-v7r11-for.patch
|
||||
block-Turn-into-BFQ-v8r6-for-4.9.0.patch
|
||||
block-Turn-into-BFQ-v8r7-for-4.9.0.patch
|
||||
block-update-bfq-from-v8r7-to-v8r10.patch
|
||||
|
||||
# new macbooks
|
||||
block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch
|
||||
@@ -159,6 +160,9 @@ fs-aufs-4.9-modular.patch
|
||||
# needed for mdadm: imsm: enable bad block support for imsm metadata
|
||||
fs-seq_file-reset-iterator-to-first-record-for-zero-off.patch
|
||||
|
||||
# performance regression fix
|
||||
fs-jbd2-Fix-dbench4-performance-regression-for-nobarrier-mounts.patch
|
||||
|
||||
###
|
||||
### FireWire
|
||||
###
|
||||
@@ -266,12 +270,12 @@ net-wireless-rtlwifi-Fix-kernel-oops-introduced-with-commit-e4965.patch
|
||||
# update rtl8xxxu for mga#20508
|
||||
net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch
|
||||
|
||||
# ceph
|
||||
net-libceph-force-gfp_noio-for-socket-allocations.patch
|
||||
|
||||
# WireGuard support
|
||||
net-wireguard.patch
|
||||
|
||||
# CVE-2017-7477
|
||||
net-macsec-dynamically-allocate-space-for-sglist.patch
|
||||
|
||||
###
|
||||
### Platform drivers
|
||||
###
|
||||
@@ -301,6 +305,12 @@ include-kbuild-export-pci_ids.patch
|
||||
sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch
|
||||
sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch
|
||||
|
||||
# add support for Gigabyte GA-AX370 Gaming 5 with dual codecs (TTL: 4.12)
|
||||
sound-ALSA-hda-A-new-flag-to-enforce-prefix-to-each-pin.patch
|
||||
sound-ALSA-hda-Allow-to-enable-disable-vmaster-build-expli.patch
|
||||
sound-ALSA-hda-Support-Gigabyte-Gaming-board-with-dual-Rea.patch
|
||||
sound-ALSA-hda-Use-a-helper-function-for-renaming-kctl-nam.patch
|
||||
|
||||
###
|
||||
### Staging
|
||||
###
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
From 9f3dadb156692e15933a4a97ef659f65151be4a1 Mon Sep 17 00:00:00 2001
|
||||
From: Takashi Iwai <tiwai@suse.de>
|
||||
Date: Mon, 10 Apr 2017 17:12:33 +0200
|
||||
Subject: [PATCH 1/4] ALSA: hda - A new flag to enforce prefix to each pin
|
||||
|
||||
This is a preliminary patch for a smooth multi-codec support, and it
|
||||
introduces a new flag, force_pin_prefix, to struct hda_codec.
|
||||
This flag is used to force to add the pin location prefix to each
|
||||
input pin. For example, when there is only one microphone pin,
|
||||
usually the auto-parser assigns the string "Mic". With this flag on,
|
||||
it'll be like "Front Mic". Also, the creation of "Master" or "PCM"
|
||||
playback volume for a single pin is suppressed, too.
|
||||
|
||||
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=195305
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
sound/pci/hda/hda_auto_parser.c | 1 +
|
||||
sound/pci/hda/hda_codec.h | 1 +
|
||||
sound/pci/hda/hda_generic.c | 2 ++
|
||||
3 files changed, 4 insertions(+)
|
||||
|
||||
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
|
||||
index a03cf68..d3ea731 100644
|
||||
--- a/sound/pci/hda/hda_auto_parser.c
|
||||
+++ b/sound/pci/hda/hda_auto_parser.c
|
||||
@@ -580,6 +580,7 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec,
|
||||
has_multiple_pins = 1;
|
||||
if (has_multiple_pins && type == AUTO_PIN_MIC)
|
||||
has_multiple_pins &= check_mic_location_need(codec, cfg, input);
|
||||
+ has_multiple_pins |= codec->force_pin_prefix;
|
||||
return hda_get_input_pin_label(codec, &cfg->inputs[input],
|
||||
cfg->inputs[input].pin,
|
||||
has_multiple_pins);
|
||||
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
|
||||
index f17f252..d6fb2d5 100644
|
||||
--- a/sound/pci/hda/hda_codec.h
|
||||
+++ b/sound/pci/hda/hda_codec.h
|
||||
@@ -256,6 +256,7 @@ struct hda_codec {
|
||||
unsigned int dump_coef:1; /* dump processing coefs in codec proc file */
|
||||
unsigned int power_save_node:1; /* advanced PM for each widget */
|
||||
unsigned int auto_runtime_pm:1; /* enable automatic codec runtime pm */
|
||||
+ unsigned int force_pin_prefix:1; /* Add location prefix */
|
||||
#ifdef CONFIG_PM
|
||||
unsigned long power_on_acct;
|
||||
unsigned long power_off_acct;
|
||||
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
|
||||
index e7c8f4f..4438328 100644
|
||||
--- a/sound/pci/hda/hda_generic.c
|
||||
+++ b/sound/pci/hda/hda_generic.c
|
||||
@@ -1125,6 +1125,7 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
|
||||
|
||||
*index = 0;
|
||||
if (cfg->line_outs == 1 && !spec->multi_ios &&
|
||||
+ !codec->force_pin_prefix &&
|
||||
!cfg->hp_outs && !cfg->speaker_outs)
|
||||
return spec->vmaster_mute.hook ? "PCM" : "Master";
|
||||
|
||||
@@ -1132,6 +1133,7 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
|
||||
* use it master (or "PCM" if a vmaster hook is present)
|
||||
*/
|
||||
if (spec->multiout.num_dacs == 1 && !spec->mixer_nid &&
|
||||
+ !codec->force_pin_prefix &&
|
||||
!spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0])
|
||||
return spec->vmaster_mute.hook ? "PCM" : "Master";
|
||||
|
||||
--
|
||||
2.10.2
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
From 7480316c265c9fcdbf73b1b8dec061b893b7e987 Mon Sep 17 00:00:00 2001
|
||||
From: Takashi Iwai <tiwai@suse.de>
|
||||
Date: Mon, 10 Apr 2017 17:37:34 +0200
|
||||
Subject: [PATCH 2/4] ALSA: hda - Allow to enable/disable vmaster build
|
||||
explicitly
|
||||
|
||||
Another preliminary patch for the dual-codec support: since the
|
||||
support of vmaster over multiple codecs is difficult, simply disable
|
||||
it by a new flag to hda_codec struct. A new user hint is added as
|
||||
well for consistency.
|
||||
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
Documentation/sound/hd-audio/notes.rst | 2 ++
|
||||
sound/pci/hda/hda_generic.c | 7 +++++--
|
||||
sound/pci/hda/hda_generic.h | 1 +
|
||||
3 files changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
#diff --git a/Documentation/sound/hd-audio/notes.rst b/Documentation/sound/hd-audio/notes.rst
|
||||
#index 9eeb9b4..f59c3cd 100644
|
||||
#--- a/Documentation/sound/hd-audio/notes.rst
|
||||
#+++ b/Documentation/sound/hd-audio/notes.rst
|
||||
#@@ -494,6 +494,8 @@ add_hp_mic (bool)
|
||||
# hp_mic_detect (bool)
|
||||
# enable/disable the hp/mic shared input for a single built-in mic
|
||||
# case; default true
|
||||
#+vmaster (bool)
|
||||
#+ enable/disable the virtual Master control; default true
|
||||
# mixer_nid (int)
|
||||
# specifies the widget NID of the analog-loopback mixer
|
||||
#
|
||||
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
|
||||
index 4438328..2842c82 100644
|
||||
--- a/sound/pci/hda/hda_generic.c
|
||||
+++ b/sound/pci/hda/hda_generic.c
|
||||
@@ -196,6 +196,9 @@ static void parse_user_hints(struct hda_codec *codec)
|
||||
val = snd_hda_get_bool_hint(codec, "hp_mic_detect");
|
||||
if (val >= 0)
|
||||
spec->suppress_hp_mic_detect = !val;
|
||||
+ val = snd_hda_get_bool_hint(codec, "vmaster");
|
||||
+ if (val >= 0)
|
||||
+ spec->suppress_vmaster = !val;
|
||||
|
||||
if (!snd_hda_get_int_hint(codec, "mixer_nid", &val))
|
||||
spec->mixer_nid = val;
|
||||
@@ -5033,7 +5036,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
|
||||
}
|
||||
|
||||
/* if we have no master control, let's create it */
|
||||
- if (!spec->no_analog &&
|
||||
+ if (!spec->no_analog && !spec->suppress_vmaster &&
|
||||
!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
|
||||
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
|
||||
spec->vmaster_tlv, slave_pfxs,
|
||||
@@ -5041,7 +5044,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
- if (!spec->no_analog &&
|
||||
+ if (!spec->no_analog && !spec->suppress_vmaster &&
|
||||
!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
|
||||
err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
|
||||
NULL, slave_pfxs,
|
||||
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
|
||||
index f66fc7e..6177231 100644
|
||||
--- a/sound/pci/hda/hda_generic.h
|
||||
+++ b/sound/pci/hda/hda_generic.h
|
||||
@@ -229,6 +229,7 @@ struct hda_gen_spec {
|
||||
unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */
|
||||
unsigned int power_down_unused:1; /* power down unused widgets */
|
||||
unsigned int dac_min_mute:1; /* minimal = mute for DACs */
|
||||
+ unsigned int suppress_vmaster:1; /* don't create vmaster kctls */
|
||||
|
||||
/* other internal flags */
|
||||
unsigned int no_analog:1; /* digital I/O only */
|
||||
--
|
||||
2.10.2
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
From 7beb3a6e9335d13872f24566b451f8371edd238f Mon Sep 17 00:00:00 2001
|
||||
From: Takashi Iwai <tiwai@suse.de>
|
||||
Date: Mon, 10 Apr 2017 18:05:52 +0200
|
||||
Subject: [PATCH 3/4] ALSA: hda - Support Gigabyte Gaming board with dual
|
||||
Realtek codecs
|
||||
|
||||
This patch adds some workarounds to make Gigabyte GA-AX370 Gaming 5
|
||||
board working without the conflicts of kctls, etc. In general, the
|
||||
dual codec configs result in the conflicts of the following stuff:
|
||||
- Master controls
|
||||
- Capture controls
|
||||
- Analog loopback controls
|
||||
In addition, the auto-mute and the auto-mic can't work well among
|
||||
multiple codecs.
|
||||
|
||||
The current "solution" is to disable all these features, and use UCM
|
||||
for a better PulseAudio management. For a dedicated UCM profile, the
|
||||
patch overrides the card longname so that the system an get a unique
|
||||
profile path.
|
||||
|
||||
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=195305
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
sound/pci/hda/patch_realtek.c | 61 +++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 61 insertions(+)
|
||||
|
||||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
|
||||
index 9371f1a..e81cf83 100644
|
||||
--- a/sound/pci/hda/patch_realtek.c
|
||||
+++ b/sound/pci/hda/patch_realtek.c
|
||||
@@ -1800,6 +1800,7 @@ enum {
|
||||
ALC882_FIXUP_NO_PRIMARY_HP,
|
||||
ALC887_FIXUP_ASUS_BASS,
|
||||
ALC887_FIXUP_BASS_CHMAP,
|
||||
+ ALC1220_FIXUP_GB_DUAL_CODECS,
|
||||
};
|
||||
|
||||
static void alc889_fixup_coef(struct hda_codec *codec,
|
||||
@@ -1962,6 +1963,61 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
|
||||
static void alc_fixup_bass_chmap(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action);
|
||||
|
||||
+/* For dual-codec configuration, we need to disable some features to avoid
|
||||
+ * conflicts of kctls and PCM streams
|
||||
+ */
|
||||
+static void alc_fixup_dual_codecs(struct hda_codec *codec,
|
||||
+ const struct hda_fixup *fix, int action)
|
||||
+{
|
||||
+ struct alc_spec *spec = codec->spec;
|
||||
+
|
||||
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
|
||||
+ return;
|
||||
+ /* disable vmaster */
|
||||
+ spec->gen.suppress_vmaster = 1;
|
||||
+ /* auto-mute and auto-mic switch don't work with multiple codecs */
|
||||
+ spec->gen.suppress_auto_mute = 1;
|
||||
+ spec->gen.suppress_auto_mic = 1;
|
||||
+ /* disable aamix as well */
|
||||
+ spec->gen.mixer_nid = 0;
|
||||
+ /* add location prefix to avoid conflicts */
|
||||
+ codec->force_pin_prefix = 1;
|
||||
+}
|
||||
+
|
||||
+static void rename_ctl(struct hda_codec *codec, const char *oldname,
|
||||
+ const char *newname)
|
||||
+{
|
||||
+ struct snd_kcontrol *kctl;
|
||||
+
|
||||
+ kctl = snd_hda_find_mixer_ctl(codec, oldname);
|
||||
+ if (kctl)
|
||||
+ strcpy(kctl->id.name, newname);
|
||||
+}
|
||||
+
|
||||
+static void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
|
||||
+ const struct hda_fixup *fix,
|
||||
+ int action)
|
||||
+{
|
||||
+ alc_fixup_dual_codecs(codec, fix, action);
|
||||
+ switch (action) {
|
||||
+ case HDA_FIXUP_ACT_PRE_PROBE:
|
||||
+ /* override card longname to provide a unique UCM profile */
|
||||
+ strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs");
|
||||
+ break;
|
||||
+ case HDA_FIXUP_ACT_BUILD:
|
||||
+ /* rename Capture controls depending on the codec */
|
||||
+ rename_ctl(codec, "Capture Volume",
|
||||
+ codec->addr == 0 ?
|
||||
+ "Rear-Panel Capture Volume" :
|
||||
+ "Front-Panel Capture Volume");
|
||||
+ rename_ctl(codec, "Capture Switch",
|
||||
+ codec->addr == 0 ?
|
||||
+ "Rear-Panel Capture Switch" :
|
||||
+ "Front-Panel Capture Switch");
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static const struct hda_fixup alc882_fixups[] = {
|
||||
[ALC882_FIXUP_ABIT_AW9D_MAX] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
@@ -2198,6 +2254,10 @@ static const struct hda_fixup alc882_fixups[] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc_fixup_bass_chmap,
|
||||
},
|
||||
+ [ALC1220_FIXUP_GB_DUAL_CODECS] = {
|
||||
+ .type = HDA_FIXUP_FUNC,
|
||||
+ .v.func = alc1220_fixup_gb_dual_codecs,
|
||||
+ },
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk alc882_fixup_tbl[] = {
|
||||
@@ -2267,6 +2327,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
|
||||
SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
|
||||
SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
|
||||
+ SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
|
||||
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
|
||||
SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
|
||||
SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
|
||||
--
|
||||
2.10.2
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
From 56798e6b3a2264b58d50b93cfd66586ede77d661 Mon Sep 17 00:00:00 2001
|
||||
From: Takashi Iwai <tiwai@suse.de>
|
||||
Date: Tue, 11 Apr 2017 08:10:52 +0200
|
||||
Subject: [PATCH 4/4] ALSA: hda - Use a helper function for renaming kctl names
|
||||
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
sound/pci/hda/patch_realtek.c | 11 ++++-------
|
||||
1 file changed, 4 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
|
||||
index e81cf83..57eeefd 100644
|
||||
--- a/sound/pci/hda/patch_realtek.c
|
||||
+++ b/sound/pci/hda/patch_realtek.c
|
||||
@@ -4724,7 +4724,6 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
|
||||
{ 0x1b, 0x21114000 }, /* dock speaker pin */
|
||||
{}
|
||||
};
|
||||
- struct snd_kcontrol *kctl;
|
||||
|
||||
switch (action) {
|
||||
case HDA_FIXUP_ACT_PRE_PROBE:
|
||||
@@ -4739,12 +4738,10 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
|
||||
/* this is a bit tricky; give more sane names for the main
|
||||
* (tablet) speaker and the dock speaker, respectively
|
||||
*/
|
||||
- kctl = snd_hda_find_mixer_ctl(codec, "Speaker Playback Switch");
|
||||
- if (kctl)
|
||||
- strcpy(kctl->id.name, "Dock Speaker Playback Switch");
|
||||
- kctl = snd_hda_find_mixer_ctl(codec, "Bass Speaker Playback Switch");
|
||||
- if (kctl)
|
||||
- strcpy(kctl->id.name, "Speaker Playback Switch");
|
||||
+ rename_ctl(codec, "Speaker Playback Switch",
|
||||
+ "Dock Speaker Playback Switch");
|
||||
+ rename_ctl(codec, "Bass Speaker Playback Switch",
|
||||
+ "Speaker Playback Switch");
|
||||
break;
|
||||
}
|
||||
}
|
||||
--
|
||||
2.10.2
|
||||
|
||||
+12
-6
@@ -28,8 +28,8 @@
|
||||
</BuildDependencies>
|
||||
<Patches>
|
||||
<!-- Linux patches -->
|
||||
<Patch level="1" compressionType="xz">patches/linux/patch-4.9.21.xz</Patch>
|
||||
<!-- Mageia Linux patches // compatible with http://svnweb.mageia.org/packages/cauldron/kernel/releases/4.9.20/1.mga6/PATCHES/patches/series-->
|
||||
<Patch level="1" compressionType="xz">patches/linux/patch-4.9.27.xz</Patch>
|
||||
<!-- Mageia Linux patches // compatible with http://svnweb.mageia.org/packages/cauldron/kernel/releases/4.9.27/1.mga6/PATCHES/patches/series-->
|
||||
<!--stable patches-->
|
||||
<!--CVE-2016-8405-->
|
||||
<!--other patches-->
|
||||
@@ -59,7 +59,8 @@
|
||||
<!--Patch level="1">patches/mageia/block-cgroups-kconfig-build-bits-for-BFQ-v7r11-4.5.0.patch</Patch>
|
||||
<Patch level="1">patches/mageia/block-introduce-the-BFQ-v7r11-I-O-sched-for-4.5.0.patch</Patch>
|
||||
<Patch level="1">patches/mageia/block-bfq-add-Early-Queue-Merge-EQM-to-BFQ-v7r11-for.patch</Patch>
|
||||
<Patch level="1">patches/mageia/block-Turn-into-BFQ-v8r6-for-4.9.0.patch</Patch>--><!--2-->
|
||||
<Patch level="1">patches/mageia/block-Turn-into-BFQ-v8r7-for-4.9.0.patch</Patch>
|
||||
<Patch level="1">patches/mageia/block-update-bfq-from-v8r7-to-v8r10.patch</Patch><2-->
|
||||
<Patch level="1">patches/mageia/block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch</Patch>
|
||||
<Patch level="1">patches/mageia/char-tpm-tpm_crb-implement-tpm-crb-idle-state.patch</Patch>
|
||||
<Patch level="1">patches/mageia/char-tmp-tpm_crb-fix-Intel-PTT-hw-bug-during-idle-state.patch</Patch>
|
||||
@@ -69,6 +70,7 @@
|
||||
<Patch level="1">patches/fs-aufs-4.9-posix_acl.patch</Patch>
|
||||
<Patch level="1">patches/mageia/fs-aufs-4.9-modular.patch</Patch>
|
||||
<Patch level="1">patches/mageia/fs-seq_file-reset-iterator-to-first-record-for-zero-off.patch</Patch>
|
||||
<Patch level="1">patches/mageia/fs-jbd2-Fix-dbench4-performance-regression-for-nobarrier-mounts.patch</Patch>
|
||||
<Patch level="1">patches/mageia/firewire-ieee1394-module-aliases.patch</Patch>
|
||||
<Patch level="1">patches/mageia/char-agp-intel-new-Q57-id.patch</Patch>
|
||||
<!--remove external mach64 support for buildfix-->
|
||||
@@ -112,14 +114,18 @@
|
||||
<Patch level="1">patches/mageia/net-wireless-rtlwifi-Use-dev_kfree_skb_irq-instead-of-kfree_skb.patch</Patch>
|
||||
<Patch level="1">patches/mageia/net-wireless-rtlwifi-Fix-kernel-oops-introduced-with-commit-e4965.patch</Patch>
|
||||
<Patch level="1">patches/mageia/net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch</Patch>
|
||||
<!--Patch level="1">patches/mageia/net-libceph-force-gfp_noio-for-socket-allocations.patch</Patch-->
|
||||
<Patch level="1">patches/mageia/net-wireguard.patch</Patch>
|
||||
<Patch level="1">patches/mageia/net-macsec-dynamically-allocate-space-for-sglist.patch</Patch>
|
||||
<Patch level="1">patches/mageia/platform-x86-add-shuttle-wmi-driver.patch</Patch>
|
||||
<Patch level="1">patches/mageia/platform-x86-shuttle-wmi-drop-devinit-exit.patch</Patch>
|
||||
<Patch level="1">patches/mageia/platform-x86-shuttle-wmi-4.2-buildfix.patch</Patch>
|
||||
<Patch level="1">patches/mageia/include-kbuild-export-pci_ids.patch</Patch>
|
||||
<Patch level="1">patches/mageia/sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch</Patch>
|
||||
<Patch level="1">patches/mageia/sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch</Patch>
|
||||
<Patch level="1">patches/mageia/sound-ALSA-hda-A-new-flag-to-enforce-prefix-to-each-pin.patch</Patch>
|
||||
<Patch level="1">patches/mageia/sound-ALSA-hda-Allow-to-enable-disable-vmaster-build-expli.patch</Patch>
|
||||
<Patch level="1">patches/mageia/sound-ALSA-hda-Support-Gigabyte-Gaming-board-with-dual-Rea.patch</Patch>
|
||||
<Patch level="1">patches/mageia/sound-ALSA-hda-Use-a-helper-function-for-renaming-kctl-nam.patch</Patch>
|
||||
<Patch level="1">patches/mageia/hid-usbhid-IBM-BladeCenterHS20-quirk.patch</Patch>
|
||||
<Patch level="1">patches/mageia/usb-storage-unusual_devs-add-id.patch</Patch>
|
||||
<Patch level="1">patches/mageia/usb-storage-unusual_devs-add-id-2.6.37-buildfix.patch</Patch>
|
||||
@@ -208,8 +214,8 @@
|
||||
|
||||
<History>
|
||||
<Update release="9">
|
||||
<Date>2017-03-30</Date>
|
||||
<Version>4.9.21</Version>
|
||||
<Date>2017-05-09</Date>
|
||||
<Version>4.9.27</Version>
|
||||
<Comment>Version Bump.</Comment>
|
||||
<Type package="kernel">security</Type>
|
||||
<Requires>
|
||||
|
||||
Reference in New Issue
Block a user