]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - block/elevator.c
Merge tag 'smack-for-5.4-rc1' of git://github.com/cschaufler/smack-next
[linux.git] / block / elevator.c
index ac7c8ad580bafe65ba7d4e440214bd9f5bc54064..bba10e83478a0902dc883e7924a6f5cb66bec83b 100644 (file)
@@ -651,9 +651,47 @@ static inline bool elv_support_iosched(struct request_queue *q)
 }
 
 /*
- * For blk-mq devices supporting IO scheduling, we default to using mq-deadline,
- * if available, for single queue devices. If deadline isn't available OR
- * deadline initialization fails OR we have multiple queues, default to "none".
+ * For single queue devices, default to using mq-deadline. If we have multiple
+ * queues or mq-deadline is not available, default to "none".
+ */
+static struct elevator_type *elevator_get_default(struct request_queue *q)
+{
+       if (q->nr_hw_queues != 1)
+               return NULL;
+
+       return elevator_get(q, "mq-deadline", false);
+}
+
+/*
+ * Get the first elevator providing the features required by the request queue.
+ * Default to "none" if no matching elevator is found.
+ */
+static struct elevator_type *elevator_get_by_features(struct request_queue *q)
+{
+       struct elevator_type *e, *found = NULL;
+
+       spin_lock(&elv_list_lock);
+
+       list_for_each_entry(e, &elv_list, list) {
+               if (elv_support_features(e->elevator_features,
+                                        q->required_elevator_features)) {
+                       found = e;
+                       break;
+               }
+       }
+
+       if (found && !try_module_get(found->elevator_owner))
+               found = NULL;
+
+       spin_unlock(&elv_list_lock);
+       return found;
+}
+
+/*
+ * For a device queue that has no required features, use the default elevator
+ * settings. Otherwise, use the first elevator available matching the required
+ * features. If no suitable elevator is find or if the chosen elevator
+ * initialization fails, fall back to the "none" elevator (no elevator).
  */
 void elevator_init_mq(struct request_queue *q)
 {
@@ -663,19 +701,26 @@ void elevator_init_mq(struct request_queue *q)
        if (!elv_support_iosched(q))
                return;
 
-       if (q->nr_hw_queues != 1)
-               return;
-
        WARN_ON_ONCE(test_bit(QUEUE_FLAG_REGISTERED, &q->queue_flags));
 
        if (unlikely(q->elevator))
                return;
 
-       e = elevator_get(q, "mq-deadline", false);
+       if (!q->required_elevator_features)
+               e = elevator_get_default(q);
+       else
+               e = elevator_get_by_features(q);
        if (!e)
                return;
 
+       blk_mq_freeze_queue(q);
+       blk_mq_quiesce_queue(q);
+
        err = blk_mq_init_sched(q, e);
+
+       blk_mq_unquiesce_queue(q);
+       blk_mq_unfreeze_queue(q);
+
        if (err) {
                pr_warn("\"%s\" elevator initialization failed, "
                        "falling back to \"none\"\n", e->elevator_name);