]> git.hungrycats.org Git - linux/commitdiff
[PATCH] realtime swapspace accounting
authorAndrew Morton <akpm@digeo.com>
Tue, 26 Nov 2002 01:57:13 +0000 (17:57 -0800)
committerLinus Torvalds <torvalds@home.transmeta.com>
Tue, 26 Nov 2002 01:57:13 +0000 (17:57 -0800)
There are a couple of statistical functions which scan the entire swap
map counting things up, to display in /proc.

On my machine, these hold spinlocks for 19 milliseconds which is
unacceptable from a scheduling latency point of view.

And an application which sits in a loop reading /proc/swaps on a large
machine is probably a decent denial-of-service attack - it will limit
swap allocations to tens of pages per second.

So add a counter to swap_info_struct and use it to track how many pages
are currently in use, so those reporting functions don't need to add
them all up.

include/linux/swap.h
mm/swapfile.c

index 8ad50c284b45c419873689702586ba8bf13a8026..d74f0800ab32b16494d4ad33e33075406e76035c 100644 (file)
@@ -121,6 +121,7 @@ struct swap_info_struct {
        int prio;                       /* swap priority */
        int pages;
        unsigned long max;
+       unsigned long inuse_pages;
        int next;                       /* next entry on swap list */
 };
 
index dd00507fb5711c881458a861f981e93023c240c5..2b9b14d71a4af48ae552345014d49cb2d2583be4 100644 (file)
@@ -93,6 +93,7 @@ static inline int scan_swap_map(struct swap_info_struct *si)
                        si->highest_bit = 0;
                }
                si->swap_map[offset] = 1;
+               si->inuse_pages++;
                nr_swap_pages--;
                si->cluster_next = offset+1;
                return offset;
@@ -208,6 +209,7 @@ static int swap_entry_free(struct swap_info_struct *p, unsigned long offset)
                        if (offset > p->highest_bit)
                                p->highest_bit = offset;
                        nr_swap_pages++;
+                       p->inuse_pages--;
                }
        }
        return count;
@@ -1104,7 +1106,6 @@ static void swap_stop(struct seq_file *swap, void *v)
 static int swap_show(struct seq_file *swap, void *v)
 {
        struct swap_info_struct *ptr = v;
-       int j, usedswap;
        struct file *file;
        char *path;
 
@@ -1114,20 +1115,12 @@ static int swap_show(struct seq_file *swap, void *v)
        file = ptr->swap_file;
        path = d_path(file->f_dentry, file->f_vfsmnt, swap->private, PAGE_SIZE);
 
-       for (j = 0, usedswap = 0; j < ptr->max; ++j)
-               switch (ptr->swap_map[j]) {
-                       case SWAP_MAP_BAD:
-                       case 0:
-                               continue;
-                       default:
-                               usedswap++;
-               }
-       seq_printf(swap, "%-39s %s\t%d\t%d\t%d\n",
+       seq_printf(swap, "%-39s %s\t%d\t%ld\t%d\n",
                       path,
                       S_ISBLK(file->f_dentry->d_inode->i_mode) ?
                                "partition" : "file\t",
                       ptr->pages << (PAGE_SHIFT - 10),
-                      usedswap << (PAGE_SHIFT - 10),
+                      ptr->inuse_pages << (PAGE_SHIFT - 10),
                       ptr->prio);
        return 0;
 }
@@ -1210,6 +1203,7 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
        p->lowest_bit = 0;
        p->highest_bit = 0;
        p->cluster_nr = 0;
+       p->inuse_pages = 0;
        p->sdev_lock = SPIN_LOCK_UNLOCKED;
        p->next = -1;
        if (swap_flags & SWAP_FLAG_PREFER) {
@@ -1419,19 +1413,10 @@ void si_swapinfo(struct sysinfo *val)
 
        swap_list_lock();
        for (i = 0; i < nr_swapfiles; i++) {
-               unsigned int j;
                if (!(swap_info[i].flags & SWP_USED) ||
                     (swap_info[i].flags & SWP_WRITEOK))
                        continue;
-               for (j = 0; j < swap_info[i].max; ++j) {
-                       switch (swap_info[i].swap_map[j]) {
-                               case 0:
-                               case SWAP_MAP_BAD:
-                                       continue;
-                               default:
-                                       nr_to_be_unused++;
-                       }
-               }
+               nr_to_be_unused += swap_info[i].inuse_pages;
        }
        val->freeswap = nr_swap_pages + nr_to_be_unused;
        val->totalswap = total_swap_pages + nr_to_be_unused;