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.

mm: huge_memory: refactor anon_enabled_store() with set_anon_enabled_mode()

Consolidate the repeated spin_lock/set_bit/clear_bit pattern in
anon_enabled_store() into a new set_anon_enabled_mode() helper that loops
over an orders[] array, setting the bit for the selected mode and clearing
the others.

Introduce enum anon_enabled_mode and anon_enabled_mode_strings[] for the
per-order anon THP setting.

Use sysfs_match_string() with the anon_enabled_mode_strings[] table to
replace the if/else chain of sysfs_streq() calls.

The helper uses __test_and_set_bit()/__test_and_clear_bit() to track
whether the state actually changed, so start_stop_khugepaged() is only
called when needed. When the mode is unchanged,
set_recommended_min_free_kbytes() is called directly to preserve the
watermark recalculation behavior of the original code.

Link: https://lkml.kernel.org/r/20260317-thp_logs-v7-2-31eb98fa5a8b@debian.org
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Barry Song <baohua@kernel.org>
Cc: Brendan Jackman <jackmanb@google.com>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Nico Pache <npache@redhat.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Usama Arif <usamaarif642@gmail.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Wei Yang <richard.weiyang@gmail.com>
Cc: Zi Yan <ziy@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Breno Leitao and committed by
Andrew Morton
82d9ff64 c82aade0

+52 -32
+52 -32
mm/huge_memory.c
··· 316 316 return sysfs_emit(buf, "%s\n", output); 317 317 } 318 318 319 + enum anon_enabled_mode { 320 + ANON_ENABLED_ALWAYS = 0, 321 + ANON_ENABLED_INHERIT = 1, 322 + ANON_ENABLED_MADVISE = 2, 323 + ANON_ENABLED_NEVER = 3, 324 + }; 325 + 326 + static const char * const anon_enabled_mode_strings[] = { 327 + [ANON_ENABLED_ALWAYS] = "always", 328 + [ANON_ENABLED_INHERIT] = "inherit", 329 + [ANON_ENABLED_MADVISE] = "madvise", 330 + [ANON_ENABLED_NEVER] = "never", 331 + }; 332 + 319 333 static ssize_t enabled_store(struct kobject *kobj, 320 334 struct kobj_attribute *attr, 321 335 const char *buf, size_t count) ··· 529 515 return sysfs_emit(buf, "%s\n", output); 530 516 } 531 517 518 + static bool set_anon_enabled_mode(int order, enum anon_enabled_mode mode) 519 + { 520 + static unsigned long *enabled_orders[] = { 521 + &huge_anon_orders_always, 522 + &huge_anon_orders_inherit, 523 + &huge_anon_orders_madvise, 524 + }; 525 + enum anon_enabled_mode m; 526 + bool changed = false; 527 + 528 + spin_lock(&huge_anon_orders_lock); 529 + for (m = 0; m < ARRAY_SIZE(enabled_orders); m++) { 530 + if (m == mode) 531 + changed |= !__test_and_set_bit(order, enabled_orders[m]); 532 + else 533 + changed |= __test_and_clear_bit(order, enabled_orders[m]); 534 + } 535 + spin_unlock(&huge_anon_orders_lock); 536 + 537 + return changed; 538 + } 539 + 532 540 static ssize_t anon_enabled_store(struct kobject *kobj, 533 541 struct kobj_attribute *attr, 534 542 const char *buf, size_t count) 535 543 { 536 544 int order = to_thpsize(kobj)->order; 537 - ssize_t ret = count; 545 + int mode; 538 546 539 - if (sysfs_streq(buf, "always")) { 540 - spin_lock(&huge_anon_orders_lock); 541 - clear_bit(order, &huge_anon_orders_inherit); 542 - clear_bit(order, &huge_anon_orders_madvise); 543 - set_bit(order, &huge_anon_orders_always); 544 - spin_unlock(&huge_anon_orders_lock); 545 - } else if (sysfs_streq(buf, "inherit")) { 546 - spin_lock(&huge_anon_orders_lock); 547 - clear_bit(order, &huge_anon_orders_always); 548 - clear_bit(order, &huge_anon_orders_madvise); 549 - set_bit(order, &huge_anon_orders_inherit); 550 - spin_unlock(&huge_anon_orders_lock); 551 - } else if (sysfs_streq(buf, "madvise")) { 552 - spin_lock(&huge_anon_orders_lock); 553 - clear_bit(order, &huge_anon_orders_always); 554 - clear_bit(order, &huge_anon_orders_inherit); 555 - set_bit(order, &huge_anon_orders_madvise); 556 - spin_unlock(&huge_anon_orders_lock); 557 - } else if (sysfs_streq(buf, "never")) { 558 - spin_lock(&huge_anon_orders_lock); 559 - clear_bit(order, &huge_anon_orders_always); 560 - clear_bit(order, &huge_anon_orders_inherit); 561 - clear_bit(order, &huge_anon_orders_madvise); 562 - spin_unlock(&huge_anon_orders_lock); 563 - } else 564 - ret = -EINVAL; 547 + mode = sysfs_match_string(anon_enabled_mode_strings, buf); 548 + if (mode < 0) 549 + return -EINVAL; 565 550 566 - if (ret > 0) { 567 - int err; 551 + if (set_anon_enabled_mode(order, mode)) { 552 + int err = start_stop_khugepaged(); 568 553 569 - err = start_stop_khugepaged(); 570 554 if (err) 571 - ret = err; 555 + return err; 556 + } else { 557 + /* 558 + * Recalculate watermarks even when the mode didn't 559 + * change, as the previous code always called 560 + * start_stop_khugepaged() which does this internally. 561 + */ 562 + set_recommended_min_free_kbytes(); 572 563 } 573 - return ret; 564 + 565 + return count; 574 566 } 575 567 576 568 static struct kobj_attribute anon_enabled_attr =