/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>
This commit is contained in:
committed by
Linus Torvalds
parent
e1ca7788de
commit
66d7dd518a
@@ -30,6 +30,7 @@
|
|||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
#include <linux/syscalls.h>
|
#include <linux/syscalls.h>
|
||||||
#include <linux/memcontrol.h>
|
#include <linux/memcontrol.h>
|
||||||
|
#include <linux/poll.h>
|
||||||
|
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
@@ -58,6 +59,10 @@ static struct swap_info_struct *swap_info[MAX_SWAPFILES];
|
|||||||
|
|
||||||
static DEFINE_MUTEX(swapon_mutex);
|
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)
|
static inline unsigned char swap_count(unsigned char ent)
|
||||||
{
|
{
|
||||||
return ent & ~SWAP_HAS_CACHE; /* may include SWAP_HAS_CONT flag */
|
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);
|
filp_close(swap_file, NULL);
|
||||||
err = 0;
|
err = 0;
|
||||||
|
atomic_inc(&proc_poll_event);
|
||||||
|
wake_up_interruptible(&proc_poll_wait);
|
||||||
|
|
||||||
out_dput:
|
out_dput:
|
||||||
filp_close(victim, NULL);
|
filp_close(victim, NULL);
|
||||||
@@ -1688,6 +1695,25 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#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 */
|
/* iterator */
|
||||||
static void *swap_start(struct seq_file *swap, loff_t *pos)
|
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)
|
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 = {
|
static const struct file_operations proc_swaps_operations = {
|
||||||
@@ -1779,6 +1822,7 @@ static const struct file_operations proc_swaps_operations = {
|
|||||||
.read = seq_read,
|
.read = seq_read,
|
||||||
.llseek = seq_lseek,
|
.llseek = seq_lseek,
|
||||||
.release = seq_release,
|
.release = seq_release,
|
||||||
|
.poll = swaps_poll,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init procswaps_init(void)
|
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;
|
swap_info[prev]->next = type;
|
||||||
spin_unlock(&swap_lock);
|
spin_unlock(&swap_lock);
|
||||||
mutex_unlock(&swapon_mutex);
|
mutex_unlock(&swapon_mutex);
|
||||||
|
atomic_inc(&proc_poll_event);
|
||||||
|
wake_up_interruptible(&proc_poll_wait);
|
||||||
|
|
||||||
error = 0;
|
error = 0;
|
||||||
goto out;
|
goto out;
|
||||||
bad_swap:
|
bad_swap:
|
||||||
|
Reference in New Issue
Block a user