diff -uwrN linux/mm/swapfile.c.old linux/mm/swapfile.c --- linux/mm/swapfile.c.old Tue Jun 19 17:15:07 2001 +++ linux/mm/swapfile.c Tue Jun 19 17:44:24 2001 @@ -328,6 +328,41 @@ return; } +static int unuse_entry (swp_entry_t entry) { + struct page *page; + struct task_struct *p; + + /* Get a page for the entry, using the existing swap + cache page if there is one. Otherwise, get a clean + page and read the swap into it. */ + page = read_swap_cache_async(entry); + if (!page) { + swap_free(entry); + return -ENOMEM; + } + + lock_page (page); + if (PageSwapCache(page)) + delete_from_swap_cache_nolock(page); + UnlockPage (page); + + read_lock(&tasklist_lock); + for_each_task(p) + unuse_process(p->mm, entry, page); + read_unlock(&tasklist_lock); + + shmem_unuse(entry, page); + /* Now get rid of the extra reference to the temporary + page we've been using. */ + page_cache_release(page); + /* + * Check for and clear any overflowed swap map counts. + */ + swap_free(entry); + + return 0; +} + /* * We completely avoid races by reading each swap page in advance, * and then search for the process using it. All the necessary @@ -336,12 +371,10 @@ static int try_to_unuse(unsigned int type) { struct swap_info_struct * si = &swap_info[type]; - struct task_struct *p; - struct page *page; swp_entry_t entry; int i; + int err; - while (1) { /* * Find a swap page in use and read it in. */ @@ -356,42 +389,19 @@ */ if (si->swap_map[i] != SWAP_MAP_MAX) si->swap_map[i]++; + swap_device_unlock(si); - goto found_entry; - } - } - swap_device_unlock(si); - break; - found_entry: entry = SWP_ENTRY(type, i); - - /* Get a page for the entry, using the existing swap - cache page if there is one. Otherwise, get a clean - page and read the swap into it. */ - page = read_swap_cache_async(entry); - if (!page) { - swap_free(entry); - return -ENOMEM; + err = unuse_entry (entry); + if (err < 0) { + return err; } - lock_page(page); - if (PageSwapCache(page)) - delete_from_swap_cache_nolock(page); - UnlockPage(page); - read_lock(&tasklist_lock); - for_each_task(p) - unuse_process(p->mm, entry, page); - read_unlock(&tasklist_lock); - shmem_unuse(entry, page); - /* Now get rid of the extra reference to the temporary - page we've been using. */ - page_cache_release(page); - /* - * Check for and clear any overflowed swap map counts. - */ - swap_free(entry); - swap_list_lock(); + swap_device_lock(si); + + swap_list_lock(); + /* check this value again after unusing the entry */ if (si->swap_map[i] > 0) { if (si->swap_map[i] != SWAP_MAP_MAX) printk("VM: Undead swap entry %08lx\n", @@ -399,9 +409,13 @@ nr_swap_pages++; si->swap_map[i] = 0; } - swap_device_unlock(si); swap_list_unlock(); + + /* Leave the device locked for loop */ + } } + swap_device_unlock (si); + return 0; }