]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - mm/shmem.c
UBUNTU: Ubuntu-5.15.0-37.39
[mirror_ubuntu-jammy-kernel.git] / mm / shmem.c
index b5860f4a2738ee3861e30bd4e506578a0f9218ba..d63eec1d2f58936cf649f12e9fddcca51fd392b7 100644 (file)
@@ -555,7 +555,7 @@ static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo,
        struct shmem_inode_info *info;
        struct page *page;
        unsigned long batch = sc ? sc->nr_to_scan : 128;
-       int removed = 0, split = 0;
+       int split = 0;
 
        if (list_empty(&sbinfo->shrinklist))
                return SHRINK_STOP;
@@ -570,7 +570,6 @@ static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo,
                /* inode is about to be evicted */
                if (!inode) {
                        list_del_init(&info->shrinklist);
-                       removed++;
                        goto next;
                }
 
@@ -578,12 +577,12 @@ static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo,
                if (round_up(inode->i_size, PAGE_SIZE) ==
                                round_up(inode->i_size, HPAGE_PMD_SIZE)) {
                        list_move(&info->shrinklist, &to_remove);
-                       removed++;
                        goto next;
                }
 
                list_move(&info->shrinklist, &list);
 next:
+               sbinfo->shrinklist_len--;
                if (!--batch)
                        break;
        }
@@ -603,7 +602,7 @@ next:
                inode = &info->vfs_inode;
 
                if (nr_to_split && split >= nr_to_split)
-                       goto leave;
+                       goto move_back;
 
                page = find_get_page(inode->i_mapping,
                                (inode->i_size & HPAGE_PMD_MASK) >> PAGE_SHIFT);
@@ -617,38 +616,44 @@ next:
                }
 
                /*
-                * Leave the inode on the list if we failed to lock
-                * the page at this time.
+                * Move the inode on the list back to shrinklist if we failed
+                * to lock the page at this time.
                 *
                 * Waiting for the lock may lead to deadlock in the
                 * reclaim path.
                 */
                if (!trylock_page(page)) {
                        put_page(page);
-                       goto leave;
+                       goto move_back;
                }
 
                ret = split_huge_page(page);
                unlock_page(page);
                put_page(page);
 
-               /* If split failed leave the inode on the list */
+               /* If split failed move the inode on the list back to shrinklist */
                if (ret)
-                       goto leave;
+                       goto move_back;
 
                split++;
 drop:
                list_del_init(&info->shrinklist);
-               removed++;
-leave:
+               goto put;
+move_back:
+               /*
+                * Make sure the inode is either on the global list or deleted
+                * from any local list before iput() since it could be deleted
+                * in another thread once we put the inode (then the local list
+                * is corrupted).
+                */
+               spin_lock(&sbinfo->shrinklist_lock);
+               list_move(&info->shrinklist, &sbinfo->shrinklist);
+               sbinfo->shrinklist_len++;
+               spin_unlock(&sbinfo->shrinklist_lock);
+put:
                iput(inode);
        }
 
-       spin_lock(&sbinfo->shrinklist_lock);
-       list_splice_tail(&list, &sbinfo->shrinklist);
-       sbinfo->shrinklist_len -= removed;
-       spin_unlock(&sbinfo->shrinklist_lock);
-
        return split;
 }
 
@@ -4162,6 +4167,7 @@ int shmem_zero_setup(struct vm_area_struct *vma)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(shmem_zero_setup);
 
 /**
  * shmem_read_mapping_page_gfp - read into page cache, using specified page allocation flags.