Commit fbe7559b authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] realtime swapspace accounting

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.
parent ac3b0460
...@@ -121,6 +121,7 @@ struct swap_info_struct { ...@@ -121,6 +121,7 @@ struct swap_info_struct {
int prio; /* swap priority */ int prio; /* swap priority */
int pages; int pages;
unsigned long max; unsigned long max;
unsigned long inuse_pages;
int next; /* next entry on swap list */ int next; /* next entry on swap list */
}; };
......
...@@ -93,6 +93,7 @@ static inline int scan_swap_map(struct swap_info_struct *si) ...@@ -93,6 +93,7 @@ static inline int scan_swap_map(struct swap_info_struct *si)
si->highest_bit = 0; si->highest_bit = 0;
} }
si->swap_map[offset] = 1; si->swap_map[offset] = 1;
si->inuse_pages++;
nr_swap_pages--; nr_swap_pages--;
si->cluster_next = offset+1; si->cluster_next = offset+1;
return offset; return offset;
...@@ -208,6 +209,7 @@ static int swap_entry_free(struct swap_info_struct *p, unsigned long offset) ...@@ -208,6 +209,7 @@ static int swap_entry_free(struct swap_info_struct *p, unsigned long offset)
if (offset > p->highest_bit) if (offset > p->highest_bit)
p->highest_bit = offset; p->highest_bit = offset;
nr_swap_pages++; nr_swap_pages++;
p->inuse_pages--;
} }
} }
return count; return count;
...@@ -1104,7 +1106,6 @@ static void swap_stop(struct seq_file *swap, void *v) ...@@ -1104,7 +1106,6 @@ static void swap_stop(struct seq_file *swap, void *v)
static int swap_show(struct seq_file *swap, void *v) static int swap_show(struct seq_file *swap, void *v)
{ {
struct swap_info_struct *ptr = v; struct swap_info_struct *ptr = v;
int j, usedswap;
struct file *file; struct file *file;
char *path; char *path;
...@@ -1114,20 +1115,12 @@ static int swap_show(struct seq_file *swap, void *v) ...@@ -1114,20 +1115,12 @@ static int swap_show(struct seq_file *swap, void *v)
file = ptr->swap_file; file = ptr->swap_file;
path = d_path(file->f_dentry, file->f_vfsmnt, swap->private, PAGE_SIZE); path = d_path(file->f_dentry, file->f_vfsmnt, swap->private, PAGE_SIZE);
for (j = 0, usedswap = 0; j < ptr->max; ++j) seq_printf(swap, "%-39s %s\t%d\t%ld\t%d\n",
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",
path, path,
S_ISBLK(file->f_dentry->d_inode->i_mode) ? S_ISBLK(file->f_dentry->d_inode->i_mode) ?
"partition" : "file\t", "partition" : "file\t",
ptr->pages << (PAGE_SHIFT - 10), ptr->pages << (PAGE_SHIFT - 10),
usedswap << (PAGE_SHIFT - 10), ptr->inuse_pages << (PAGE_SHIFT - 10),
ptr->prio); ptr->prio);
return 0; return 0;
} }
...@@ -1210,6 +1203,7 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags) ...@@ -1210,6 +1203,7 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
p->lowest_bit = 0; p->lowest_bit = 0;
p->highest_bit = 0; p->highest_bit = 0;
p->cluster_nr = 0; p->cluster_nr = 0;
p->inuse_pages = 0;
p->sdev_lock = SPIN_LOCK_UNLOCKED; p->sdev_lock = SPIN_LOCK_UNLOCKED;
p->next = -1; p->next = -1;
if (swap_flags & SWAP_FLAG_PREFER) { if (swap_flags & SWAP_FLAG_PREFER) {
...@@ -1419,19 +1413,10 @@ void si_swapinfo(struct sysinfo *val) ...@@ -1419,19 +1413,10 @@ void si_swapinfo(struct sysinfo *val)
swap_list_lock(); swap_list_lock();
for (i = 0; i < nr_swapfiles; i++) { for (i = 0; i < nr_swapfiles; i++) {
unsigned int j;
if (!(swap_info[i].flags & SWP_USED) || if (!(swap_info[i].flags & SWP_USED) ||
(swap_info[i].flags & SWP_WRITEOK)) (swap_info[i].flags & SWP_WRITEOK))
continue; continue;
for (j = 0; j < swap_info[i].max; ++j) { nr_to_be_unused += swap_info[i].inuse_pages;
switch (swap_info[i].swap_map[j]) {
case 0:
case SWAP_MAP_BAD:
continue;
default:
nr_to_be_unused++;
}
}
} }
val->freeswap = nr_swap_pages + nr_to_be_unused; val->freeswap = nr_swap_pages + nr_to_be_unused;
val->totalswap = total_swap_pages + nr_to_be_unused; val->totalswap = total_swap_pages + nr_to_be_unused;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment