| @@ -375,14 +375,30 @@ static struct request *__blk_mq_alloc_request(struct blk_mq_alloc_data *data) · 374 unmodified lines |
| 375 | 375 | e->type->ops.limit_depth(data->cmd_flags, data); |
| 376 | 376 | } |
| 377 | 377 | |
| 378 | +retry: |
| 378 | 379 | data->ctx = blk_mq_get_ctx(q); |
| 379 | 380 | data->hctx = blk_mq_map_queue(q, data->cmd_flags, data->ctx); |
| 380 | 381 | if (!(data->flags & BLK_MQ_REQ_INTERNAL)) |
| 381 | 382 | blk_mq_tag_busy(data->hctx); |
| 382 | 383 | |
| 384 | + /* |
| 385 | + * Waiting allocations only fail because of an inactive hctx. In that |
| 386 | + * case just retry the hctx assignment and tag allocation as CPU hotplug |
| 387 | + * should have migrated us to an online CPU by now. |
| 388 | + */ |
| 383 | 389 | tag = blk_mq_get_tag(data); |
| 384 | | − if (tag == BLK_MQ_NO_TAG) |
| 385 | | − return NULL; |
| 390 | + if (tag == BLK_MQ_NO_TAG) { |
| 391 | + if (data->flags & BLK_MQ_REQ_NOWAIT) |
| 392 | + return NULL; |
| 393 | + |
| 394 | + /* |
| 395 | + * Give up the CPU and sleep for a random short time to ensure |
| 396 | + * that thread using a realtime scheduling class are migrated |
| 397 | + * off the the CPU, and thus off the hctx that is going away. |
| 398 | + */ |
| 399 | + msleep(3); |
| 400 | + goto retry; |
| 401 | + } |
| 386 | 402 | return blk_mq_rq_ctx_init(data, tag, alloc_time_ns); |
| 387 | 403 | } |
| 388 | 404 | |
| @@ -2335,6 +2351,86 @@ fail: · 1946 unmodified lines |
| 2335 | 2351 | return -ENOMEM; |
| 2336 | 2352 | } |
| 2337 | 2353 | |
| 2354 | +struct rq_iter_data { |
| 2355 | + struct blk_mq_hw_ctx *hctx; |
| 2356 | + bool has_rq; |
| 2357 | +}; |
| 2358 | + |
| 2359 | +static bool blk_mq_has_request(struct request *rq, void *data, bool reserved) |
| 2360 | +{ |
| 2361 | + struct rq_iter_data *iter_data = data; |
| 2362 | + |
| 2363 | + if (rq->mq_hctx != iter_data->hctx) |
| 2364 | + return true; |
| 2365 | + iter_data->has_rq = true; |
| 2366 | + return false; |
| 2367 | +} |
| 2368 | + |
| 2369 | +static bool blk_mq_hctx_has_requests(struct blk_mq_hw_ctx *hctx) |
| 2370 | +{ |
| 2371 | + struct blk_mq_tags *tags = hctx->sched_tags ? |
| 2372 | + hctx->sched_tags : hctx->tags; |
| 2373 | + struct rq_iter_data data = { |
| 2374 | + .hctx = hctx, |
| 2375 | + }; |
| 2376 | + |
| 2377 | + blk_mq_all_tag_iter(tags, blk_mq_has_request, &data); |
| 2378 | + return data.has_rq; |
| 2379 | +} |
| 2380 | + |
| 2381 | +static inline bool blk_mq_last_cpu_in_hctx(unsigned int cpu, |
| 2382 | + struct blk_mq_hw_ctx *hctx) |
| 2383 | +{ |
| 2384 | + if (cpumask_next_and(-1, hctx->cpumask, cpu_online_mask) != cpu) |
| 2385 | + return false; |
| 2386 | + if (cpumask_next_and(cpu, hctx->cpumask, cpu_online_mask) < nr_cpu_ids) |
| 2387 | + return false; |
| 2388 | + return true; |
| 2389 | +} |
| 2390 | + |
| 2391 | +static int blk_mq_hctx_notify_offline(unsigned int cpu, struct hlist_node *node) |
| 2392 | +{ |
| 2393 | + struct blk_mq_hw_ctx *hctx = hlist_entry_safe(node, |
| 2394 | + struct blk_mq_hw_ctx, cpuhp_online); |
| 2395 | + |
| 2396 | + if (!cpumask_test_cpu(cpu, hctx->cpumask) || |
| 2397 | + !blk_mq_last_cpu_in_hctx(cpu, hctx)) |
| 2398 | + return 0; |
| 2399 | + |
| 2400 | + /* |
| 2401 | + * Prevent new request from being allocated on the current hctx. |
| 2402 | + * |
| 2403 | + * The smp_mb__after_atomic() Pairs with the implied barrier in |
| 2404 | + * test_and_set_bit_lock in sbitmap_get(). Ensures the inactive flag is |
| 2405 | + * seen once we return from the tag allocator. |
| 2406 | + */ |
| 2407 | + set_bit(BLK_MQ_S_INACTIVE, &hctx->state); |
| 2408 | + smp_mb__after_atomic(); |
| 2409 | + |
| 2410 | + /* |
| 2411 | + * Try to grab a reference to the queue and wait for any outstanding |
| 2412 | + * requests. If we could not grab a reference the queue has been |
| 2413 | + * frozen and there are no requests. |
| 2414 | + */ |
| 2415 | + if (percpu_ref_tryget(&hctx->queue->q_usage_counter)) { |
| 2416 | + while (blk_mq_hctx_has_requests(hctx)) |
| 2417 | + msleep(5); |
| 2418 | + percpu_ref_put(&hctx->queue->q_usage_counter); |
| 2419 | + } |
| 2420 | + |
| 2421 | + return 0; |
| 2422 | +} |
| 2423 | + |
| 2424 | +static int blk_mq_hctx_notify_online(unsigned int cpu, struct hlist_node *node) |
| 2425 | +{ |
| 2426 | + struct blk_mq_hw_ctx *hctx = hlist_entry_safe(node, |
| 2427 | + struct blk_mq_hw_ctx, cpuhp_online); |
| 2428 | + |
| 2429 | + if (cpumask_test_cpu(cpu, hctx->cpumask)) |
| 2430 | + clear_bit(BLK_MQ_S_INACTIVE, &hctx->state); |
| 2431 | + return 0; |
| 2432 | +} |
| 2433 | + |
| 2338 | 2434 | /* |
| 2339 | 2435 | * 'cpu' is going away. splice any existing rq_list entries from this |
| 2340 | 2436 | * software queue to the hw queue dispatch list, and ensure that it |
| @@ -2348,6 +2444,9 @@ static int blk_mq_hctx_notify_dead(unsigned int cpu, struct hlist_node *node) · 7 unmodified lines |
| 2348 | 2444 | enum hctx_type type; |
| 2349 | 2445 | |
| 2350 | 2446 | hctx = hlist_entry_safe(node, struct blk_mq_hw_ctx, cpuhp_dead); |
| 2447 | + if (!cpumask_test_cpu(cpu, hctx->cpumask)) |
| 2448 | + return 0; |
| 2449 | + |
| 2351 | 2450 | ctx = __blk_mq_get_ctx(hctx->queue, cpu); |
| 2352 | 2451 | type = hctx->type; |
| 2353 | 2452 | |
| @@ -2371,6 +2470,9 @@ static int blk_mq_hctx_notify_dead(unsigned int cpu, struct hlist_node *node) · 17 unmodified lines |
| 2371 | 2470 | |
| 2372 | 2471 | static void blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx) |
| 2373 | 2472 | { |
| 2473 | + if (!(hctx->flags & BLK_MQ_F_STACKING)) |
| 2474 | + cpuhp_state_remove_instance_nocalls(CPUHP_AP_BLK_MQ_ONLINE, |
| 2475 | + &hctx->cpuhp_online); |
| 2374 | 2476 | cpuhp_state_remove_instance_nocalls(CPUHP_BLK_MQ_DEAD, |
| 2375 | 2477 | &hctx->cpuhp_dead); |
| 2376 | 2478 | } |
| @@ -2430,6 +2532,9 @@ static int blk_mq_init_hctx(struct request_queue *q, · 53 unmodified lines |
| 2430 | 2532 | { |
| 2431 | 2533 | hctx->queue_num = hctx_idx; |
| 2432 | 2534 | |
| 2535 | + if (!(hctx->flags & BLK_MQ_F_STACKING)) |
| 2536 | + cpuhp_state_add_instance_nocalls(CPUHP_AP_BLK_MQ_ONLINE, |
| 2537 | + &hctx->cpuhp_online); |
| 2433 | 2538 | cpuhp_state_add_instance_nocalls(CPUHP_BLK_MQ_DEAD, &hctx->cpuhp_dead); |
| 2434 | 2539 | |
| 2435 | 2540 | hctx->tags = set->tags[hctx_idx]; |
| @@ -3684,6 +3789,9 @@ static int __init blk_mq_init(void) · 1248 unmodified lines |
| 3684 | 3789 | { |
| 3685 | 3790 | cpuhp_setup_state_multi(CPUHP_BLK_MQ_DEAD, "block/mq:dead", NULL, |
| 3686 | 3791 | blk_mq_hctx_notify_dead); |
| 3792 | + cpuhp_setup_state_multi(CPUHP_AP_BLK_MQ_ONLINE, "block/mq:online", |
| 3793 | + blk_mq_hctx_notify_online, |
| 3794 | + blk_mq_hctx_notify_offline); |
| 3687 | 3795 | return 0; |
| 3688 | 3796 | } |
| 3689 | 3797 | subsys_initcall(blk_mq_init); |