Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drivers/hv: add CPU offlining support

Currently, it is tedious to offline CPUs in a Hyper-V VM since CPUs may
have VMBus channels attached to them that a user would have to manually
rebind elsewhere. So, as made mention of in
commit d570aec0f2154 ("Drivers: hv: vmbus: Synchronize init_vp_index()
vs. CPU hotplug"), rebind channels associated with CPUs that a user is
trying to offline to a new "randomly" selected CPU.

Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: Michael Kelley <mhklinux@outlook.com>
Cc: Wei Liu <wei.liu@kernel.org>
Signed-off-by: Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Tested-by: Michael Kelley <mhklinux@outlook.com>
Link: https://lore.kernel.org/r/20250117203309.192072-3-hamzamahfooz@linux.microsoft.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>
Message-ID: <20250117203309.192072-3-hamzamahfooz@linux.microsoft.com>

authored by

Hamza Mahfooz and committed by
Wei Liu
3a7f7785 5e4304ff

+51 -21
+51 -21
drivers/hv/hv.c
··· 433 433 return pending; 434 434 } 435 435 436 + static int hv_pick_new_cpu(struct vmbus_channel *channel) 437 + { 438 + int ret = -EBUSY; 439 + int start; 440 + int cpu; 441 + 442 + lockdep_assert_cpus_held(); 443 + lockdep_assert_held(&vmbus_connection.channel_mutex); 444 + 445 + /* 446 + * We can't assume that the relevant interrupts will be sent before 447 + * the cpu is offlined on older versions of hyperv. 448 + */ 449 + if (vmbus_proto_version < VERSION_WIN10_V5_3) 450 + return -EBUSY; 451 + 452 + start = get_random_u32_below(nr_cpu_ids); 453 + 454 + for_each_cpu_wrap(cpu, cpu_online_mask, start) { 455 + if (channel->target_cpu == cpu || 456 + channel->target_cpu == VMBUS_CONNECT_CPU) 457 + continue; 458 + 459 + ret = vmbus_channel_set_cpu(channel, cpu); 460 + if (!ret) 461 + break; 462 + } 463 + 464 + if (ret) 465 + ret = vmbus_channel_set_cpu(channel, VMBUS_CONNECT_CPU); 466 + 467 + return ret; 468 + } 469 + 436 470 /* 437 471 * hv_synic_cleanup - Cleanup routine for hv_synic_init(). 438 472 */ 439 473 int hv_synic_cleanup(unsigned int cpu) 440 474 { 441 475 struct vmbus_channel *channel, *sc; 442 - bool channel_found = false; 476 + int ret = 0; 443 477 444 478 if (vmbus_connection.conn_state != CONNECTED) 445 479 goto always_cleanup; ··· 490 456 491 457 /* 492 458 * Search for channels which are bound to the CPU we're about to 493 - * cleanup. In case we find one and vmbus is still connected, we 494 - * fail; this will effectively prevent CPU offlining. 495 - * 496 - * TODO: Re-bind the channels to different CPUs. 459 + * cleanup. 497 460 */ 498 461 mutex_lock(&vmbus_connection.channel_mutex); 499 462 list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) { 500 463 if (channel->target_cpu == cpu) { 501 - channel_found = true; 502 - break; 464 + ret = hv_pick_new_cpu(channel); 465 + if (ret) { 466 + mutex_unlock(&vmbus_connection.channel_mutex); 467 + return ret; 468 + } 503 469 } 504 470 list_for_each_entry(sc, &channel->sc_list, sc_list) { 505 471 if (sc->target_cpu == cpu) { 506 - channel_found = true; 507 - break; 472 + ret = hv_pick_new_cpu(sc); 473 + if (ret) { 474 + mutex_unlock(&vmbus_connection.channel_mutex); 475 + return ret; 476 + } 508 477 } 509 478 } 510 - if (channel_found) 511 - break; 512 479 } 513 480 mutex_unlock(&vmbus_connection.channel_mutex); 514 481 515 - if (channel_found) 516 - return -EBUSY; 517 - 518 482 /* 519 - * channel_found == false means that any channels that were previously 520 - * assigned to the CPU have been reassigned elsewhere with a call of 521 - * vmbus_send_modifychannel(). Scan the event flags page looking for 522 - * bits that are set and waiting with a timeout for vmbus_chan_sched() 523 - * to process such bits. If bits are still set after this operation 524 - * and VMBus is connected, fail the CPU offlining operation. 483 + * Scan the event flags page looking for bits that are set and waiting 484 + * with a timeout for vmbus_chan_sched() to process such bits. If bits 485 + * are still set after this operation and VMBus is connected, fail the 486 + * CPU offlining operation. 525 487 */ 526 488 if (vmbus_proto_version >= VERSION_WIN10_V4_1 && hv_synic_event_pending()) 527 489 return -EBUSY; ··· 527 497 528 498 hv_synic_disable_regs(cpu); 529 499 530 - return 0; 500 + return ret; 531 501 }