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, swap: use an enum to define all cluster flags and wrap flags changes

Currently, we are only using flags to indicate which list the cluster is
on. Using one bit for each list type might be a waste, as the list type
grows, we will consume too many bits. Additionally, the current mixed
usage of '&' and '==' is a bit confusing.

Make it clean by using an enum to define all possible cluster statuses.
Only an off-list cluster will have the NONE (0) flag. And use a wrapper
to annotate and sanitize all flag settings and list movements.

Link: https://lkml.kernel.org/r/20250113175732.48099-9-ryncsn@gmail.com
Signed-off-by: Kairui Song <kasong@tencent.com>
Suggested-by: Chris Li <chrisl@kernel.org>
Cc: Baoquan He <bhe@redhat.com>
Cc: Barry Song <v-songbaohua@oppo.com>
Cc: "Huang, Ying" <ying.huang@linux.alibaba.com>
Cc: Hugh Dickens <hughd@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Kalesh Singh <kaleshsingh@google.com>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Yosry Ahmed <yosryahmed@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Kairui Song and committed by
Andrew Morton
3494d184 9a0ddeb7

+53 -40
+13 -4
include/linux/swap.h
··· 256 256 u8 order; 257 257 struct list_head list; 258 258 }; 259 - #define CLUSTER_FLAG_FREE 1 /* This cluster is free */ 260 - #define CLUSTER_FLAG_NONFULL 2 /* This cluster is on nonfull list */ 261 - #define CLUSTER_FLAG_FRAG 4 /* This cluster is on nonfull list */ 262 - #define CLUSTER_FLAG_FULL 8 /* This cluster is on full list */ 259 + 260 + /* All on-list cluster must have a non-zero flag. */ 261 + enum swap_cluster_flags { 262 + CLUSTER_FLAG_NONE = 0, /* For temporary off-list cluster */ 263 + CLUSTER_FLAG_FREE, 264 + CLUSTER_FLAG_NONFULL, 265 + CLUSTER_FLAG_FRAG, 266 + /* Clusters with flags above are allocatable */ 267 + CLUSTER_FLAG_USABLE = CLUSTER_FLAG_FRAG, 268 + CLUSTER_FLAG_FULL, 269 + CLUSTER_FLAG_DISCARD, 270 + CLUSTER_FLAG_MAX, 271 + }; 263 272 264 273 /* 265 274 * The first page in the swap file is the swap header, which is always marked
+40 -36
mm/swapfile.c
··· 403 403 404 404 static inline bool cluster_is_free(struct swap_cluster_info *info) 405 405 { 406 - return info->flags & CLUSTER_FLAG_FREE; 406 + return info->flags == CLUSTER_FLAG_FREE; 407 407 } 408 408 409 409 static inline unsigned int cluster_index(struct swap_info_struct *si, ··· 434 434 spin_unlock(&ci->lock); 435 435 } 436 436 437 + static void move_cluster(struct swap_info_struct *si, 438 + struct swap_cluster_info *ci, struct list_head *list, 439 + enum swap_cluster_flags new_flags) 440 + { 441 + VM_WARN_ON(ci->flags == new_flags); 442 + 443 + BUILD_BUG_ON(1 << sizeof(ci->flags) * BITS_PER_BYTE < CLUSTER_FLAG_MAX); 444 + 445 + if (ci->flags == CLUSTER_FLAG_NONE) { 446 + list_add_tail(&ci->list, list); 447 + } else { 448 + if (ci->flags == CLUSTER_FLAG_FRAG) { 449 + VM_WARN_ON(!si->frag_cluster_nr[ci->order]); 450 + si->frag_cluster_nr[ci->order]--; 451 + } 452 + list_move_tail(&ci->list, list); 453 + } 454 + ci->flags = new_flags; 455 + if (new_flags == CLUSTER_FLAG_FRAG) 456 + si->frag_cluster_nr[ci->order]++; 457 + } 458 + 437 459 /* Add a cluster to discard list and schedule it to do discard */ 438 460 static void swap_cluster_schedule_discard(struct swap_info_struct *si, 439 461 struct swap_cluster_info *ci) ··· 469 447 */ 470 448 memset(si->swap_map + idx * SWAPFILE_CLUSTER, 471 449 SWAP_MAP_BAD, SWAPFILE_CLUSTER); 472 - 473 - VM_BUG_ON(ci->flags & CLUSTER_FLAG_FREE); 474 - list_move_tail(&ci->list, &si->discard_clusters); 475 - ci->flags = 0; 450 + VM_BUG_ON(ci->flags == CLUSTER_FLAG_FREE); 451 + move_cluster(si, ci, &si->discard_clusters, CLUSTER_FLAG_DISCARD); 476 452 schedule_work(&si->discard_work); 477 453 } 478 454 ··· 478 458 { 479 459 lockdep_assert_held(&si->lock); 480 460 lockdep_assert_held(&ci->lock); 481 - 482 - if (ci->flags) 483 - list_move_tail(&ci->list, &si->free_clusters); 484 - else 485 - list_add_tail(&ci->list, &si->free_clusters); 486 - ci->flags = CLUSTER_FLAG_FREE; 461 + move_cluster(si, ci, &si->free_clusters, CLUSTER_FLAG_FREE); 487 462 ci->order = 0; 488 463 } 489 464 ··· 494 479 while (!list_empty(&si->discard_clusters)) { 495 480 ci = list_first_entry(&si->discard_clusters, struct swap_cluster_info, list); 496 481 list_del(&ci->list); 482 + /* Must clear flag when taking a cluster off-list */ 483 + ci->flags = CLUSTER_FLAG_NONE; 497 484 idx = cluster_index(si, ci); 498 485 spin_unlock(&si->lock); 499 486 ··· 535 518 VM_BUG_ON(ci->count != 0); 536 519 lockdep_assert_held(&si->lock); 537 520 lockdep_assert_held(&ci->lock); 538 - 539 - if (ci->flags & CLUSTER_FLAG_FRAG) 540 - si->frag_cluster_nr[ci->order]--; 541 521 542 522 /* 543 523 * If the swap is discardable, prepare discard the cluster ··· 587 573 return; 588 574 } 589 575 590 - if (!(ci->flags & CLUSTER_FLAG_NONFULL)) { 591 - VM_BUG_ON(ci->flags & CLUSTER_FLAG_FREE); 592 - if (ci->flags & CLUSTER_FLAG_FRAG) 593 - si->frag_cluster_nr[ci->order]--; 594 - list_move_tail(&ci->list, &si->nonfull_clusters[ci->order]); 595 - ci->flags = CLUSTER_FLAG_NONFULL; 596 - } 576 + if (ci->flags != CLUSTER_FLAG_NONFULL) 577 + move_cluster(si, ci, &si->nonfull_clusters[ci->order], 578 + CLUSTER_FLAG_NONFULL); 597 579 } 598 580 599 581 static bool cluster_reclaim_range(struct swap_info_struct *si, ··· 673 663 if (!(si->flags & SWP_WRITEOK)) 674 664 return false; 675 665 666 + VM_BUG_ON(ci->flags == CLUSTER_FLAG_NONE); 667 + VM_BUG_ON(ci->flags > CLUSTER_FLAG_USABLE); 668 + 676 669 if (cluster_is_free(ci)) { 677 - if (nr_pages < SWAPFILE_CLUSTER) { 678 - list_move_tail(&ci->list, &si->nonfull_clusters[order]); 679 - ci->flags = CLUSTER_FLAG_NONFULL; 680 - } 670 + if (nr_pages < SWAPFILE_CLUSTER) 671 + move_cluster(si, ci, &si->nonfull_clusters[order], 672 + CLUSTER_FLAG_NONFULL); 681 673 ci->order = order; 682 674 } 683 675 ··· 687 675 swap_range_alloc(si, nr_pages); 688 676 ci->count += nr_pages; 689 677 690 - if (ci->count == SWAPFILE_CLUSTER) { 691 - VM_BUG_ON(!(ci->flags & 692 - (CLUSTER_FLAG_FREE | CLUSTER_FLAG_NONFULL | CLUSTER_FLAG_FRAG))); 693 - if (ci->flags & CLUSTER_FLAG_FRAG) 694 - si->frag_cluster_nr[ci->order]--; 695 - list_move_tail(&ci->list, &si->full_clusters); 696 - ci->flags = CLUSTER_FLAG_FULL; 697 - } 678 + if (ci->count == SWAPFILE_CLUSTER) 679 + move_cluster(si, ci, &si->full_clusters, CLUSTER_FLAG_FULL); 698 680 699 681 return true; 700 682 } ··· 827 821 while (!list_empty(&si->nonfull_clusters[order])) { 828 822 ci = list_first_entry(&si->nonfull_clusters[order], 829 823 struct swap_cluster_info, list); 830 - list_move_tail(&ci->list, &si->frag_clusters[order]); 831 - ci->flags = CLUSTER_FLAG_FRAG; 832 - si->frag_cluster_nr[order]++; 824 + move_cluster(si, ci, &si->frag_clusters[order], CLUSTER_FLAG_FRAG); 833 825 offset = alloc_swap_scan_cluster(si, cluster_offset(si, ci), 834 826 &found, order, usage); 835 827 frags++;