]> git.ipfire.org Git - thirdparty/linux.git/blobdiff - mm/swapfile.c
mm/swapfile.c: __swap_entry_free() always free 1 entry
[thirdparty/linux.git] / mm / swapfile.c
index 5871a2aa86a57d4a43d2edb8d76fa083265cfde0..2aa272376cae18652ad7e3712cc6d78062820e7f 100644 (file)
@@ -601,7 +601,6 @@ static bool scan_swap_map_try_ssd_cluster(struct swap_info_struct *si,
 {
        struct percpu_cluster *cluster;
        struct swap_cluster_info *ci;
-       bool found_free;
        unsigned long tmp, max;
 
 new_cluster:
@@ -623,8 +622,6 @@ new_cluster:
                        return false;
        }
 
-       found_free = false;
-
        /*
         * Other CPUs can use our cluster if they can't find a free cluster,
         * check if there is still free entry in the cluster
@@ -632,27 +629,23 @@ new_cluster:
        tmp = cluster->next;
        max = min_t(unsigned long, si->max,
                    (cluster_next(&cluster->index) + 1) * SWAPFILE_CLUSTER);
-       if (tmp >= max) {
-               cluster_set_null(&cluster->index);
-               goto new_cluster;
-       }
-       ci = lock_cluster(si, tmp);
-       while (tmp < max) {
-               if (!si->swap_map[tmp]) {
-                       found_free = true;
-                       break;
+       if (tmp < max) {
+               ci = lock_cluster(si, tmp);
+               while (tmp < max) {
+                       if (!si->swap_map[tmp])
+                               break;
+                       tmp++;
                }
-               tmp++;
+               unlock_cluster(ci);
        }
-       unlock_cluster(ci);
-       if (!found_free) {
+       if (tmp >= max) {
                cluster_set_null(&cluster->index);
                goto new_cluster;
        }
        cluster->next = tmp + 1;
        *offset = tmp;
        *scan_base = tmp;
-       return found_free;
+       return true;
 }
 
 static void __del_from_avail_list(struct swap_info_struct *p)
@@ -739,9 +732,7 @@ static int scan_swap_map_slots(struct swap_info_struct *si,
        unsigned long last_in_cluster = 0;
        int latency_ration = LATENCY_LIMIT;
        int n_ret = 0;
-
-       if (nr > SWAP_BATCH)
-               nr = SWAP_BATCH;
+       bool scanned_many = false;
 
        /*
         * We try to cluster swap pages by allocating them sequentially
@@ -759,13 +750,9 @@ static int scan_swap_map_slots(struct swap_info_struct *si,
 
        /* SSD algorithm */
        if (si->cluster_info) {
-               if (scan_swap_map_try_ssd_cluster(si, &offset, &scan_base))
-                       goto checks;
-               else
+               if (!scan_swap_map_try_ssd_cluster(si, &offset, &scan_base))
                        goto scan;
-       }
-
-       if (unlikely(!si->cluster_nr--)) {
+       } else if (unlikely(!si->cluster_nr--)) {
                if (si->pages - si->inuse_pages < SWAPFILE_CLUSTER) {
                        si->cluster_nr = SWAPFILE_CLUSTER - 1;
                        goto checks;
@@ -871,18 +858,31 @@ checks:
        if (si->cluster_info) {
                if (scan_swap_map_try_ssd_cluster(si, &offset, &scan_base))
                        goto checks;
-               else
-                       goto done;
-       }
-       /* non-ssd case */
-       ++offset;
-
-       /* non-ssd case, still more slots in cluster? */
-       if (si->cluster_nr && !si->swap_map[offset]) {
+       } else if (si->cluster_nr && !si->swap_map[++offset]) {
+               /* non-ssd case, still more slots in cluster? */
                --si->cluster_nr;
                goto checks;
        }
 
+       /*
+        * Even if there's no free clusters available (fragmented),
+        * try to scan a little more quickly with lock held unless we
+        * have scanned too many slots already.
+        */
+       if (!scanned_many) {
+               unsigned long scan_limit;
+
+               if (offset < scan_base)
+                       scan_limit = scan_base;
+               else
+                       scan_limit = si->highest_bit;
+               for (; offset <= scan_limit && --latency_ration > 0;
+                    offset++) {
+                       if (!si->swap_map[offset])
+                               goto checks;
+               }
+       }
+
 done:
        si->flags -= SWP_SCANNING;
        return n_ret;
@@ -901,6 +901,7 @@ scan:
                if (unlikely(--latency_ration < 0)) {
                        cond_resched();
                        latency_ration = LATENCY_LIMIT;
+                       scanned_many = true;
                }
        }
        offset = si->lowest_bit;
@@ -916,6 +917,7 @@ scan:
                if (unlikely(--latency_ration < 0)) {
                        cond_resched();
                        latency_ration = LATENCY_LIMIT;
+                       scanned_many = true;
                }
                offset++;
        }
@@ -1004,11 +1006,7 @@ int get_swap_pages(int n_goal, swp_entry_t swp_entries[], int entry_size)
        if (avail_pgs <= 0)
                goto noswap;
 
-       if (n_goal > SWAP_BATCH)
-               n_goal = SWAP_BATCH;
-
-       if (n_goal > avail_pgs)
-               n_goal = avail_pgs;
+       n_goal = min3((long)n_goal, (long)SWAP_BATCH, avail_pgs);
 
        atomic_long_sub(n_goal * size, &nr_swap_pages);
 
@@ -1275,13 +1273,14 @@ unlock_out:
 }
 
 static unsigned char __swap_entry_free(struct swap_info_struct *p,
-                                      swp_entry_t entry, unsigned char usage)
+                                      swp_entry_t entry)
 {
        struct swap_cluster_info *ci;
        unsigned long offset = swp_offset(entry);
+       unsigned char usage;
 
        ci = lock_cluster_or_swap_info(p, offset);
-       usage = __swap_entry_free_locked(p, offset, usage);
+       usage = __swap_entry_free_locked(p, offset, 1);
        unlock_cluster_or_swap_info(p, ci);
        if (!usage)
                free_swap_slot(entry);
@@ -1316,7 +1315,7 @@ void swap_free(swp_entry_t entry)
 
        p = _swap_info_get(entry);
        if (p)
-               __swap_entry_free(p, entry, 1);
+               __swap_entry_free(p, entry);
 }
 
 /*
@@ -1739,7 +1738,7 @@ int free_swap_and_cache(swp_entry_t entry)
 
        p = _swap_info_get(entry);
        if (p) {
-               count = __swap_entry_free(p, entry, 1);
+               count = __swap_entry_free(p, entry);
                if (count == SWAP_HAS_CACHE &&
                    !swap_page_trans_huge_swapped(p, entry))
                        __try_to_reclaim_swap(p, swp_offset(entry),
@@ -1937,10 +1936,14 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
 
                pte_unmap(pte);
                swap_map = &si->swap_map[offset];
-               vmf.vma = vma;
-               vmf.address = addr;
-               vmf.pmd = pmd;
-               page = swapin_readahead(entry, GFP_HIGHUSER_MOVABLE, &vmf);
+               page = lookup_swap_cache(entry, vma, addr);
+               if (!page) {
+                       vmf.vma = vma;
+                       vmf.address = addr;
+                       vmf.pmd = pmd;
+                       page = swapin_readahead(entry, GFP_HIGHUSER_MOVABLE,
+                                               &vmf);
+               }
                if (!page) {
                        if (*swap_map == 0 || *swap_map == SWAP_MAP_BAD)
                                goto try_next;
@@ -3654,7 +3657,7 @@ static bool swap_count_continued(struct swap_info_struct *si,
 
        spin_lock(&si->cont_lock);
        offset &= ~PAGE_MASK;
-       page = list_entry(head->lru.next, struct page, lru);
+       page = list_next_entry(head, lru);
        map = kmap_atomic(page) + offset;
 
        if (count == SWAP_MAP_MAX)      /* initial increment from swap_map */
@@ -3666,13 +3669,13 @@ static bool swap_count_continued(struct swap_info_struct *si,
                 */
                while (*map == (SWAP_CONT_MAX | COUNT_CONTINUED)) {
                        kunmap_atomic(map);
-                       page = list_entry(page->lru.next, struct page, lru);
+                       page = list_next_entry(page, lru);
                        BUG_ON(page == head);
                        map = kmap_atomic(page) + offset;
                }
                if (*map == SWAP_CONT_MAX) {
                        kunmap_atomic(map);
-                       page = list_entry(page->lru.next, struct page, lru);
+                       page = list_next_entry(page, lru);
                        if (page == head) {
                                ret = false;    /* add count continuation */
                                goto out;
@@ -3682,12 +3685,10 @@ init_map:               *map = 0;               /* we didn't zero the page */
                }
                *map += 1;
                kunmap_atomic(map);
-               page = list_entry(page->lru.prev, struct page, lru);
-               while (page != head) {
+               while ((page = list_prev_entry(page, lru)) != head) {
                        map = kmap_atomic(page) + offset;
                        *map = COUNT_CONTINUED;
                        kunmap_atomic(map);
-                       page = list_entry(page->lru.prev, struct page, lru);
                }
                ret = true;                     /* incremented */
 
@@ -3698,7 +3699,7 @@ init_map:         *map = 0;               /* we didn't zero the page */
                BUG_ON(count != COUNT_CONTINUED);
                while (*map == COUNT_CONTINUED) {
                        kunmap_atomic(map);
-                       page = list_entry(page->lru.next, struct page, lru);
+                       page = list_next_entry(page, lru);
                        BUG_ON(page == head);
                        map = kmap_atomic(page) + offset;
                }
@@ -3707,13 +3708,11 @@ init_map:               *map = 0;               /* we didn't zero the page */
                if (*map == 0)
                        count = 0;
                kunmap_atomic(map);
-               page = list_entry(page->lru.prev, struct page, lru);
-               while (page != head) {
+               while ((page = list_prev_entry(page, lru)) != head) {
                        map = kmap_atomic(page) + offset;
                        *map = SWAP_CONT_MAX | count;
                        count = COUNT_CONTINUED;
                        kunmap_atomic(map);
-                       page = list_entry(page->lru.prev, struct page, lru);
                }
                ret = count == COUNT_CONTINUED;
        }