patch-2.4.8 linux/mm/swapfile.c
Next file: linux/mm/vmscan.c
Previous file: linux/mm/swap.c
Back to the patch index
Back to the overall index
- Lines: 254
- Date:
Fri Aug 10 18:02:42 2001
- Orig file:
v2.4.7/linux/mm/swapfile.c
- Orig date:
Wed Jul 25 17:10:26 2001
diff -u --recursive --new-file v2.4.7/linux/mm/swapfile.c linux/mm/swapfile.c
@@ -19,11 +19,31 @@
spinlock_t swaplock = SPIN_LOCK_UNLOCKED;
unsigned int nr_swapfiles;
+int total_swap_pages;
struct swap_list_t swap_list = {-1, -1};
struct swap_info_struct swap_info[MAX_SWAPFILES];
+/*
+ * When swap space gets filled up, we will set this flag.
+ * This will make do_swap_page(), in the page fault path,
+ * free swap entries on swapin so we'll reclaim swap space
+ * in order to be able to swap something out.
+ *
+ * At the moment we start reclaiming when swap usage goes
+ * over 80% of swap space.
+ *
+ * XXX: Random numbers, fixme.
+ */
+#define SWAP_FULL_PCT 80
+int vm_swap_full (void)
+{
+ int swap_used = total_swap_pages - nr_swap_pages;
+
+ return swap_used * 100 > total_swap_pages * SWAP_FULL_PCT;
+}
+
#define SWAPFILE_CLUSTER 256
static inline int scan_swap_map(struct swap_info_struct *si, unsigned short count)
@@ -329,6 +349,54 @@
}
/*
+ * this is called when we find a page in the swap list
+ * all the locks have been dropped at this point which
+ * isn't a problem because we rescan the swap map
+ * and we _don't_ clear the refrence count if for
+ * some reason it isn't 0
+ */
+
+static inline int free_found_swap_entry(unsigned int type, int i)
+{
+ struct task_struct *p;
+ struct page *page;
+ swp_entry_t 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;
+ }
+ 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
* page table adjustments can then be made atomically.
@@ -336,82 +404,79 @@
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 ret, foundpage;
+
+ do {
+ int i;
- while (1) {
/*
* The algorithm is inefficient but seldomly used
- * and probably not worth fixing.
*
- * Make sure that we aren't completely killing
- * interactive performance.
- */
- if (current->need_resched)
- schedule();
-
- /*
* Find a swap page in use and read it in.
*/
+ foundpage = 0;
swap_device_lock(si);
for (i = 1; i < si->max ; i++) {
- if (si->swap_map[i] > 0 && si->swap_map[i] != SWAP_MAP_BAD) {
- /*
- * Prevent swaphandle from being completely
- * unused by swap_free while we are trying
- * to read in the page - this prevents warning
- * messages from rw_swap_page_base.
+ int count = si->swap_map[i];
+ if (!count || count == SWAP_MAP_BAD)
+ continue;
+
+ /*
+ * Prevent swaphandle from being completely
+ * unused by swap_free while we are trying
+ * to read in the page - this prevents warning
+ * messages from rw_swap_page_base.
+ */
+ foundpage = 1;
+ if (count != SWAP_MAP_MAX)
+ si->swap_map[i] = count + 1;
+
+ swap_device_unlock(si);
+ ret = free_found_swap_entry(type,i);
+ if (ret)
+ return ret;
+
+ /*
+ * we pick up the swap_list_lock() to guard the nr_swap_pages,
+ * si->swap_map[] should only be changed if it is SWAP_MAP_MAX
+ * otherwise ugly stuff can happen with other people who are in
+ * the middle of a swap operation to this device. This kind of
+ * operation can sometimes be detected with the undead swap
+ * check. Don't worry about these 'undead' entries for now
+ * they will be caught the next time though the top loop.
+ * Do worry, about the weak locking that allows this to happen
+ * because if it happens to a page that is SWAP_MAP_MAX
+ * then bad stuff can happen.
+ */
+ swap_list_lock();
+ swap_device_lock(si);
+ if (si->swap_map[i] > 0) {
+ /* normally this would just kill the swap page if
+ * it still existed, it appears though that the locks
+ * are a little fuzzy
*/
- if (si->swap_map[i] != SWAP_MAP_MAX)
- si->swap_map[i]++;
- swap_device_unlock(si);
- goto found_entry;
+ if (si->swap_map[i] != SWAP_MAP_MAX) {
+ printk("VM: Undead swap entry %08lx\n",
+ SWP_ENTRY(type, i).val);
+ } else {
+ nr_swap_pages++;
+ si->swap_map[i] = 0;
+ }
}
- }
- swap_device_unlock(si);
- break;
+ swap_device_unlock(si);
+ swap_list_unlock();
- 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;
- }
- 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);
- if (si->swap_map[i] > 0) {
- if (si->swap_map[i] != SWAP_MAP_MAX)
- printk("VM: Undead swap entry %08lx\n",
- entry.val);
- nr_swap_pages++;
- si->swap_map[i] = 0;
+ /*
+ * This lock stuff is ulgy!
+ * Make sure that we aren't completely killing
+ * interactive performance.
+ */
+ if (current->need_resched)
+ schedule();
+ swap_device_lock(si);
}
swap_device_unlock(si);
- swap_list_unlock();
- }
+ } while (foundpage);
return 0;
}
@@ -462,6 +527,7 @@
swap_list.next = swap_list.head;
}
nr_swap_pages -= p->pages;
+ total_swap_pages -= p->pages;
swap_list_unlock();
p->flags = SWP_USED;
err = try_to_unuse(type);
@@ -477,6 +543,7 @@
else
swap_info[prev].next = p - swap_info;
nr_swap_pages += p->pages;
+ total_swap_pages += p->pages;
swap_list_unlock();
p->flags = SWP_WRITEOK;
goto out_dput;
@@ -764,6 +831,7 @@
p->pages = nr_good_pages;
swap_list_lock();
nr_swap_pages += nr_good_pages;
+ total_swap_pages += nr_good_pages;
printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n",
nr_good_pages<<(PAGE_SHIFT-10), p->prio);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)