aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2005-11-07 17:15:49 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 21:18:10 -0500
commit5addc5dd8836aa061f6efc4a0d9ba6323726297a (patch)
treea5ce3703bbb421c93482b6043ebd57137276808f /fs
parent1abe77b0fc4b485927f1f798ae81a752677e1d05 (diff)
[PATCH] make /proc/mounts pollable
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/namespace.c30
-rw-r--r--fs/proc/base.c62
2 files changed, 76 insertions, 16 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 611f777bbd61..d1aca685aacf 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -37,7 +37,9 @@ static inline int sysfs_init(void)
37#endif 37#endif
38 38
39/* spinlock for vfsmount related operations, inplace of dcache_lock */ 39/* spinlock for vfsmount related operations, inplace of dcache_lock */
40 __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); 40__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
41
42static int event;
41 43
42static struct list_head *mount_hashtable; 44static struct list_head *mount_hashtable;
43static int hash_mask __read_mostly, hash_bits __read_mostly; 45static int hash_mask __read_mostly, hash_bits __read_mostly;
@@ -111,6 +113,22 @@ static inline int check_mnt(struct vfsmount *mnt)
111 return mnt->mnt_namespace == current->namespace; 113 return mnt->mnt_namespace == current->namespace;
112} 114}
113 115
116static void touch_namespace(struct namespace *ns)
117{
118 if (ns) {
119 ns->event = ++event;
120 wake_up_interruptible(&ns->poll);
121 }
122}
123
124static void __touch_namespace(struct namespace *ns)
125{
126 if (ns && ns->event != event) {
127 ns->event = event;
128 wake_up_interruptible(&ns->poll);
129 }
130}
131
114static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd) 132static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd)
115{ 133{
116 old_nd->dentry = mnt->mnt_mountpoint; 134 old_nd->dentry = mnt->mnt_mountpoint;
@@ -384,6 +402,7 @@ static void umount_tree(struct vfsmount *mnt)
384 for (p = mnt; p; p = next_mnt(p, mnt)) { 402 for (p = mnt; p; p = next_mnt(p, mnt)) {
385 list_del(&p->mnt_list); 403 list_del(&p->mnt_list);
386 list_add(&p->mnt_list, &kill); 404 list_add(&p->mnt_list, &kill);
405 __touch_namespace(p->mnt_namespace);
387 p->mnt_namespace = NULL; 406 p->mnt_namespace = NULL;
388 } 407 }
389 408
@@ -473,6 +492,7 @@ static int do_umount(struct vfsmount *mnt, int flags)
473 492
474 down_write(&current->namespace->sem); 493 down_write(&current->namespace->sem);
475 spin_lock(&vfsmount_lock); 494 spin_lock(&vfsmount_lock);
495 event++;
476 496
477 retval = -EBUSY; 497 retval = -EBUSY;
478 if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) { 498 if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) {
@@ -634,6 +654,7 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd)
634 list_splice(&head, current->namespace->list.prev); 654 list_splice(&head, current->namespace->list.prev);
635 mntget(mnt); 655 mntget(mnt);
636 err = 0; 656 err = 0;
657 touch_namespace(current->namespace);
637 } 658 }
638 spin_unlock(&vfsmount_lock); 659 spin_unlock(&vfsmount_lock);
639out_unlock: 660out_unlock:
@@ -771,6 +792,7 @@ static int do_move_mount(struct nameidata *nd, char *old_name)
771 792
772 detach_mnt(old_nd.mnt, &parent_nd); 793 detach_mnt(old_nd.mnt, &parent_nd);
773 attach_mnt(old_nd.mnt, nd); 794 attach_mnt(old_nd.mnt, nd);
795 touch_namespace(current->namespace);
774 796
775 /* if the mount is moved, it should no longer be expire 797 /* if the mount is moved, it should no longer be expire
776 * automatically */ 798 * automatically */
@@ -877,6 +899,7 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts)
877 struct nameidata old_nd; 899 struct nameidata old_nd;
878 900
879 /* delete from the namespace */ 901 /* delete from the namespace */
902 touch_namespace(mnt->mnt_namespace);
880 list_del_init(&mnt->mnt_list); 903 list_del_init(&mnt->mnt_list);
881 mnt->mnt_namespace = NULL; 904 mnt->mnt_namespace = NULL;
882 detach_mnt(mnt, &old_nd); 905 detach_mnt(mnt, &old_nd);
@@ -1114,6 +1137,8 @@ int copy_namespace(int flags, struct task_struct *tsk)
1114 atomic_set(&new_ns->count, 1); 1137 atomic_set(&new_ns->count, 1);
1115 init_rwsem(&new_ns->sem); 1138 init_rwsem(&new_ns->sem);
1116 INIT_LIST_HEAD(&new_ns->list); 1139 INIT_LIST_HEAD(&new_ns->list);
1140 init_waitqueue_head(&new_ns->poll);
1141 new_ns->event = 0;
1117 1142
1118 down_write(&tsk->namespace->sem); 1143 down_write(&tsk->namespace->sem);
1119 /* First pass: copy the tree topology */ 1144 /* First pass: copy the tree topology */
@@ -1377,6 +1402,7 @@ asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *p
1377 detach_mnt(user_nd.mnt, &root_parent); 1402 detach_mnt(user_nd.mnt, &root_parent);
1378 attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */ 1403 attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */
1379 attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */ 1404 attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */
1405 touch_namespace(current->namespace);
1380 spin_unlock(&vfsmount_lock); 1406 spin_unlock(&vfsmount_lock);
1381 chroot_fs_refs(&user_nd, &new_nd); 1407 chroot_fs_refs(&user_nd, &new_nd);
1382 security_sb_post_pivotroot(&user_nd, &new_nd); 1408 security_sb_post_pivotroot(&user_nd, &new_nd);
@@ -1413,6 +1439,8 @@ static void __init init_mount_tree(void)
1413 atomic_set(&namespace->count, 1); 1439 atomic_set(&namespace->count, 1);
1414 INIT_LIST_HEAD(&namespace->list); 1440 INIT_LIST_HEAD(&namespace->list);
1415 init_rwsem(&namespace->sem); 1441 init_rwsem(&namespace->sem);
1442 init_waitqueue_head(&namespace->poll);
1443 namespace->event = 0;
1416 list_add(&mnt->mnt_list, &namespace->list); 1444 list_add(&mnt->mnt_list, &namespace->list);
1417 namespace->root = mnt; 1445 namespace->root = mnt;
1418 mnt->mnt_namespace = namespace; 1446 mnt->mnt_namespace = namespace;
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
662extern struct seq_operations mounts_op; 663extern struct seq_operations mounts_op;
664struct proc_mounts {
665 struct seq_file m;
666 int event;
667};
668
663static int mounts_open(struct inode *inode, struct file *file) 669static 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
708static 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
695static struct file_operations proc_mounts_operations = { 726static 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 */