aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/namespace.c14
-rw-r--r--fs/proc/base.c108
-rw-r--r--include/linux/mnt_namespace.h11
3 files changed, 70 insertions, 63 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index cefa1d9939b0..dfdf51e81c1c 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -724,20 +724,21 @@ void save_mount_options(struct super_block *sb, char *options)
724} 724}
725EXPORT_SYMBOL(save_mount_options); 725EXPORT_SYMBOL(save_mount_options);
726 726
727#ifdef CONFIG_PROC_FS
727/* iterator */ 728/* iterator */
728static void *m_start(struct seq_file *m, loff_t *pos) 729static void *m_start(struct seq_file *m, loff_t *pos)
729{ 730{
730 struct mnt_namespace *n = m->private; 731 struct proc_mounts *p = m->private;
731 732
732 down_read(&namespace_sem); 733 down_read(&namespace_sem);
733 return seq_list_start(&n->list, *pos); 734 return seq_list_start(&p->ns->list, *pos);
734} 735}
735 736
736static void *m_next(struct seq_file *m, void *v, loff_t *pos) 737static void *m_next(struct seq_file *m, void *v, loff_t *pos)
737{ 738{
738 struct mnt_namespace *n = m->private; 739 struct proc_mounts *p = m->private;
739 740
740 return seq_list_next(v, &n->list, pos); 741 return seq_list_next(v, &p->ns->list, pos);
741} 742}
742 743
743static void m_stop(struct seq_file *m, void *v) 744static void m_stop(struct seq_file *m, void *v)
@@ -794,7 +795,7 @@ static int show_vfsmnt(struct seq_file *m, void *v)
794 return err; 795 return err;
795} 796}
796 797
797struct seq_operations mounts_op = { 798const struct seq_operations mounts_op = {
798 .start = m_start, 799 .start = m_start,
799 .next = m_next, 800 .next = m_next,
800 .stop = m_stop, 801 .stop = m_stop,
@@ -833,12 +834,13 @@ static int show_vfsstat(struct seq_file *m, void *v)
833 return err; 834 return err;
834} 835}
835 836
836struct seq_operations mountstats_op = { 837const struct seq_operations mountstats_op = {
837 .start = m_start, 838 .start = m_start,
838 .next = m_next, 839 .next = m_next,
839 .stop = m_stop, 840 .stop = m_stop,
840 .show = show_vfsstat, 841 .show = show_vfsstat,
841}; 842};
843#endif /* CONFIG_PROC_FS */
842 844
843/** 845/**
844 * may_umount_tree - check if a mount tree is busy 846 * may_umount_tree - check if a mount tree is busy
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 7313c62e3e9d..a04b3db7a296 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -502,17 +502,14 @@ static const struct inode_operations proc_def_inode_operations = {
502 .setattr = proc_setattr, 502 .setattr = proc_setattr,
503}; 503};
504 504
505extern const struct seq_operations mounts_op; 505static int mounts_open_common(struct inode *inode, struct file *file,
506struct proc_mounts { 506 const struct seq_operations *op)
507 struct seq_file m;
508 int event;
509};
510
511static int mounts_open(struct inode *inode, struct file *file)
512{ 507{
513 struct task_struct *task = get_proc_task(inode); 508 struct task_struct *task = get_proc_task(inode);
514 struct nsproxy *nsp; 509 struct nsproxy *nsp;
515 struct mnt_namespace *ns = NULL; 510 struct mnt_namespace *ns = NULL;
511 struct fs_struct *fs = NULL;
512 struct path root;
516 struct proc_mounts *p; 513 struct proc_mounts *p;
517 int ret = -EINVAL; 514 int ret = -EINVAL;
518 515
@@ -525,40 +522,61 @@ static int mounts_open(struct inode *inode, struct file *file)
525 get_mnt_ns(ns); 522 get_mnt_ns(ns);
526 } 523 }
527 rcu_read_unlock(); 524 rcu_read_unlock();
528 525 if (ns)
526 fs = get_fs_struct(task);
529 put_task_struct(task); 527 put_task_struct(task);
530 } 528 }
531 529
532 if (ns) { 530 if (!ns)
533 ret = -ENOMEM; 531 goto err;
534 p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); 532 if (!fs)
535 if (p) { 533 goto err_put_ns;
536 file->private_data = &p->m; 534
537 ret = seq_open(file, &mounts_op); 535 read_lock(&fs->lock);
538 if (!ret) { 536 root = fs->root;
539 p->m.private = ns; 537 path_get(&root);
540 p->event = ns->event; 538 read_unlock(&fs->lock);
541 return 0; 539 put_fs_struct(fs);
542 } 540
543 kfree(p); 541 ret = -ENOMEM;
544 } 542 p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
545 put_mnt_ns(ns); 543 if (!p)
546 } 544 goto err_put_path;
545
546 file->private_data = &p->m;
547 ret = seq_open(file, op);
548 if (ret)
549 goto err_free;
550
551 p->m.private = p;
552 p->ns = ns;
553 p->root = root;
554 p->event = ns->event;
555
556 return 0;
557
558 err_free:
559 kfree(p);
560 err_put_path:
561 path_put(&root);
562 err_put_ns:
563 put_mnt_ns(ns);
564 err:
547 return ret; 565 return ret;
548} 566}
549 567
550static int mounts_release(struct inode *inode, struct file *file) 568static int mounts_release(struct inode *inode, struct file *file)
551{ 569{
552 struct seq_file *m = file->private_data; 570 struct proc_mounts *p = file->private_data;
553 struct mnt_namespace *ns = m->private; 571 path_put(&p->root);
554 put_mnt_ns(ns); 572 put_mnt_ns(p->ns);
555 return seq_release(inode, file); 573 return seq_release(inode, file);
556} 574}
557 575
558static unsigned mounts_poll(struct file *file, poll_table *wait) 576static unsigned mounts_poll(struct file *file, poll_table *wait)
559{ 577{
560 struct proc_mounts *p = file->private_data; 578 struct proc_mounts *p = file->private_data;
561 struct mnt_namespace *ns = p->m.private; 579 struct mnt_namespace *ns = p->ns;
562 unsigned res = 0; 580 unsigned res = 0;
563 581
564 poll_wait(file, &ns->poll, wait); 582 poll_wait(file, &ns->poll, wait);
@@ -573,6 +591,11 @@ static unsigned mounts_poll(struct file *file, poll_table *wait)
573 return res; 591 return res;
574} 592}
575 593
594static int mounts_open(struct inode *inode, struct file *file)
595{
596 return mounts_open_common(inode, file, &mounts_op);
597}
598
576static const struct file_operations proc_mounts_operations = { 599static const struct file_operations proc_mounts_operations = {
577 .open = mounts_open, 600 .open = mounts_open,
578 .read = seq_read, 601 .read = seq_read,
@@ -581,38 +604,9 @@ static const struct file_operations proc_mounts_operations = {
581 .poll = mounts_poll, 604 .poll = mounts_poll,
582}; 605};
583 606
584extern const struct seq_operations mountstats_op;
585static int mountstats_open(struct inode *inode, struct file *file) 607static int mountstats_open(struct inode *inode, struct file *file)
586{ 608{
587 int ret = seq_open(file, &mountstats_op); 609 return mounts_open_common(inode, file, &mountstats_op);
588
589 if (!ret) {
590 struct seq_file *m = file->private_data;
591 struct nsproxy *nsp;
592 struct mnt_namespace *mnt_ns = NULL;
593 struct task_struct *task = get_proc_task(inode);
594
595 if (task) {
596 rcu_read_lock();
597 nsp = task_nsproxy(task);
598 if (nsp) {
599 mnt_ns = nsp->mnt_ns;
600 if (mnt_ns)
601 get_mnt_ns(mnt_ns);
602 }
603 rcu_read_unlock();
604
605 put_task_struct(task);
606 }
607
608 if (mnt_ns)
609 m->private = mnt_ns;
610 else {
611 seq_release(inode, file);
612 ret = -EINVAL;
613 }
614 }
615 return ret;
616} 610}
617 611
618static const struct file_operations proc_mountstats_operations = { 612static const struct file_operations proc_mountstats_operations = {
diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h
index 8eed44f8ca73..c078aacc8116 100644
--- a/include/linux/mnt_namespace.h
+++ b/include/linux/mnt_namespace.h
@@ -5,6 +5,7 @@
5#include <linux/mount.h> 5#include <linux/mount.h>
6#include <linux/sched.h> 6#include <linux/sched.h>
7#include <linux/nsproxy.h> 7#include <linux/nsproxy.h>
8#include <linux/seq_file.h>
8 9
9struct mnt_namespace { 10struct mnt_namespace {
10 atomic_t count; 11 atomic_t count;
@@ -14,6 +15,13 @@ struct mnt_namespace {
14 int event; 15 int event;
15}; 16};
16 17
18struct proc_mounts {
19 struct seq_file m; /* must be the first element */
20 struct mnt_namespace *ns;
21 struct path root;
22 int event;
23};
24
17extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, 25extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
18 struct fs_struct *); 26 struct fs_struct *);
19extern void __put_mnt_ns(struct mnt_namespace *ns); 27extern void __put_mnt_ns(struct mnt_namespace *ns);
@@ -37,5 +45,8 @@ static inline void get_mnt_ns(struct mnt_namespace *ns)
37 atomic_inc(&ns->count); 45 atomic_inc(&ns->count);
38} 46}
39 47
48extern const struct seq_operations mounts_op;
49extern const struct seq_operations mountstats_op;
50
40#endif 51#endif
41#endif 52#endif