|
@@ -30,6 +30,7 @@
|
|
|
#include <linux/capability.h>
|
|
|
#include <linux/syscalls.h>
|
|
|
#include <linux/memcontrol.h>
|
|
|
+#include <linux/poll.h>
|
|
|
|
|
|
#include <asm/pgtable.h>
|
|
|
#include <asm/tlbflush.h>
|
|
@@ -58,6 +59,10 @@ static struct swap_info_struct *swap_info[MAX_SWAPFILES];
|
|
|
|
|
|
static DEFINE_MUTEX(swapon_mutex);
|
|
|
|
|
|
+static DECLARE_WAIT_QUEUE_HEAD(proc_poll_wait);
|
|
|
+/* Activity counter to indicate that a swapon or swapoff has occurred */
|
|
|
+static atomic_t proc_poll_event = ATOMIC_INIT(0);
|
|
|
+
|
|
|
static inline unsigned char swap_count(unsigned char ent)
|
|
|
{
|
|
|
return ent & ~SWAP_HAS_CACHE; /* may include SWAP_HAS_CONT flag */
|
|
@@ -1680,6 +1685,8 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
|
|
|
}
|
|
|
filp_close(swap_file, NULL);
|
|
|
err = 0;
|
|
|
+ atomic_inc(&proc_poll_event);
|
|
|
+ wake_up_interruptible(&proc_poll_wait);
|
|
|
|
|
|
out_dput:
|
|
|
filp_close(victim, NULL);
|
|
@@ -1688,6 +1695,25 @@ out:
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
|
+struct proc_swaps {
|
|
|
+ struct seq_file seq;
|
|
|
+ int event;
|
|
|
+};
|
|
|
+
|
|
|
+static unsigned swaps_poll(struct file *file, poll_table *wait)
|
|
|
+{
|
|
|
+ struct proc_swaps *s = file->private_data;
|
|
|
+
|
|
|
+ poll_wait(file, &proc_poll_wait, wait);
|
|
|
+
|
|
|
+ if (s->event != atomic_read(&proc_poll_event)) {
|
|
|
+ s->event = atomic_read(&proc_poll_event);
|
|
|
+ return POLLIN | POLLRDNORM | POLLERR | POLLPRI;
|
|
|
+ }
|
|
|
+
|
|
|
+ return POLLIN | POLLRDNORM;
|
|
|
+}
|
|
|
+
|
|
|
/* iterator */
|
|
|
static void *swap_start(struct seq_file *swap, loff_t *pos)
|
|
|
{
|
|
@@ -1771,7 +1797,24 @@ static const struct seq_operations swaps_op = {
|
|
|
|
|
|
static int swaps_open(struct inode *inode, struct file *file)
|
|
|
{
|
|
|
- return seq_open(file, &swaps_op);
|
|
|
+ struct proc_swaps *s;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ s = kmalloc(sizeof(struct proc_swaps), GFP_KERNEL);
|
|
|
+ if (!s)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ file->private_data = s;
|
|
|
+
|
|
|
+ ret = seq_open(file, &swaps_op);
|
|
|
+ if (ret) {
|
|
|
+ kfree(s);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ s->seq.private = s;
|
|
|
+ s->event = atomic_read(&proc_poll_event);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static const struct file_operations proc_swaps_operations = {
|
|
@@ -1779,6 +1822,7 @@ static const struct file_operations proc_swaps_operations = {
|
|
|
.read = seq_read,
|
|
|
.llseek = seq_lseek,
|
|
|
.release = seq_release,
|
|
|
+ .poll = swaps_poll,
|
|
|
};
|
|
|
|
|
|
static int __init procswaps_init(void)
|
|
@@ -2084,6 +2128,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
|
|
|
swap_info[prev]->next = type;
|
|
|
spin_unlock(&swap_lock);
|
|
|
mutex_unlock(&swapon_mutex);
|
|
|
+ atomic_inc(&proc_poll_event);
|
|
|
+ wake_up_interruptible(&proc_poll_wait);
|
|
|
+
|
|
|
error = 0;
|
|
|
goto out;
|
|
|
bad_swap:
|