diff options
author | Kay Sievers <kay.sievers@vrfy.org> | 2010-10-26 17:22:06 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 19:52:11 -0400 |
commit | 66d7dd518ae413a383ab2c6c263cc30617329842 (patch) | |
tree | 8e16f734aebba063e0df052825ac375aefeeab5a /mm | |
parent | e1ca7788dec6773b1a2bce51b7141948f2b8bccf (diff) |
/proc/swaps: support polling
System management wants to subscribe to changes in swap configuration.
Make /proc/swaps pollable like /proc/mounts.
[akpm@linux-foundation.org: document proc_poll_event]
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Acked-by: Greg KH <greg@kroah.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/swapfile.c | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c index 9fc7bac7db0c..67ddaaf98c74 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/capability.h> | 30 | #include <linux/capability.h> |
31 | #include <linux/syscalls.h> | 31 | #include <linux/syscalls.h> |
32 | #include <linux/memcontrol.h> | 32 | #include <linux/memcontrol.h> |
33 | #include <linux/poll.h> | ||
33 | 34 | ||
34 | #include <asm/pgtable.h> | 35 | #include <asm/pgtable.h> |
35 | #include <asm/tlbflush.h> | 36 | #include <asm/tlbflush.h> |
@@ -58,6 +59,10 @@ static struct swap_info_struct *swap_info[MAX_SWAPFILES]; | |||
58 | 59 | ||
59 | static DEFINE_MUTEX(swapon_mutex); | 60 | static DEFINE_MUTEX(swapon_mutex); |
60 | 61 | ||
62 | static DECLARE_WAIT_QUEUE_HEAD(proc_poll_wait); | ||
63 | /* Activity counter to indicate that a swapon or swapoff has occurred */ | ||
64 | static atomic_t proc_poll_event = ATOMIC_INIT(0); | ||
65 | |||
61 | static inline unsigned char swap_count(unsigned char ent) | 66 | static inline unsigned char swap_count(unsigned char ent) |
62 | { | 67 | { |
63 | return ent & ~SWAP_HAS_CACHE; /* may include SWAP_HAS_CONT flag */ | 68 | return ent & ~SWAP_HAS_CACHE; /* may include SWAP_HAS_CONT flag */ |
@@ -1680,6 +1685,8 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) | |||
1680 | } | 1685 | } |
1681 | filp_close(swap_file, NULL); | 1686 | filp_close(swap_file, NULL); |
1682 | err = 0; | 1687 | err = 0; |
1688 | atomic_inc(&proc_poll_event); | ||
1689 | wake_up_interruptible(&proc_poll_wait); | ||
1683 | 1690 | ||
1684 | out_dput: | 1691 | out_dput: |
1685 | filp_close(victim, NULL); | 1692 | filp_close(victim, NULL); |
@@ -1688,6 +1695,25 @@ out: | |||
1688 | } | 1695 | } |
1689 | 1696 | ||
1690 | #ifdef CONFIG_PROC_FS | 1697 | #ifdef CONFIG_PROC_FS |
1698 | struct proc_swaps { | ||
1699 | struct seq_file seq; | ||
1700 | int event; | ||
1701 | }; | ||
1702 | |||
1703 | static unsigned swaps_poll(struct file *file, poll_table *wait) | ||
1704 | { | ||
1705 | struct proc_swaps *s = file->private_data; | ||
1706 | |||
1707 | poll_wait(file, &proc_poll_wait, wait); | ||
1708 | |||
1709 | if (s->event != atomic_read(&proc_poll_event)) { | ||
1710 | s->event = atomic_read(&proc_poll_event); | ||
1711 | return POLLIN | POLLRDNORM | POLLERR | POLLPRI; | ||
1712 | } | ||
1713 | |||
1714 | return POLLIN | POLLRDNORM; | ||
1715 | } | ||
1716 | |||
1691 | /* iterator */ | 1717 | /* iterator */ |
1692 | static void *swap_start(struct seq_file *swap, loff_t *pos) | 1718 | static void *swap_start(struct seq_file *swap, loff_t *pos) |
1693 | { | 1719 | { |
@@ -1771,7 +1797,24 @@ static const struct seq_operations swaps_op = { | |||
1771 | 1797 | ||
1772 | static int swaps_open(struct inode *inode, struct file *file) | 1798 | static int swaps_open(struct inode *inode, struct file *file) |
1773 | { | 1799 | { |
1774 | return seq_open(file, &swaps_op); | 1800 | struct proc_swaps *s; |
1801 | int ret; | ||
1802 | |||
1803 | s = kmalloc(sizeof(struct proc_swaps), GFP_KERNEL); | ||
1804 | if (!s) | ||
1805 | return -ENOMEM; | ||
1806 | |||
1807 | file->private_data = s; | ||
1808 | |||
1809 | ret = seq_open(file, &swaps_op); | ||
1810 | if (ret) { | ||
1811 | kfree(s); | ||
1812 | return ret; | ||
1813 | } | ||
1814 | |||
1815 | s->seq.private = s; | ||
1816 | s->event = atomic_read(&proc_poll_event); | ||
1817 | return ret; | ||
1775 | } | 1818 | } |
1776 | 1819 | ||
1777 | static const struct file_operations proc_swaps_operations = { | 1820 | static const struct file_operations proc_swaps_operations = { |
@@ -1779,6 +1822,7 @@ static const struct file_operations proc_swaps_operations = { | |||
1779 | .read = seq_read, | 1822 | .read = seq_read, |
1780 | .llseek = seq_lseek, | 1823 | .llseek = seq_lseek, |
1781 | .release = seq_release, | 1824 | .release = seq_release, |
1825 | .poll = swaps_poll, | ||
1782 | }; | 1826 | }; |
1783 | 1827 | ||
1784 | static int __init procswaps_init(void) | 1828 | static int __init procswaps_init(void) |
@@ -2084,6 +2128,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) | |||
2084 | swap_info[prev]->next = type; | 2128 | swap_info[prev]->next = type; |
2085 | spin_unlock(&swap_lock); | 2129 | spin_unlock(&swap_lock); |
2086 | mutex_unlock(&swapon_mutex); | 2130 | mutex_unlock(&swapon_mutex); |
2131 | atomic_inc(&proc_poll_event); | ||
2132 | wake_up_interruptible(&proc_poll_wait); | ||
2133 | |||
2087 | error = 0; | 2134 | error = 0; |
2088 | goto out; | 2135 | goto out; |
2089 | bad_swap: | 2136 | bad_swap: |