when usage=1 and swapcount is very large, the situation can become quite complex. The first entry might succeed with swap_count_continued(), but the second entry may require extending to an additional continued page. Rolling back these changes can be extremely challenging. Therefore, anyone using usage==1 for batched __swap_duplicate() operations should proceed with caution. Additionally, we have moved swap_count_continued() to the second iteration to enhance readability, as this function may modify data. Suggested-by: "Huang, Ying" <ying.huang@xxxxxxxxx> Signed-off-by: Barry Song <v-songbaohua@xxxxxxxx> --- mm/swapfile.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/mm/swapfile.c b/mm/swapfile.c index d9cf31b04db3..ea023fc25d08 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -3540,6 +3540,7 @@ static int __swap_duplicate(swp_entry_t entry, unsigned char usage, int nr) offset = swp_offset(entry); VM_WARN_ON(nr > SWAPFILE_CLUSTER - offset % SWAPFILE_CLUSTER); + VM_WARN_ON(usage == 1 && nr > 1); ci = lock_cluster_or_swap_info(p, offset); err = 0; @@ -3558,27 +3559,14 @@ static int __swap_duplicate(swp_entry_t entry, unsigned char usage, int nr) has_cache = count & SWAP_HAS_CACHE; count &= ~SWAP_HAS_CACHE; - if (usage == SWAP_HAS_CACHE) { - /* set SWAP_HAS_CACHE if there is no cache and entry is used */ - if (!has_cache && count) - continue; - else if (has_cache) /* someone else added cache */ + if (!count && !has_cache) { + err = -ENOENT; + } else if (usage == SWAP_HAS_CACHE) { + if (has_cache) err = -EEXIST; - else /* no users remaining */ - err = -ENOENT; - - } else if (count || has_cache) { - - if ((count & ~COUNT_CONTINUED) < SWAP_MAP_MAX) - continue; - else if ((count & ~COUNT_CONTINUED) > SWAP_MAP_MAX) - err = -EINVAL; - else if (swap_count_continued(p, offset + i, count)) - continue; - else - err = -ENOMEM; - } else - err = -ENOENT; /* unused swap entry */ + } else if ((count & ~COUNT_CONTINUED) > SWAP_MAP_MAX) { + err = -EINVAL; + } if (err) goto unlock_out; @@ -3593,8 +3581,16 @@ static int __swap_duplicate(swp_entry_t entry, unsigned char usage, int nr) has_cache = SWAP_HAS_CACHE; else if ((count & ~COUNT_CONTINUED) < SWAP_MAP_MAX) count += usage; - else + else if (swap_count_continued(p, offset + i, count)) count = COUNT_CONTINUED; + else { + /* + * Don't need to rollback changes, because if + * usage == 1, there must be nr == 1. + */ + err = -ENOMEM; + goto unlock_out; + } WRITE_ONCE(p->swap_map[offset + i], count | has_cache); } -- 2.34.1 > >> >> >> >> >> Best Regards, > >> >> >> >> >> Huang, Ying > >> >> >> >> > > >> >> > > > Thanks Barry