diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/base.c | 62 |
1 files changed, 47 insertions, 15 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index a170450aadb1..634355e16986 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -70,6 +70,7 @@ | |||
70 | #include <linux/seccomp.h> | 70 | #include <linux/seccomp.h> |
71 | #include <linux/cpuset.h> | 71 | #include <linux/cpuset.h> |
72 | #include <linux/audit.h> | 72 | #include <linux/audit.h> |
73 | #include <linux/poll.h> | ||
73 | #include "internal.h" | 74 | #include "internal.h" |
74 | 75 | ||
75 | /* | 76 | /* |
@@ -660,26 +661,38 @@ static struct file_operations proc_smaps_operations = { | |||
660 | #endif | 661 | #endif |
661 | 662 | ||
662 | extern struct seq_operations mounts_op; | 663 | extern struct seq_operations mounts_op; |
664 | struct proc_mounts { | ||
665 | struct seq_file m; | ||
666 | int event; | ||
667 | }; | ||
668 | |||
663 | static int mounts_open(struct inode *inode, struct file *file) | 669 | static int mounts_open(struct inode *inode, struct file *file) |
664 | { | 670 | { |
665 | struct task_struct *task = proc_task(inode); | 671 | struct task_struct *task = proc_task(inode); |
666 | int ret = seq_open(file, &mounts_op); | 672 | struct namespace *namespace; |
673 | struct proc_mounts *p; | ||
674 | int ret = -EINVAL; | ||
667 | 675 | ||
668 | if (!ret) { | 676 | task_lock(task); |
669 | struct seq_file *m = file->private_data; | 677 | namespace = task->namespace; |
670 | struct namespace *namespace; | 678 | if (namespace) |
671 | task_lock(task); | 679 | get_namespace(namespace); |
672 | namespace = task->namespace; | 680 | task_unlock(task); |
673 | if (namespace) | 681 | |
674 | get_namespace(namespace); | 682 | if (namespace) { |
675 | task_unlock(task); | 683 | ret = -ENOMEM; |
676 | 684 | p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); | |
677 | if (namespace) | 685 | if (p) { |
678 | m->private = namespace; | 686 | file->private_data = &p->m; |
679 | else { | 687 | ret = seq_open(file, &mounts_op); |
680 | seq_release(inode, file); | 688 | if (!ret) { |
681 | ret = -EINVAL; | 689 | p->m.private = namespace; |
690 | p->event = namespace->event; | ||
691 | return 0; | ||
692 | } | ||
693 | kfree(p); | ||
682 | } | 694 | } |
695 | put_namespace(namespace); | ||
683 | } | 696 | } |
684 | return ret; | 697 | return ret; |
685 | } | 698 | } |
@@ -692,11 +705,30 @@ static int mounts_release(struct inode *inode, struct file *file) | |||
692 | return seq_release(inode, file); | 705 | return seq_release(inode, file); |
693 | } | 706 | } |
694 | 707 | ||
708 | static unsigned mounts_poll(struct file *file, poll_table *wait) | ||
709 | { | ||
710 | struct proc_mounts *p = file->private_data; | ||
711 | struct namespace *ns = p->m.private; | ||
712 | unsigned res = 0; | ||
713 | |||
714 | poll_wait(file, &ns->poll, wait); | ||
715 | |||
716 | spin_lock(&vfsmount_lock); | ||
717 | if (p->event != ns->event) { | ||
718 | p->event = ns->event; | ||
719 | res = POLLERR; | ||
720 | } | ||
721 | spin_unlock(&vfsmount_lock); | ||
722 | |||
723 | return res; | ||
724 | } | ||
725 | |||
695 | static struct file_operations proc_mounts_operations = { | 726 | static struct file_operations proc_mounts_operations = { |
696 | .open = mounts_open, | 727 | .open = mounts_open, |
697 | .read = seq_read, | 728 | .read = seq_read, |
698 | .llseek = seq_lseek, | 729 | .llseek = seq_lseek, |
699 | .release = mounts_release, | 730 | .release = mounts_release, |
731 | .poll = mounts_poll, | ||
700 | }; | 732 | }; |
701 | 733 | ||
702 | #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ | 734 | #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ |