Skip to content

Commit 5addc5d

Browse files
Al ViroLinus Torvalds
authored andcommitted
[PATCH] make /proc/mounts pollable
Signed-off-by: Al Viro <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 1abe77b commit 5addc5d

File tree

3 files changed

+78
-16
lines changed

3 files changed

+78
-16
lines changed

fs/namespace.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ static inline int sysfs_init(void)
3737
#endif
3838

3939
/* 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+
42+
static int event;
4143

4244
static struct list_head *mount_hashtable;
4345
static int hash_mask __read_mostly, hash_bits __read_mostly;
@@ -111,6 +113,22 @@ static inline int check_mnt(struct vfsmount *mnt)
111113
return mnt->mnt_namespace == current->namespace;
112114
}
113115

116+
static void touch_namespace(struct namespace *ns)
117+
{
118+
if (ns) {
119+
ns->event = ++event;
120+
wake_up_interruptible(&ns->poll);
121+
}
122+
}
123+
124+
static 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+
114132
static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd)
115133
{
116134
old_nd->dentry = mnt->mnt_mountpoint;
@@ -384,6 +402,7 @@ static void umount_tree(struct vfsmount *mnt)
384402
for (p = mnt; p; p = next_mnt(p, mnt)) {
385403
list_del(&p->mnt_list);
386404
list_add(&p->mnt_list, &kill);
405+
__touch_namespace(p->mnt_namespace);
387406
p->mnt_namespace = NULL;
388407
}
389408

@@ -473,6 +492,7 @@ static int do_umount(struct vfsmount *mnt, int flags)
473492

474493
down_write(&current->namespace->sem);
475494
spin_lock(&vfsmount_lock);
495+
event++;
476496

477497
retval = -EBUSY;
478498
if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) {
@@ -634,6 +654,7 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd)
634654
list_splice(&head, current->namespace->list.prev);
635655
mntget(mnt);
636656
err = 0;
657+
touch_namespace(current->namespace);
637658
}
638659
spin_unlock(&vfsmount_lock);
639660
out_unlock:
@@ -771,6 +792,7 @@ static int do_move_mount(struct nameidata *nd, char *old_name)
771792

772793
detach_mnt(old_nd.mnt, &parent_nd);
773794
attach_mnt(old_nd.mnt, nd);
795+
touch_namespace(current->namespace);
774796

775797
/* if the mount is moved, it should no longer be expire
776798
* automatically */
@@ -877,6 +899,7 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts)
877899
struct nameidata old_nd;
878900

879901
/* delete from the namespace */
902+
touch_namespace(mnt->mnt_namespace);
880903
list_del_init(&mnt->mnt_list);
881904
mnt->mnt_namespace = NULL;
882905
detach_mnt(mnt, &old_nd);
@@ -1114,6 +1137,8 @@ int copy_namespace(int flags, struct task_struct *tsk)
11141137
atomic_set(&new_ns->count, 1);
11151138
init_rwsem(&new_ns->sem);
11161139
INIT_LIST_HEAD(&new_ns->list);
1140+
init_waitqueue_head(&new_ns->poll);
1141+
new_ns->event = 0;
11171142

11181143
down_write(&tsk->namespace->sem);
11191144
/* First pass: copy the tree topology */
@@ -1377,6 +1402,7 @@ asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *p
13771402
detach_mnt(user_nd.mnt, &root_parent);
13781403
attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */
13791404
attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */
1405+
touch_namespace(current->namespace);
13801406
spin_unlock(&vfsmount_lock);
13811407
chroot_fs_refs(&user_nd, &new_nd);
13821408
security_sb_post_pivotroot(&user_nd, &new_nd);
@@ -1413,6 +1439,8 @@ static void __init init_mount_tree(void)
14131439
atomic_set(&namespace->count, 1);
14141440
INIT_LIST_HEAD(&namespace->list);
14151441
init_rwsem(&namespace->sem);
1442+
init_waitqueue_head(&namespace->poll);
1443+
namespace->event = 0;
14161444
list_add(&mnt->mnt_list, &namespace->list);
14171445
namespace->root = mnt;
14181446
mnt->mnt_namespace = namespace;

fs/proc/base.c

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
#include <linux/seccomp.h>
7171
#include <linux/cpuset.h>
7272
#include <linux/audit.h>
73+
#include <linux/poll.h>
7374
#include "internal.h"
7475

7576
/*
@@ -660,26 +661,38 @@ static struct file_operations proc_smaps_operations = {
660661
#endif
661662

662663
extern struct seq_operations mounts_op;
664+
struct proc_mounts {
665+
struct seq_file m;
666+
int event;
667+
};
668+
663669
static int mounts_open(struct inode *inode, struct file *file)
664670
{
665671
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;
667675

668-
if (!ret) {
669-
struct seq_file *m = file->private_data;
670-
struct namespace *namespace;
671-
task_lock(task);
672-
namespace = task->namespace;
673-
if (namespace)
674-
get_namespace(namespace);
675-
task_unlock(task);
676-
677-
if (namespace)
678-
m->private = namespace;
679-
else {
680-
seq_release(inode, file);
681-
ret = -EINVAL;
676+
task_lock(task);
677+
namespace = task->namespace;
678+
if (namespace)
679+
get_namespace(namespace);
680+
task_unlock(task);
681+
682+
if (namespace) {
683+
ret = -ENOMEM;
684+
p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
685+
if (p) {
686+
file->private_data = &p->m;
687+
ret = seq_open(file, &mounts_op);
688+
if (!ret) {
689+
p->m.private = namespace;
690+
p->event = namespace->event;
691+
return 0;
692+
}
693+
kfree(p);
682694
}
695+
put_namespace(namespace);
683696
}
684697
return ret;
685698
}
@@ -692,11 +705,30 @@ static int mounts_release(struct inode *inode, struct file *file)
692705
return seq_release(inode, file);
693706
}
694707

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+
695726
static struct file_operations proc_mounts_operations = {
696727
.open = mounts_open,
697728
.read = seq_read,
698729
.llseek = seq_lseek,
699730
.release = mounts_release,
731+
.poll = mounts_poll,
700732
};
701733

702734
#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */

include/linux/namespace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ struct namespace {
1010
struct vfsmount * root;
1111
struct list_head list;
1212
struct rw_semaphore sem;
13+
wait_queue_head_t poll;
14+
int event;
1315
};
1416

1517
extern int copy_namespace(int, struct task_struct *);

0 commit comments

Comments
 (0)