From 312a2bdd84a72bd20fae2125fdae0fdc37590a2f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Jul 2011 17:32:17 -0400 Subject: [PATCH] --- yaml --- r: 280211 b: refs/heads/master c: 8208a22bb8bd3c52ef634b4ff194f14892ab1713 h: refs/heads/master i: 280209: bb37077e7c882f43b48d9a03fb51be82e0ce0bdf 280207: 3e3203781ce7268b78d22c24c8deb828ae016e3a v: v3 --- [refs] | 2 +- trunk/fs/Makefile | 2 - trunk/fs/dcache.c | 10 +- trunk/fs/fhandle.c | 4 +- trunk/fs/internal.h | 2 +- trunk/fs/mount.h | 71 +-- trunk/fs/namei.c | 41 +- trunk/fs/namespace.c | 689 ++++++++++++++--------- trunk/fs/notify/fanotify/fanotify_user.c | 6 +- trunk/fs/notify/fsnotify.c | 9 +- trunk/fs/notify/vfsmount_mark.c | 19 +- trunk/fs/pnode.c | 105 ++-- trunk/fs/pnode.h | 38 +- trunk/fs/proc/base.c | 114 ++++ trunk/fs/proc/namespaces.c | 1 + trunk/fs/proc_namespace.c | 331 ----------- trunk/include/linux/mnt_namespace.h | 30 +- trunk/include/linux/mount.h | 35 ++ trunk/include/linux/syscalls.h | 4 +- trunk/security/tomoyo/realpath.c | 1 - 20 files changed, 727 insertions(+), 787 deletions(-) delete mode 100644 trunk/fs/proc_namespace.c diff --git a/[refs] b/[refs] index c86d7635c859..bc9c83156e5e 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: d10577a8d86a0c735488d66d32289a6d66bcfa20 +refs/heads/master: 8208a22bb8bd3c52ef634b4ff194f14892ab1713 diff --git a/trunk/fs/Makefile b/trunk/fs/Makefile index 310cfc4e69d3..d2c3353d5477 100644 --- a/trunk/fs/Makefile +++ b/trunk/fs/Makefile @@ -19,8 +19,6 @@ else obj-y += no-block.o endif -obj-$(CONFIG_PROC_FS) += proc_namespace.o - obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o obj-y += notify/ obj-$(CONFIG_EPOLL) += eventpoll.o diff --git a/trunk/fs/dcache.c b/trunk/fs/dcache.c index 9791b1e7eee4..64c8ce4c147f 100644 --- a/trunk/fs/dcache.c +++ b/trunk/fs/dcache.c @@ -2452,7 +2452,6 @@ static int prepend_path(const struct path *path, { struct dentry *dentry = path->dentry; struct vfsmount *vfsmnt = path->mnt; - struct mount *mnt = real_mount(vfsmnt); bool slash = false; int error = 0; @@ -2462,11 +2461,10 @@ static int prepend_path(const struct path *path, if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { /* Global root? */ - if (!mnt_has_parent(mnt)) + if (!mnt_has_parent(vfsmnt)) goto global_root; - dentry = mnt->mnt_mountpoint; - mnt = mnt->mnt_parent; - vfsmnt = &mnt->mnt; + dentry = vfsmnt->mnt_mountpoint; + vfsmnt = vfsmnt->mnt_parent; continue; } parent = dentry->d_parent; @@ -2503,7 +2501,7 @@ static int prepend_path(const struct path *path, if (!slash) error = prepend(buffer, buflen, "/", 1); if (!error) - error = real_mount(vfsmnt)->mnt_ns ? 1 : 2; + error = vfsmnt->mnt_ns ? 1 : 2; goto out; } diff --git a/trunk/fs/fhandle.c b/trunk/fs/fhandle.c index 5eff7116951e..6b088641f5bf 100644 --- a/trunk/fs/fhandle.c +++ b/trunk/fs/fhandle.c @@ -10,7 +10,6 @@ #include #include #include "internal.h" -#include "mount.h" static long do_sys_name_to_handle(struct path *path, struct file_handle __user *ufh, @@ -67,8 +66,7 @@ static long do_sys_name_to_handle(struct path *path, } else retval = 0; /* copy the mount id */ - if (copy_to_user(mnt_id, &real_mount(path->mnt)->mnt_id, - sizeof(*mnt_id)) || + if (copy_to_user(mnt_id, &path->mnt->mnt_id, sizeof(*mnt_id)) || copy_to_user(ufh, handle, sizeof(struct file_handle) + handle_bytes)) retval = -EFAULT; diff --git a/trunk/fs/internal.h b/trunk/fs/internal.h index 6aab61a4f36f..7b1cb1528ac2 100644 --- a/trunk/fs/internal.h +++ b/trunk/fs/internal.h @@ -15,7 +15,6 @@ struct super_block; struct file_system_type; struct linux_binprm; struct path; -struct mount; /* * block_dev.c @@ -47,6 +46,7 @@ extern void __init chrdev_init(void); extern int copy_mount_options(const void __user *, unsigned long *); extern int copy_mount_string(const void __user *, char **); +extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int); extern struct vfsmount *lookup_mnt(struct path *); extern int finish_automount(struct vfsmount *, struct path *); diff --git a/trunk/fs/mount.h b/trunk/fs/mount.h index 0921b51e27e2..7890e49f74ef 100644 --- a/trunk/fs/mount.h +++ b/trunk/fs/mount.h @@ -1,75 +1,6 @@ #include -#include -#include -struct mnt_namespace { - atomic_t count; - struct mount * root; - struct list_head list; - wait_queue_head_t poll; - int event; -}; - -struct mnt_pcp { - int mnt_count; - int mnt_writers; -}; - -struct mount { - struct list_head mnt_hash; - struct mount *mnt_parent; - struct dentry *mnt_mountpoint; - struct vfsmount mnt; -#ifdef CONFIG_SMP - struct mnt_pcp __percpu *mnt_pcp; - atomic_t mnt_longterm; /* how many of the refs are longterm */ -#else - int mnt_count; - int mnt_writers; -#endif - struct list_head mnt_mounts; /* list of children, anchored here */ - struct list_head mnt_child; /* and going through their mnt_child */ - const char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ - struct list_head mnt_list; - struct list_head mnt_expire; /* link in fs-specific expiry list */ - struct list_head mnt_share; /* circular list of shared mounts */ - struct list_head mnt_slave_list;/* list of slave mounts */ - struct list_head mnt_slave; /* slave list entry */ - struct mount *mnt_master; /* slave is on master->mnt_slave_list */ - struct mnt_namespace *mnt_ns; /* containing namespace */ -#ifdef CONFIG_FSNOTIFY - struct hlist_head mnt_fsnotify_marks; - __u32 mnt_fsnotify_mask; -#endif - int mnt_id; /* mount identifier */ - int mnt_group_id; /* peer group identifier */ - int mnt_expiry_mark; /* true if marked for expiry */ - int mnt_pinned; - int mnt_ghosts; -}; - -static inline struct mount *real_mount(struct vfsmount *mnt) -{ - return container_of(mnt, struct mount, mnt); -} - -static inline int mnt_has_parent(struct mount *mnt) +static inline int mnt_has_parent(struct vfsmount *mnt) { return mnt != mnt->mnt_parent; } - -extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *, int); - -static inline void get_mnt_ns(struct mnt_namespace *ns) -{ - atomic_inc(&ns->count); -} - -struct proc_mounts { - struct seq_file m; /* must be the first element */ - struct mnt_namespace *ns; - struct path root; - int (*show)(struct seq_file *, struct vfsmount *); -}; - -extern const struct seq_operations mounts_op; diff --git a/trunk/fs/namei.c b/trunk/fs/namei.c index 87363aab43f0..f6b3c73e862c 100644 --- a/trunk/fs/namei.c +++ b/trunk/fs/namei.c @@ -36,7 +36,6 @@ #include #include "internal.h" -#include "mount.h" /* [Feb-1997 T. Schoebel-Theuer] * Fundamental changes in the pathname lookup mechanisms (namei) @@ -677,38 +676,36 @@ follow_link(struct path *link, struct nameidata *nd, void **p) static int follow_up_rcu(struct path *path) { - struct mount *mnt = real_mount(path->mnt); - struct mount *parent; + struct vfsmount *parent; struct dentry *mountpoint; - parent = mnt->mnt_parent; - if (&parent->mnt == path->mnt) + parent = path->mnt->mnt_parent; + if (parent == path->mnt) return 0; - mountpoint = mnt->mnt_mountpoint; + mountpoint = path->mnt->mnt_mountpoint; path->dentry = mountpoint; - path->mnt = &parent->mnt; + path->mnt = parent; return 1; } int follow_up(struct path *path) { - struct mount *mnt = real_mount(path->mnt); - struct mount *parent; + struct vfsmount *parent; struct dentry *mountpoint; br_read_lock(vfsmount_lock); - parent = mnt->mnt_parent; - if (&parent->mnt == path->mnt) { + parent = path->mnt->mnt_parent; + if (parent == path->mnt) { br_read_unlock(vfsmount_lock); return 0; } - mntget(&parent->mnt); - mountpoint = dget(mnt->mnt_mountpoint); + mntget(parent); + mountpoint = dget(path->mnt->mnt_mountpoint); br_read_unlock(vfsmount_lock); dput(path->dentry); path->dentry = mountpoint; mntput(path->mnt); - path->mnt = &parent->mnt; + path->mnt = parent; return 1; } @@ -887,7 +884,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, struct inode **inode) { for (;;) { - struct mount *mounted; + struct vfsmount *mounted; /* * Don't forget we might have a non-mountpoint managed dentry * that wants to block transit. @@ -901,8 +898,8 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, mounted = __lookup_mnt(path->mnt, path->dentry, 1); if (!mounted) break; - path->mnt = &mounted->mnt; - path->dentry = mounted->mnt.mnt_root; + path->mnt = mounted; + path->dentry = mounted->mnt_root; nd->flags |= LOOKUP_JUMPED; nd->seq = read_seqcount_begin(&path->dentry->d_seq); /* @@ -918,12 +915,12 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, static void follow_mount_rcu(struct nameidata *nd) { while (d_mountpoint(nd->path.dentry)) { - struct mount *mounted; + struct vfsmount *mounted; mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry, 1); if (!mounted) break; - nd->path.mnt = &mounted->mnt; - nd->path.dentry = mounted->mnt.mnt_root; + nd->path.mnt = mounted; + nd->path.dentry = mounted->mnt_root; nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); } } @@ -2492,7 +2489,7 @@ static int may_mknod(mode_t mode) } } -SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode, +SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, unsigned, dev) { struct dentry *dentry; @@ -2539,7 +2536,7 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode, return error; } -SYSCALL_DEFINE3(mknod, const char __user *, filename, int, mode, unsigned, dev) +SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev) { return sys_mknodat(AT_FDCWD, filename, mode, dev); } diff --git a/trunk/fs/namespace.c b/trunk/fs/namespace.c index 773435ca300d..86b4f6406470 100644 --- a/trunk/fs/namespace.c +++ b/trunk/fs/namespace.c @@ -9,17 +9,30 @@ */ #include -#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include #include #include +#include #include +#include +#include +#include #include -#include /* acct_auto_close_mnt */ -#include /* init_rootfs */ -#include /* get_fs_root et.al. */ -#include /* fsnotify_vfsmount_delete */ -#include +#include +#include +#include +#include #include "pnode.h" #include "internal.h" @@ -65,7 +78,7 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) * allocation is serialized by namespace_sem, but we need the spinlock to * serialize with freeing. */ -static int mnt_alloc_id(struct mount *mnt) +static int mnt_alloc_id(struct vfsmount *mnt) { int res; @@ -82,7 +95,7 @@ static int mnt_alloc_id(struct mount *mnt) return res; } -static void mnt_free_id(struct mount *mnt) +static void mnt_free_id(struct vfsmount *mnt) { int id = mnt->mnt_id; spin_lock(&mnt_id_lock); @@ -97,7 +110,7 @@ static void mnt_free_id(struct mount *mnt) * * mnt_group_ida is protected by namespace_sem */ -static int mnt_alloc_group_id(struct mount *mnt) +static int mnt_alloc_group_id(struct vfsmount *mnt) { int res; @@ -116,7 +129,7 @@ static int mnt_alloc_group_id(struct mount *mnt) /* * Release a peer group ID */ -void mnt_release_group_id(struct mount *mnt) +void mnt_release_group_id(struct vfsmount *mnt) { int id = mnt->mnt_group_id; ida_remove(&mnt_group_ida, id); @@ -128,7 +141,7 @@ void mnt_release_group_id(struct mount *mnt) /* * vfsmount lock must be held for read */ -static inline void mnt_add_count(struct mount *mnt, int n) +static inline void mnt_add_count(struct vfsmount *mnt, int n) { #ifdef CONFIG_SMP this_cpu_add(mnt->mnt_pcp->mnt_count, n); @@ -142,7 +155,7 @@ static inline void mnt_add_count(struct mount *mnt, int n) /* * vfsmount lock must be held for write */ -unsigned int mnt_get_count(struct mount *mnt) +unsigned int mnt_get_count(struct vfsmount *mnt) { #ifdef CONFIG_SMP unsigned int count = 0; @@ -158,9 +171,9 @@ unsigned int mnt_get_count(struct mount *mnt) #endif } -static struct mount *alloc_vfsmnt(const char *name) +static struct vfsmount *alloc_vfsmnt(const char *name) { - struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); + struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); if (mnt) { int err; @@ -239,7 +252,7 @@ int __mnt_is_readonly(struct vfsmount *mnt) } EXPORT_SYMBOL_GPL(__mnt_is_readonly); -static inline void mnt_inc_writers(struct mount *mnt) +static inline void mnt_inc_writers(struct vfsmount *mnt) { #ifdef CONFIG_SMP this_cpu_inc(mnt->mnt_pcp->mnt_writers); @@ -248,7 +261,7 @@ static inline void mnt_inc_writers(struct mount *mnt) #endif } -static inline void mnt_dec_writers(struct mount *mnt) +static inline void mnt_dec_writers(struct vfsmount *mnt) { #ifdef CONFIG_SMP this_cpu_dec(mnt->mnt_pcp->mnt_writers); @@ -257,7 +270,7 @@ static inline void mnt_dec_writers(struct mount *mnt) #endif } -static unsigned int mnt_get_writers(struct mount *mnt) +static unsigned int mnt_get_writers(struct vfsmount *mnt) { #ifdef CONFIG_SMP unsigned int count = 0; @@ -283,7 +296,7 @@ static unsigned int mnt_get_writers(struct mount *mnt) */ /** * mnt_want_write - get write access to a mount - * @m: the mount on which to take a write + * @mnt: the mount on which to take a write * * This tells the low-level filesystem that a write is * about to be performed to it, and makes sure that @@ -291,9 +304,8 @@ static unsigned int mnt_get_writers(struct mount *mnt) * the write operation is finished, mnt_drop_write() * must be called. This is effectively a refcount. */ -int mnt_want_write(struct vfsmount *m) +int mnt_want_write(struct vfsmount *mnt) { - struct mount *mnt = real_mount(m); int ret = 0; preempt_disable(); @@ -304,7 +316,7 @@ int mnt_want_write(struct vfsmount *m) * incremented count after it has set MNT_WRITE_HOLD. */ smp_mb(); - while (mnt->mnt.mnt_flags & MNT_WRITE_HOLD) + while (mnt->mnt_flags & MNT_WRITE_HOLD) cpu_relax(); /* * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will @@ -312,7 +324,7 @@ int mnt_want_write(struct vfsmount *m) * MNT_WRITE_HOLD is cleared. */ smp_rmb(); - if (__mnt_is_readonly(m)) { + if (__mnt_is_readonly(mnt)) { mnt_dec_writers(mnt); ret = -EROFS; goto out; @@ -341,7 +353,7 @@ int mnt_clone_write(struct vfsmount *mnt) if (__mnt_is_readonly(mnt)) return -EROFS; preempt_disable(); - mnt_inc_writers(real_mount(mnt)); + mnt_inc_writers(mnt); preempt_enable(); return 0; } @@ -375,7 +387,7 @@ EXPORT_SYMBOL_GPL(mnt_want_write_file); void mnt_drop_write(struct vfsmount *mnt) { preempt_disable(); - mnt_dec_writers(real_mount(mnt)); + mnt_dec_writers(mnt); preempt_enable(); } EXPORT_SYMBOL_GPL(mnt_drop_write); @@ -386,12 +398,12 @@ void mnt_drop_write_file(struct file *file) } EXPORT_SYMBOL(mnt_drop_write_file); -static int mnt_make_readonly(struct mount *mnt) +static int mnt_make_readonly(struct vfsmount *mnt) { int ret = 0; br_write_lock(vfsmount_lock); - mnt->mnt.mnt_flags |= MNT_WRITE_HOLD; + mnt->mnt_flags |= MNT_WRITE_HOLD; /* * After storing MNT_WRITE_HOLD, we'll read the counters. This store * should be visible before we do. @@ -417,25 +429,25 @@ static int mnt_make_readonly(struct mount *mnt) if (mnt_get_writers(mnt) > 0) ret = -EBUSY; else - mnt->mnt.mnt_flags |= MNT_READONLY; + mnt->mnt_flags |= MNT_READONLY; /* * MNT_READONLY must become visible before ~MNT_WRITE_HOLD, so writers * that become unheld will see MNT_READONLY. */ smp_wmb(); - mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD; + mnt->mnt_flags &= ~MNT_WRITE_HOLD; br_write_unlock(vfsmount_lock); return ret; } -static void __mnt_unmake_readonly(struct mount *mnt) +static void __mnt_unmake_readonly(struct vfsmount *mnt) { br_write_lock(vfsmount_lock); - mnt->mnt.mnt_flags &= ~MNT_READONLY; + mnt->mnt_flags &= ~MNT_READONLY; br_write_unlock(vfsmount_lock); } -static void free_vfsmnt(struct mount *mnt) +static void free_vfsmnt(struct vfsmount *mnt) { kfree(mnt->mnt_devname); mnt_free_id(mnt); @@ -450,20 +462,20 @@ static void free_vfsmnt(struct mount *mnt) * @dir. If @dir is set return the first mount else return the last mount. * vfsmount_lock must be held for read or write. */ -struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, +struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, int dir) { struct list_head *head = mount_hashtable + hash(mnt, dentry); struct list_head *tmp = head; - struct mount *p, *found = NULL; + struct vfsmount *p, *found = NULL; for (;;) { tmp = dir ? tmp->next : tmp->prev; p = NULL; if (tmp == head) break; - p = list_entry(tmp, struct mount, mnt_hash); - if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) { + p = list_entry(tmp, struct vfsmount, mnt_hash); + if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) { found = p; break; } @@ -477,21 +489,16 @@ struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, */ struct vfsmount *lookup_mnt(struct path *path) { - struct mount *child_mnt; + struct vfsmount *child_mnt; br_read_lock(vfsmount_lock); - child_mnt = __lookup_mnt(path->mnt, path->dentry, 1); - if (child_mnt) { - mnt_add_count(child_mnt, 1); - br_read_unlock(vfsmount_lock); - return &child_mnt->mnt; - } else { - br_read_unlock(vfsmount_lock); - return NULL; - } + if ((child_mnt = __lookup_mnt(path->mnt, path->dentry, 1))) + mntget(child_mnt); + br_read_unlock(vfsmount_lock); + return child_mnt; } -static inline int check_mnt(struct mount *mnt) +static inline int check_mnt(struct vfsmount *mnt) { return mnt->mnt_ns == current->nsproxy->mnt_ns; } @@ -527,7 +534,7 @@ static void dentry_reset_mounted(struct dentry *dentry) unsigned u; for (u = 0; u < HASH_SIZE; u++) { - struct mount *p; + struct vfsmount *p; list_for_each_entry(p, &mount_hashtable[u], mnt_hash) { if (p->mnt_mountpoint == dentry) @@ -542,12 +549,12 @@ static void dentry_reset_mounted(struct dentry *dentry) /* * vfsmount lock must be held for write */ -static void detach_mnt(struct mount *mnt, struct path *old_path) +static void detach_mnt(struct vfsmount *mnt, struct path *old_path) { old_path->dentry = mnt->mnt_mountpoint; - old_path->mnt = &mnt->mnt_parent->mnt; + old_path->mnt = mnt->mnt_parent; mnt->mnt_parent = mnt; - mnt->mnt_mountpoint = mnt->mnt.mnt_root; + mnt->mnt_mountpoint = mnt->mnt_root; list_del_init(&mnt->mnt_child); list_del_init(&mnt->mnt_hash); dentry_reset_mounted(old_path->dentry); @@ -556,12 +563,11 @@ static void detach_mnt(struct mount *mnt, struct path *old_path) /* * vfsmount lock must be held for write */ -void mnt_set_mountpoint(struct mount *mnt, struct dentry *dentry, - struct mount *child_mnt) +void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, + struct vfsmount *child_mnt) { - mnt_add_count(mnt, 1); /* essentially, that's mntget */ + child_mnt->mnt_parent = mntget(mnt); child_mnt->mnt_mountpoint = dget(dentry); - child_mnt->mnt_parent = mnt; spin_lock(&dentry->d_lock); dentry->d_flags |= DCACHE_MOUNTED; spin_unlock(&dentry->d_lock); @@ -570,15 +576,15 @@ void mnt_set_mountpoint(struct mount *mnt, struct dentry *dentry, /* * vfsmount lock must be held for write */ -static void attach_mnt(struct mount *mnt, struct path *path) +static void attach_mnt(struct vfsmount *mnt, struct path *path) { - mnt_set_mountpoint(real_mount(path->mnt), path->dentry, mnt); + mnt_set_mountpoint(path->mnt, path->dentry, mnt); list_add_tail(&mnt->mnt_hash, mount_hashtable + hash(path->mnt, path->dentry)); - list_add_tail(&mnt->mnt_child, &real_mount(path->mnt)->mnt_mounts); + list_add_tail(&mnt->mnt_child, &path->mnt->mnt_mounts); } -static inline void __mnt_make_longterm(struct mount *mnt) +static inline void __mnt_make_longterm(struct vfsmount *mnt) { #ifdef CONFIG_SMP atomic_inc(&mnt->mnt_longterm); @@ -586,7 +592,7 @@ static inline void __mnt_make_longterm(struct mount *mnt) } /* needs vfsmount lock for write */ -static inline void __mnt_make_shortterm(struct mount *mnt) +static inline void __mnt_make_shortterm(struct vfsmount *mnt) { #ifdef CONFIG_SMP atomic_dec(&mnt->mnt_longterm); @@ -596,10 +602,10 @@ static inline void __mnt_make_shortterm(struct mount *mnt) /* * vfsmount lock must be held for write */ -static void commit_tree(struct mount *mnt) +static void commit_tree(struct vfsmount *mnt) { - struct mount *parent = mnt->mnt_parent; - struct mount *m; + struct vfsmount *parent = mnt->mnt_parent; + struct vfsmount *m; LIST_HEAD(head); struct mnt_namespace *n = parent->mnt_ns; @@ -614,12 +620,12 @@ static void commit_tree(struct mount *mnt) list_splice(&head, n->list.prev); list_add_tail(&mnt->mnt_hash, mount_hashtable + - hash(&parent->mnt, mnt->mnt_mountpoint)); + hash(parent, mnt->mnt_mountpoint)); list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); touch_mnt_namespace(n); } -static struct mount *next_mnt(struct mount *p, struct mount *root) +static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root) { struct list_head *next = p->mnt_mounts.next; if (next == &p->mnt_mounts) { @@ -632,14 +638,14 @@ static struct mount *next_mnt(struct mount *p, struct mount *root) p = p->mnt_parent; } } - return list_entry(next, struct mount, mnt_child); + return list_entry(next, struct vfsmount, mnt_child); } -static struct mount *skip_mnt_tree(struct mount *p) +static struct vfsmount *skip_mnt_tree(struct vfsmount *p) { struct list_head *prev = p->mnt_mounts.prev; while (prev != &p->mnt_mounts) { - p = list_entry(prev, struct mount, mnt_child); + p = list_entry(prev, struct vfsmount, mnt_child); prev = p->mnt_mounts.prev; } return p; @@ -648,7 +654,7 @@ static struct mount *skip_mnt_tree(struct mount *p) struct vfsmount * vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) { - struct mount *mnt; + struct vfsmount *mnt; struct dentry *root; if (!type) @@ -659,7 +665,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void return ERR_PTR(-ENOMEM); if (flags & MS_KERNMOUNT) - mnt->mnt.mnt_flags = MNT_INTERNAL; + mnt->mnt_flags = MNT_INTERNAL; root = mount_fs(type, flags, name, data); if (IS_ERR(root)) { @@ -667,19 +673,19 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void return ERR_CAST(root); } - mnt->mnt.mnt_root = root; - mnt->mnt.mnt_sb = root->d_sb; - mnt->mnt_mountpoint = mnt->mnt.mnt_root; + mnt->mnt_root = root; + mnt->mnt_sb = root->d_sb; + mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; - return &mnt->mnt; + return mnt; } EXPORT_SYMBOL_GPL(vfs_kern_mount); -static struct mount *clone_mnt(struct mount *old, struct dentry *root, +static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, int flag) { - struct super_block *sb = old->mnt.mnt_sb; - struct mount *mnt = alloc_vfsmnt(old->mnt_devname); + struct super_block *sb = old->mnt_sb; + struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname); if (mnt) { if (flag & (CL_SLAVE | CL_PRIVATE)) @@ -693,11 +699,11 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, goto out_free; } - mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD; + mnt->mnt_flags = old->mnt_flags & ~MNT_WRITE_HOLD; atomic_inc(&sb->s_active); - mnt->mnt.mnt_sb = sb; - mnt->mnt.mnt_root = dget(root); - mnt->mnt_mountpoint = mnt->mnt.mnt_root; + mnt->mnt_sb = sb; + mnt->mnt_root = dget(root); + mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; if (flag & CL_SLAVE) { @@ -728,10 +734,9 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, return NULL; } -static inline void mntfree(struct mount *mnt) +static inline void mntfree(struct vfsmount *mnt) { - struct vfsmount *m = &mnt->mnt; - struct super_block *sb = m->mnt_sb; + struct super_block *sb = mnt->mnt_sb; /* * This probably indicates that somebody messed @@ -744,13 +749,13 @@ static inline void mntfree(struct mount *mnt) * so mnt_get_writers() below is safe. */ WARN_ON(mnt_get_writers(mnt)); - fsnotify_vfsmount_delete(m); - dput(m->mnt_root); + fsnotify_vfsmount_delete(mnt); + dput(mnt->mnt_root); free_vfsmnt(mnt); deactivate_super(sb); } -static void mntput_no_expire(struct mount *mnt) +static void mntput_no_expire(struct vfsmount *mnt) { put_again: #ifdef CONFIG_SMP @@ -778,7 +783,7 @@ static void mntput_no_expire(struct mount *mnt) mnt_add_count(mnt, mnt->mnt_pinned + 1); mnt->mnt_pinned = 0; br_write_unlock(vfsmount_lock); - acct_auto_close_mnt(&mnt->mnt); + acct_auto_close_mnt(mnt); goto put_again; } br_write_unlock(vfsmount_lock); @@ -788,11 +793,10 @@ static void mntput_no_expire(struct mount *mnt) void mntput(struct vfsmount *mnt) { if (mnt) { - struct mount *m = real_mount(mnt); /* avoid cacheline pingpong, hope gcc doesn't get "smart" */ - if (unlikely(m->mnt_expiry_mark)) - m->mnt_expiry_mark = 0; - mntput_no_expire(m); + if (unlikely(mnt->mnt_expiry_mark)) + mnt->mnt_expiry_mark = 0; + mntput_no_expire(mnt); } } EXPORT_SYMBOL(mntput); @@ -800,7 +804,7 @@ EXPORT_SYMBOL(mntput); struct vfsmount *mntget(struct vfsmount *mnt) { if (mnt) - mnt_add_count(real_mount(mnt), 1); + mnt_add_count(mnt, 1); return mnt; } EXPORT_SYMBOL(mntget); @@ -808,14 +812,13 @@ EXPORT_SYMBOL(mntget); void mnt_pin(struct vfsmount *mnt) { br_write_lock(vfsmount_lock); - real_mount(mnt)->mnt_pinned++; + mnt->mnt_pinned++; br_write_unlock(vfsmount_lock); } EXPORT_SYMBOL(mnt_pin); -void mnt_unpin(struct vfsmount *m) +void mnt_unpin(struct vfsmount *mnt) { - struct mount *mnt = real_mount(m); br_write_lock(vfsmount_lock); if (mnt->mnt_pinned) { mnt_add_count(mnt, 1); @@ -885,10 +888,10 @@ void replace_mount_options(struct super_block *sb, char *options) EXPORT_SYMBOL(replace_mount_options); #ifdef CONFIG_PROC_FS -/* iterator; we want it to have access to namespace_sem, thus here... */ +/* iterator */ static void *m_start(struct seq_file *m, loff_t *pos) { - struct proc_mounts *p = container_of(m, struct proc_mounts, m); + struct proc_mounts *p = m->private; down_read(&namespace_sem); return seq_list_start(&p->ns->list, *pos); @@ -896,7 +899,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) static void *m_next(struct seq_file *m, void *v, loff_t *pos) { - struct proc_mounts *p = container_of(m, struct proc_mounts, m); + struct proc_mounts *p = m->private; return seq_list_next(v, &p->ns->list, pos); } @@ -906,18 +909,219 @@ static void m_stop(struct seq_file *m, void *v) up_read(&namespace_sem); } -static int m_show(struct seq_file *m, void *v) +int mnt_had_events(struct proc_mounts *p) +{ + struct mnt_namespace *ns = p->ns; + int res = 0; + + br_read_lock(vfsmount_lock); + if (p->m.poll_event != ns->event) { + p->m.poll_event = ns->event; + res = 1; + } + br_read_unlock(vfsmount_lock); + + return res; +} + +struct proc_fs_info { + int flag; + const char *str; +}; + +static int show_sb_opts(struct seq_file *m, struct super_block *sb) +{ + static const struct proc_fs_info fs_info[] = { + { MS_SYNCHRONOUS, ",sync" }, + { MS_DIRSYNC, ",dirsync" }, + { MS_MANDLOCK, ",mand" }, + { 0, NULL } + }; + const struct proc_fs_info *fs_infop; + + for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { + if (sb->s_flags & fs_infop->flag) + seq_puts(m, fs_infop->str); + } + + return security_sb_show_options(m, sb); +} + +static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) { - struct proc_mounts *p = container_of(m, struct proc_mounts, m); - struct mount *r = list_entry(v, struct mount, mnt_list); - return p->show(m, &r->mnt); + static const struct proc_fs_info mnt_info[] = { + { MNT_NOSUID, ",nosuid" }, + { MNT_NODEV, ",nodev" }, + { MNT_NOEXEC, ",noexec" }, + { MNT_NOATIME, ",noatime" }, + { MNT_NODIRATIME, ",nodiratime" }, + { MNT_RELATIME, ",relatime" }, + { 0, NULL } + }; + const struct proc_fs_info *fs_infop; + + for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { + if (mnt->mnt_flags & fs_infop->flag) + seq_puts(m, fs_infop->str); + } +} + +static void show_type(struct seq_file *m, struct super_block *sb) +{ + mangle(m, sb->s_type->name); + if (sb->s_subtype && sb->s_subtype[0]) { + seq_putc(m, '.'); + mangle(m, sb->s_subtype); + } +} + +static int show_vfsmnt(struct seq_file *m, void *v) +{ + struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); + int err = 0; + struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; + + if (mnt->mnt_sb->s_op->show_devname) { + err = mnt->mnt_sb->s_op->show_devname(m, mnt); + if (err) + goto out; + } else { + mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); + } + seq_putc(m, ' '); + seq_path(m, &mnt_path, " \t\n\\"); + seq_putc(m, ' '); + show_type(m, mnt->mnt_sb); + seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); + err = show_sb_opts(m, mnt->mnt_sb); + if (err) + goto out; + show_mnt_opts(m, mnt); + if (mnt->mnt_sb->s_op->show_options) + err = mnt->mnt_sb->s_op->show_options(m, mnt); + seq_puts(m, " 0 0\n"); +out: + return err; } const struct seq_operations mounts_op = { .start = m_start, .next = m_next, .stop = m_stop, - .show = m_show, + .show = show_vfsmnt +}; + +static int show_mountinfo(struct seq_file *m, void *v) +{ + struct proc_mounts *p = m->private; + struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); + struct super_block *sb = mnt->mnt_sb; + struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; + struct path root = p->root; + int err = 0; + + seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id, + MAJOR(sb->s_dev), MINOR(sb->s_dev)); + if (sb->s_op->show_path) + err = sb->s_op->show_path(m, mnt); + else + seq_dentry(m, mnt->mnt_root, " \t\n\\"); + if (err) + goto out; + seq_putc(m, ' '); + + /* mountpoints outside of chroot jail will give SEQ_SKIP on this */ + err = seq_path_root(m, &mnt_path, &root, " \t\n\\"); + if (err) + goto out; + + seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw"); + show_mnt_opts(m, mnt); + + /* Tagged fields ("foo:X" or "bar") */ + if (IS_MNT_SHARED(mnt)) + seq_printf(m, " shared:%i", mnt->mnt_group_id); + if (IS_MNT_SLAVE(mnt)) { + int master = mnt->mnt_master->mnt_group_id; + int dom = get_dominating_id(mnt, &p->root); + seq_printf(m, " master:%i", master); + if (dom && dom != master) + seq_printf(m, " propagate_from:%i", dom); + } + if (IS_MNT_UNBINDABLE(mnt)) + seq_puts(m, " unbindable"); + + /* Filesystem specific data */ + seq_puts(m, " - "); + show_type(m, sb); + seq_putc(m, ' '); + if (sb->s_op->show_devname) + err = sb->s_op->show_devname(m, mnt); + else + mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); + if (err) + goto out; + seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw"); + err = show_sb_opts(m, sb); + if (err) + goto out; + if (sb->s_op->show_options) + err = sb->s_op->show_options(m, mnt); + seq_putc(m, '\n'); +out: + return err; +} + +const struct seq_operations mountinfo_op = { + .start = m_start, + .next = m_next, + .stop = m_stop, + .show = show_mountinfo, +}; + +static int show_vfsstat(struct seq_file *m, void *v) +{ + struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); + struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; + int err = 0; + + /* device */ + if (mnt->mnt_sb->s_op->show_devname) { + seq_puts(m, "device "); + err = mnt->mnt_sb->s_op->show_devname(m, mnt); + } else { + if (mnt->mnt_devname) { + seq_puts(m, "device "); + mangle(m, mnt->mnt_devname); + } else + seq_puts(m, "no device"); + } + + /* mount point */ + seq_puts(m, " mounted on "); + seq_path(m, &mnt_path, " \t\n\\"); + seq_putc(m, ' '); + + /* file system type */ + seq_puts(m, "with fstype "); + show_type(m, mnt->mnt_sb); + + /* optional statistics */ + if (mnt->mnt_sb->s_op->show_stats) { + seq_putc(m, ' '); + if (!err) + err = mnt->mnt_sb->s_op->show_stats(m, mnt); + } + + seq_putc(m, '\n'); + return err; +} + +const struct seq_operations mountstats_op = { + .start = m_start, + .next = m_next, + .stop = m_stop, + .show = show_vfsstat, }; #endif /* CONFIG_PROC_FS */ @@ -929,13 +1133,11 @@ const struct seq_operations mounts_op = { * open files, pwds, chroots or sub mounts that are * busy. */ -int may_umount_tree(struct vfsmount *m) +int may_umount_tree(struct vfsmount *mnt) { - struct mount *mnt = real_mount(m); int actual_refs = 0; int minimum_refs = 0; - struct mount *p; - BUG_ON(!m); + struct vfsmount *p; /* write lock needed for mnt_get_count */ br_write_lock(vfsmount_lock); @@ -971,7 +1173,7 @@ int may_umount(struct vfsmount *mnt) int ret = 1; down_read(&namespace_sem); br_write_lock(vfsmount_lock); - if (propagate_mount_busy(real_mount(mnt), 2)) + if (propagate_mount_busy(mnt, 2)) ret = 0; br_write_unlock(vfsmount_lock); up_read(&namespace_sem); @@ -982,25 +1184,25 @@ EXPORT_SYMBOL(may_umount); void release_mounts(struct list_head *head) { - struct mount *mnt; + struct vfsmount *mnt; while (!list_empty(head)) { - mnt = list_first_entry(head, struct mount, mnt_hash); + mnt = list_first_entry(head, struct vfsmount, mnt_hash); list_del_init(&mnt->mnt_hash); if (mnt_has_parent(mnt)) { struct dentry *dentry; - struct mount *m; + struct vfsmount *m; br_write_lock(vfsmount_lock); dentry = mnt->mnt_mountpoint; m = mnt->mnt_parent; - mnt->mnt_mountpoint = mnt->mnt.mnt_root; + mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; m->mnt_ghosts--; br_write_unlock(vfsmount_lock); dput(dentry); - mntput(&m->mnt); + mntput(m); } - mntput(&mnt->mnt); + mntput(mnt); } } @@ -1008,10 +1210,10 @@ void release_mounts(struct list_head *head) * vfsmount lock must be held for write * namespace_sem must be held for write */ -void umount_tree(struct mount *mnt, int propagate, struct list_head *kill) +void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) { LIST_HEAD(tmp_list); - struct mount *p; + struct vfsmount *p; for (p = mnt; p; p = next_mnt(p, mnt)) list_move(&p->mnt_hash, &tmp_list); @@ -1035,15 +1237,15 @@ void umount_tree(struct mount *mnt, int propagate, struct list_head *kill) list_splice(&tmp_list, kill); } -static void shrink_submounts(struct mount *mnt, struct list_head *umounts); +static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts); -static int do_umount(struct mount *mnt, int flags) +static int do_umount(struct vfsmount *mnt, int flags) { - struct super_block *sb = mnt->mnt.mnt_sb; + struct super_block *sb = mnt->mnt_sb; int retval; LIST_HEAD(umount_list); - retval = security_sb_umount(&mnt->mnt, flags); + retval = security_sb_umount(mnt, flags); if (retval) return retval; @@ -1054,7 +1256,7 @@ static int do_umount(struct mount *mnt, int flags) * (2) the usage count == 1 [parent vfsmount] + 1 [sys_umount] */ if (flags & MNT_EXPIRE) { - if (&mnt->mnt == current->fs->root.mnt || + if (mnt == current->fs->root.mnt || flags & (MNT_FORCE | MNT_DETACH)) return -EINVAL; @@ -1096,7 +1298,7 @@ static int do_umount(struct mount *mnt, int flags) * /reboot - static binary that would close all descriptors and * call reboot(9). Then init(8) could umount root and exec /reboot. */ - if (&mnt->mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) { + if (mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) { /* * Special case for "unmounting" root ... * we just try to remount it readonly. @@ -1138,7 +1340,6 @@ static int do_umount(struct mount *mnt, int flags) SYSCALL_DEFINE2(umount, char __user *, name, int, flags) { struct path path; - struct mount *mnt; int retval; int lookup_flags = 0; @@ -1151,22 +1352,21 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) retval = user_path_at(AT_FDCWD, name, lookup_flags, &path); if (retval) goto out; - mnt = real_mount(path.mnt); retval = -EINVAL; if (path.dentry != path.mnt->mnt_root) goto dput_and_out; - if (!check_mnt(mnt)) + if (!check_mnt(path.mnt)) goto dput_and_out; retval = -EPERM; if (!capable(CAP_SYS_ADMIN)) goto dput_and_out; - retval = do_umount(mnt, flags); + retval = do_umount(path.mnt, flags); dput_and_out: /* we mustn't call path_put() as that would clear mnt_expiry_mark */ dput(path.dentry); - mntput_no_expire(mnt); + mntput_no_expire(path.mnt); out: return retval; } @@ -1201,10 +1401,10 @@ static int mount_is_safe(struct path *path) #endif } -struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, +struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, int flag) { - struct mount *res, *p, *q, *r; + struct vfsmount *res, *p, *q, *r, *s; struct path path; if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt)) @@ -1217,7 +1417,6 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, p = mnt; list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) { - struct mount *s; if (!is_subdir(r->mnt_mountpoint, dentry)) continue; @@ -1231,9 +1430,9 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, q = q->mnt_parent; } p = s; - path.mnt = &q->mnt; + path.mnt = q; path.dentry = p->mnt_mountpoint; - q = clone_mnt(p, p->mnt.mnt_root, flag); + q = clone_mnt(p, p->mnt_root, flag); if (!q) goto Enomem; br_write_lock(vfsmount_lock); @@ -1256,12 +1455,11 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, struct vfsmount *collect_mounts(struct path *path) { - struct mount *tree; + struct vfsmount *tree; down_write(&namespace_sem); - tree = copy_tree(real_mount(path->mnt), path->dentry, - CL_COPY_ALL | CL_PRIVATE); + tree = copy_tree(path->mnt, path->dentry, CL_COPY_ALL | CL_PRIVATE); up_write(&namespace_sem); - return tree ? &tree->mnt : NULL; + return tree; } void drop_collected_mounts(struct vfsmount *mnt) @@ -1269,7 +1467,7 @@ void drop_collected_mounts(struct vfsmount *mnt) LIST_HEAD(umount_list); down_write(&namespace_sem); br_write_lock(vfsmount_lock); - umount_tree(real_mount(mnt), 0, &umount_list); + umount_tree(mnt, 0, &umount_list); br_write_unlock(vfsmount_lock); up_write(&namespace_sem); release_mounts(&umount_list); @@ -1278,21 +1476,21 @@ void drop_collected_mounts(struct vfsmount *mnt) int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, struct vfsmount *root) { - struct mount *mnt; + struct vfsmount *mnt; int res = f(root, arg); if (res) return res; - list_for_each_entry(mnt, &real_mount(root)->mnt_list, mnt_list) { - res = f(&mnt->mnt, arg); + list_for_each_entry(mnt, &root->mnt_list, mnt_list) { + res = f(mnt, arg); if (res) return res; } return 0; } -static void cleanup_group_ids(struct mount *mnt, struct mount *end) +static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end) { - struct mount *p; + struct vfsmount *p; for (p = mnt; p != end; p = next_mnt(p, mnt)) { if (p->mnt_group_id && !IS_MNT_SHARED(p)) @@ -1300,9 +1498,9 @@ static void cleanup_group_ids(struct mount *mnt, struct mount *end) } } -static int invent_group_ids(struct mount *mnt, bool recurse) +static int invent_group_ids(struct vfsmount *mnt, bool recurse) { - struct mount *p; + struct vfsmount *p; for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) { if (!p->mnt_group_id && !IS_MNT_SHARED(p)) { @@ -1380,13 +1578,13 @@ static int invent_group_ids(struct mount *mnt, bool recurse) * Must be called without spinlocks held, since this function can sleep * in allocations. */ -static int attach_recursive_mnt(struct mount *source_mnt, +static int attach_recursive_mnt(struct vfsmount *source_mnt, struct path *path, struct path *parent_path) { LIST_HEAD(tree_list); - struct mount *dest_mnt = real_mount(path->mnt); + struct vfsmount *dest_mnt = path->mnt; struct dentry *dest_dentry = path->dentry; - struct mount *child, *p; + struct vfsmount *child, *p; int err; if (IS_MNT_SHARED(dest_mnt)) { @@ -1407,7 +1605,7 @@ static int attach_recursive_mnt(struct mount *source_mnt, if (parent_path) { detach_mnt(source_mnt, parent_path); attach_mnt(source_mnt, path); - touch_mnt_namespace(source_mnt->mnt_ns); + touch_mnt_namespace(parent_path->mnt->mnt_ns); } else { mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); commit_tree(source_mnt); @@ -1455,13 +1653,13 @@ static void unlock_mount(struct path *path) mutex_unlock(&path->dentry->d_inode->i_mutex); } -static int graft_tree(struct mount *mnt, struct path *path) +static int graft_tree(struct vfsmount *mnt, struct path *path) { - if (mnt->mnt.mnt_sb->s_flags & MS_NOUSER) + if (mnt->mnt_sb->s_flags & MS_NOUSER) return -EINVAL; if (S_ISDIR(path->dentry->d_inode->i_mode) != - S_ISDIR(mnt->mnt.mnt_root->d_inode->i_mode)) + S_ISDIR(mnt->mnt_root->d_inode->i_mode)) return -ENOTDIR; if (d_unlinked(path->dentry)) @@ -1492,8 +1690,7 @@ static int flags_to_propagation_type(int flags) */ static int do_change_type(struct path *path, int flag) { - struct mount *m; - struct mount *mnt = real_mount(path->mnt); + struct vfsmount *m, *mnt = path->mnt; int recurse = flag & MS_REC; int type; int err = 0; @@ -1533,7 +1730,7 @@ static int do_loopback(struct path *path, char *old_name, { LIST_HEAD(umount_list); struct path old_path; - struct mount *mnt = NULL, *old; + struct vfsmount *mnt = NULL; int err = mount_is_safe(path); if (err) return err; @@ -1547,20 +1744,18 @@ static int do_loopback(struct path *path, char *old_name, if (err) goto out; - old = real_mount(old_path.mnt); - err = -EINVAL; - if (IS_MNT_UNBINDABLE(old)) + if (IS_MNT_UNBINDABLE(old_path.mnt)) goto out2; - if (!check_mnt(real_mount(path->mnt)) || !check_mnt(old)) + if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) goto out2; err = -ENOMEM; if (recurse) - mnt = copy_tree(old, old_path.dentry, 0); + mnt = copy_tree(old_path.mnt, old_path.dentry, 0); else - mnt = clone_mnt(old, old_path.dentry, 0); + mnt = clone_mnt(old_path.mnt, old_path.dentry, 0); if (!mnt) goto out2; @@ -1590,9 +1785,9 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags) return 0; if (readonly_request) - error = mnt_make_readonly(real_mount(mnt)); + error = mnt_make_readonly(mnt); else - __mnt_unmake_readonly(real_mount(mnt)); + __mnt_unmake_readonly(mnt); return error; } @@ -1606,12 +1801,11 @@ static int do_remount(struct path *path, int flags, int mnt_flags, { int err; struct super_block *sb = path->mnt->mnt_sb; - struct mount *mnt = real_mount(path->mnt); if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!check_mnt(mnt)) + if (!check_mnt(path->mnt)) return -EINVAL; if (path->dentry != path->mnt->mnt_root) @@ -1628,22 +1822,22 @@ static int do_remount(struct path *path, int flags, int mnt_flags, err = do_remount_sb(sb, flags, data, 0); if (!err) { br_write_lock(vfsmount_lock); - mnt_flags |= mnt->mnt.mnt_flags & MNT_PROPAGATION_MASK; - mnt->mnt.mnt_flags = mnt_flags; + mnt_flags |= path->mnt->mnt_flags & MNT_PROPAGATION_MASK; + path->mnt->mnt_flags = mnt_flags; br_write_unlock(vfsmount_lock); } up_write(&sb->s_umount); if (!err) { br_write_lock(vfsmount_lock); - touch_mnt_namespace(mnt->mnt_ns); + touch_mnt_namespace(path->mnt->mnt_ns); br_write_unlock(vfsmount_lock); } return err; } -static inline int tree_contains_unbindable(struct mount *mnt) +static inline int tree_contains_unbindable(struct vfsmount *mnt) { - struct mount *p; + struct vfsmount *p; for (p = mnt; p; p = next_mnt(p, mnt)) { if (IS_MNT_UNBINDABLE(p)) return 1; @@ -1654,8 +1848,7 @@ static inline int tree_contains_unbindable(struct mount *mnt) static int do_move_mount(struct path *path, char *old_name) { struct path old_path, parent_path; - struct mount *p; - struct mount *old; + struct vfsmount *p; int err = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1669,11 +1862,8 @@ static int do_move_mount(struct path *path, char *old_name) if (err < 0) goto out; - old = real_mount(old_path.mnt); - p = real_mount(path->mnt); - err = -EINVAL; - if (!check_mnt(p) || !check_mnt(old)) + if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) goto out1; if (d_unlinked(path->dentry)) @@ -1683,7 +1873,7 @@ static int do_move_mount(struct path *path, char *old_name) if (old_path.dentry != old_path.mnt->mnt_root) goto out1; - if (!mnt_has_parent(old)) + if (!mnt_has_parent(old_path.mnt)) goto out1; if (S_ISDIR(path->dentry->d_inode->i_mode) != @@ -1692,26 +1882,27 @@ static int do_move_mount(struct path *path, char *old_name) /* * Don't move a mount residing in a shared parent. */ - if (IS_MNT_SHARED(old->mnt_parent)) + if (IS_MNT_SHARED(old_path.mnt->mnt_parent)) goto out1; /* * Don't move a mount tree containing unbindable mounts to a destination * mount which is shared. */ - if (IS_MNT_SHARED(p) && tree_contains_unbindable(old)) + if (IS_MNT_SHARED(path->mnt) && + tree_contains_unbindable(old_path.mnt)) goto out1; err = -ELOOP; - for (; mnt_has_parent(p); p = p->mnt_parent) - if (p == old) + for (p = path->mnt; mnt_has_parent(p); p = p->mnt_parent) + if (p == old_path.mnt) goto out1; - err = attach_recursive_mnt(old, path, &parent_path); + err = attach_recursive_mnt(old_path.mnt, path, &parent_path); if (err) goto out1; /* if the mount is moved, it should no longer be expire * automatically */ - list_del_init(&old->mnt_expire); + list_del_init(&old_path.mnt->mnt_expire); out1: unlock_mount(path); out: @@ -1762,7 +1953,7 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data) /* * add a mount into a namespace's mount tree */ -static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags) +static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags) { int err; @@ -1773,20 +1964,20 @@ static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags) return err; err = -EINVAL; - if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(real_mount(path->mnt))) + if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) goto unlock; /* Refuse the same filesystem on the same mount point */ err = -EBUSY; - if (path->mnt->mnt_sb == newmnt->mnt.mnt_sb && + if (path->mnt->mnt_sb == newmnt->mnt_sb && path->mnt->mnt_root == path->dentry) goto unlock; err = -EINVAL; - if (S_ISLNK(newmnt->mnt.mnt_root->d_inode->i_mode)) + if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode)) goto unlock; - newmnt->mnt.mnt_flags = mnt_flags; + newmnt->mnt_flags = mnt_flags; err = graft_tree(newmnt, path); unlock: @@ -1815,7 +2006,7 @@ static int do_new_mount(struct path *path, char *type, int flags, if (IS_ERR(mnt)) return PTR_ERR(mnt); - err = do_add_mount(real_mount(mnt), path, mnt_flags); + err = do_add_mount(mnt, path, mnt_flags); if (err) mntput(mnt); return err; @@ -1823,12 +2014,11 @@ static int do_new_mount(struct path *path, char *type, int flags, int finish_automount(struct vfsmount *m, struct path *path) { - struct mount *mnt = real_mount(m); int err; /* The new mount record should have at least 2 refs to prevent it being * expired before we get a chance to add it */ - BUG_ON(mnt_get_count(mnt) < 2); + BUG_ON(mnt_get_count(m) < 2); if (m->mnt_sb == path->mnt->mnt_sb && m->mnt_root == path->dentry) { @@ -1836,15 +2026,15 @@ int finish_automount(struct vfsmount *m, struct path *path) goto fail; } - err = do_add_mount(mnt, path, path->mnt->mnt_flags | MNT_SHRINKABLE); + err = do_add_mount(m, path, path->mnt->mnt_flags | MNT_SHRINKABLE); if (!err) return 0; fail: /* remove m from any expiration list it may be on */ - if (!list_empty(&mnt->mnt_expire)) { + if (!list_empty(&m->mnt_expire)) { down_write(&namespace_sem); br_write_lock(vfsmount_lock); - list_del_init(&mnt->mnt_expire); + list_del_init(&m->mnt_expire); br_write_unlock(vfsmount_lock); up_write(&namespace_sem); } @@ -1863,7 +2053,7 @@ void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list) down_write(&namespace_sem); br_write_lock(vfsmount_lock); - list_add_tail(&real_mount(mnt)->mnt_expire, expiry_list); + list_add_tail(&mnt->mnt_expire, expiry_list); br_write_unlock(vfsmount_lock); up_write(&namespace_sem); @@ -1877,7 +2067,7 @@ EXPORT_SYMBOL(mnt_set_expiry); */ void mark_mounts_for_expiry(struct list_head *mounts) { - struct mount *mnt, *next; + struct vfsmount *mnt, *next; LIST_HEAD(graveyard); LIST_HEAD(umounts); @@ -1900,7 +2090,7 @@ void mark_mounts_for_expiry(struct list_head *mounts) list_move(&mnt->mnt_expire, &graveyard); } while (!list_empty(&graveyard)) { - mnt = list_first_entry(&graveyard, struct mount, mnt_expire); + mnt = list_first_entry(&graveyard, struct vfsmount, mnt_expire); touch_mnt_namespace(mnt->mnt_ns); umount_tree(mnt, 1, &umounts); } @@ -1918,9 +2108,9 @@ EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); * search the list of submounts for a given mountpoint, and move any * shrinkable submounts to the 'graveyard' list. */ -static int select_submounts(struct mount *parent, struct list_head *graveyard) +static int select_submounts(struct vfsmount *parent, struct list_head *graveyard) { - struct mount *this_parent = parent; + struct vfsmount *this_parent = parent; struct list_head *next; int found = 0; @@ -1929,10 +2119,10 @@ static int select_submounts(struct mount *parent, struct list_head *graveyard) resume: while (next != &this_parent->mnt_mounts) { struct list_head *tmp = next; - struct mount *mnt = list_entry(tmp, struct mount, mnt_child); + struct vfsmount *mnt = list_entry(tmp, struct vfsmount, mnt_child); next = tmp->next; - if (!(mnt->mnt.mnt_flags & MNT_SHRINKABLE)) + if (!(mnt->mnt_flags & MNT_SHRINKABLE)) continue; /* * Descend a level if the d_mounts list is non-empty. @@ -1964,15 +2154,15 @@ static int select_submounts(struct mount *parent, struct list_head *graveyard) * * vfsmount_lock must be held for write */ -static void shrink_submounts(struct mount *mnt, struct list_head *umounts) +static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts) { LIST_HEAD(graveyard); - struct mount *m; + struct vfsmount *m; /* extract submounts of 'mountpoint' from the expiration list */ while (select_submounts(mnt, &graveyard)) { while (!list_empty(&graveyard)) { - m = list_first_entry(&graveyard, struct mount, + m = list_first_entry(&graveyard, struct vfsmount, mnt_expire); touch_mnt_namespace(m->mnt_ns); umount_tree(m, 1, umounts); @@ -2159,13 +2349,12 @@ static struct mnt_namespace *alloc_mnt_ns(void) void mnt_make_longterm(struct vfsmount *mnt) { - __mnt_make_longterm(real_mount(mnt)); + __mnt_make_longterm(mnt); } -void mnt_make_shortterm(struct vfsmount *m) +void mnt_make_shortterm(struct vfsmount *mnt) { #ifdef CONFIG_SMP - struct mount *mnt = real_mount(m); if (atomic_add_unless(&mnt->mnt_longterm, -1, 1)) return; br_write_lock(vfsmount_lock); @@ -2183,9 +2372,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, { struct mnt_namespace *new_ns; struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; - struct mount *p, *q; - struct mount *old = mnt_ns->root; - struct mount *new; + struct vfsmount *p, *q; new_ns = alloc_mnt_ns(); if (IS_ERR(new_ns)) @@ -2193,15 +2380,15 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, down_write(&namespace_sem); /* First pass: copy the tree topology */ - new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE); - if (!new) { + new_ns->root = copy_tree(mnt_ns->root, mnt_ns->root->mnt_root, + CL_COPY_ALL | CL_EXPIRE); + if (!new_ns->root) { up_write(&namespace_sem); kfree(new_ns); return ERR_PTR(-ENOMEM); } - new_ns->root = new; br_write_lock(vfsmount_lock); - list_add_tail(&new_ns->list, &new->mnt_list); + list_add_tail(&new_ns->list, &new_ns->root->mnt_list); br_write_unlock(vfsmount_lock); /* @@ -2209,27 +2396,27 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, * as belonging to new namespace. We have already acquired a private * fs_struct, so tsk->fs->lock is not needed. */ - p = old; - q = new; + p = mnt_ns->root; + q = new_ns->root; while (p) { q->mnt_ns = new_ns; __mnt_make_longterm(q); if (fs) { - if (&p->mnt == fs->root.mnt) { - fs->root.mnt = mntget(&q->mnt); + if (p == fs->root.mnt) { + fs->root.mnt = mntget(q); __mnt_make_longterm(q); - mnt_make_shortterm(&p->mnt); - rootmnt = &p->mnt; + mnt_make_shortterm(p); + rootmnt = p; } - if (&p->mnt == fs->pwd.mnt) { - fs->pwd.mnt = mntget(&q->mnt); + if (p == fs->pwd.mnt) { + fs->pwd.mnt = mntget(q); __mnt_make_longterm(q); - mnt_make_shortterm(&p->mnt); - pwdmnt = &p->mnt; + mnt_make_shortterm(p); + pwdmnt = p; } } - p = next_mnt(p, old); - q = next_mnt(q, new); + p = next_mnt(p, mnt_ns->root); + q = next_mnt(q, new_ns->root); } up_write(&namespace_sem); @@ -2262,17 +2449,18 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, * create_mnt_ns - creates a private namespace and adds a root filesystem * @mnt: pointer to the new root filesystem mountpoint */ -static struct mnt_namespace *create_mnt_ns(struct vfsmount *m) +static struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt) { - struct mnt_namespace *new_ns = alloc_mnt_ns(); + struct mnt_namespace *new_ns; + + new_ns = alloc_mnt_ns(); if (!IS_ERR(new_ns)) { - struct mount *mnt = real_mount(m); mnt->mnt_ns = new_ns; __mnt_make_longterm(mnt); new_ns->root = mnt; - list_add(&new_ns->list, &mnt->mnt_list); + list_add(&new_ns->list, &new_ns->root->mnt_list); } else { - mntput(m); + mntput(mnt); } return new_ns; } @@ -2353,21 +2541,21 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, * * namespace_sem or vfsmount_lock is held */ -bool is_path_reachable(struct mount *mnt, struct dentry *dentry, +bool is_path_reachable(struct vfsmount *mnt, struct dentry *dentry, const struct path *root) { - while (&mnt->mnt != root->mnt && mnt_has_parent(mnt)) { + while (mnt != root->mnt && mnt_has_parent(mnt)) { dentry = mnt->mnt_mountpoint; mnt = mnt->mnt_parent; } - return &mnt->mnt == root->mnt && is_subdir(dentry, root->dentry); + return mnt == root->mnt && is_subdir(dentry, root->dentry); } int path_is_under(struct path *path1, struct path *path2) { int res; br_read_lock(vfsmount_lock); - res = is_path_reachable(real_mount(path1->mnt), path1->dentry, path2); + res = is_path_reachable(path1->mnt, path1->dentry, path2); br_read_unlock(vfsmount_lock); return res; } @@ -2402,7 +2590,6 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, const char __user *, put_old) { struct path new, old, parent_path, root_parent, root; - struct mount *new_mnt, *root_mnt; int error; if (!capable(CAP_SYS_ADMIN)) @@ -2426,13 +2613,11 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, goto out3; error = -EINVAL; - new_mnt = real_mount(new.mnt); - root_mnt = real_mount(root.mnt); - if (IS_MNT_SHARED(real_mount(old.mnt)) || - IS_MNT_SHARED(new_mnt->mnt_parent) || - IS_MNT_SHARED(root_mnt->mnt_parent)) + if (IS_MNT_SHARED(old.mnt) || + IS_MNT_SHARED(new.mnt->mnt_parent) || + IS_MNT_SHARED(root.mnt->mnt_parent)) goto out4; - if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) + if (!check_mnt(root.mnt) || !check_mnt(new.mnt)) goto out4; error = -ENOENT; if (d_unlinked(new.dentry)) @@ -2446,22 +2631,22 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, error = -EINVAL; if (root.mnt->mnt_root != root.dentry) goto out4; /* not a mountpoint */ - if (!mnt_has_parent(root_mnt)) + if (!mnt_has_parent(root.mnt)) goto out4; /* not attached */ if (new.mnt->mnt_root != new.dentry) goto out4; /* not a mountpoint */ - if (!mnt_has_parent(new_mnt)) + if (!mnt_has_parent(new.mnt)) goto out4; /* not attached */ /* make sure we can reach put_old from new_root */ - if (!is_path_reachable(real_mount(old.mnt), old.dentry, &new)) + if (!is_path_reachable(old.mnt, old.dentry, &new)) goto out4; br_write_lock(vfsmount_lock); - detach_mnt(new_mnt, &parent_path); - detach_mnt(root_mnt, &root_parent); + detach_mnt(new.mnt, &parent_path); + detach_mnt(root.mnt, &root_parent); /* mount old root on put_old */ - attach_mnt(root_mnt, &old); + attach_mnt(root.mnt, &old); /* mount new_root on / */ - attach_mnt(new_mnt, &root_parent); + attach_mnt(new.mnt, &root_parent); touch_mnt_namespace(current->nsproxy->mnt_ns); br_write_unlock(vfsmount_lock); chroot_fs_refs(&root, &new); @@ -2499,8 +2684,8 @@ static void __init init_mount_tree(void) init_task.nsproxy->mnt_ns = ns; get_mnt_ns(ns); - root.mnt = mnt; - root.dentry = mnt->mnt_root; + root.mnt = ns->root; + root.dentry = ns->root->mnt_root; set_fs_pwd(current->fs, &root); set_fs_root(current->fs, &root); @@ -2513,7 +2698,7 @@ void __init mnt_init(void) init_rwsem(&namespace_sem); - mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount), + mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount), 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC); @@ -2581,5 +2766,5 @@ EXPORT_SYMBOL(kern_unmount); bool our_mnt(struct vfsmount *mnt) { - return check_mnt(real_mount(mnt)); + return check_mnt(mnt); } diff --git a/trunk/fs/notify/fanotify/fanotify_user.c b/trunk/fs/notify/fanotify/fanotify_user.c index 3568c8a8b138..9fde1c00a296 100644 --- a/trunk/fs/notify/fanotify/fanotify_user.c +++ b/trunk/fs/notify/fanotify/fanotify_user.c @@ -16,8 +16,6 @@ #include -#include "../../mount.h" - #define FANOTIFY_DEFAULT_MAX_EVENTS 16384 #define FANOTIFY_DEFAULT_MAX_MARKS 8192 #define FANOTIFY_DEFAULT_MAX_LISTENERS 128 @@ -548,7 +546,7 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group, removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags); fsnotify_put_mark(fsn_mark); - if (removed & real_mount(mnt)->mnt_fsnotify_mask) + if (removed & mnt->mnt_fsnotify_mask) fsnotify_recalc_vfsmount_mask(mnt); return 0; @@ -625,7 +623,7 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, } added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); - if (added & ~real_mount(mnt)->mnt_fsnotify_mask) + if (added & ~mnt->mnt_fsnotify_mask) fsnotify_recalc_vfsmount_mask(mnt); err: fsnotify_put_mark(fsn_mark); diff --git a/trunk/fs/notify/fsnotify.c b/trunk/fs/notify/fsnotify.c index ccb14d3fc0de..79b47cbb5cd8 100644 --- a/trunk/fs/notify/fsnotify.c +++ b/trunk/fs/notify/fsnotify.c @@ -26,7 +26,6 @@ #include #include "fsnotify.h" -#include "../mount.h" /* * Clear all of the marks on an inode when it is being evicted from core @@ -206,13 +205,13 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, struct fsnotify_mark *inode_mark = NULL, *vfsmount_mark = NULL; struct fsnotify_group *inode_group, *vfsmount_group; struct fsnotify_event *event = NULL; - struct mount *mnt; + struct vfsmount *mnt; int idx, ret = 0; /* global tests shouldn't care about events on child only the specific event */ __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); if (data_is == FSNOTIFY_EVENT_PATH) - mnt = real_mount(((struct path *)data)->mnt); + mnt = ((struct path *)data)->mnt; else mnt = NULL; @@ -263,11 +262,11 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, /* we didn't use the vfsmount_mark */ vfsmount_group = NULL; } else if (vfsmount_group > inode_group) { - ret = send_to_group(to_tell, &mnt->mnt, NULL, vfsmount_mark, mask, data, + ret = send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data, data_is, cookie, file_name, &event); inode_group = NULL; } else { - ret = send_to_group(to_tell, &mnt->mnt, inode_mark, vfsmount_mark, + ret = send_to_group(to_tell, mnt, inode_mark, vfsmount_mark, mask, data, data_is, cookie, file_name, &event); } diff --git a/trunk/fs/notify/vfsmount_mark.c b/trunk/fs/notify/vfsmount_mark.c index b7b4b0e8554f..778fe6cae3b0 100644 --- a/trunk/fs/notify/vfsmount_mark.c +++ b/trunk/fs/notify/vfsmount_mark.c @@ -28,17 +28,15 @@ #include #include "fsnotify.h" -#include "../mount.h" void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) { struct fsnotify_mark *mark, *lmark; struct hlist_node *pos, *n; - struct mount *m = real_mount(mnt); LIST_HEAD(free_list); spin_lock(&mnt->mnt_root->d_lock); - hlist_for_each_entry_safe(mark, pos, n, &m->mnt_fsnotify_marks, m.m_list) { + hlist_for_each_entry_safe(mark, pos, n, &mnt->mnt_fsnotify_marks, m.m_list) { list_add(&mark->m.free_m_list, &free_list); hlist_del_init_rcu(&mark->m.m_list); fsnotify_get_mark(mark); @@ -61,16 +59,15 @@ void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) */ static void fsnotify_recalc_vfsmount_mask_locked(struct vfsmount *mnt) { - struct mount *m = real_mount(mnt); struct fsnotify_mark *mark; struct hlist_node *pos; __u32 new_mask = 0; assert_spin_locked(&mnt->mnt_root->d_lock); - hlist_for_each_entry(mark, pos, &m->mnt_fsnotify_marks, m.m_list) + hlist_for_each_entry(mark, pos, &mnt->mnt_fsnotify_marks, m.m_list) new_mask |= mark->mask; - m->mnt_fsnotify_mask = new_mask; + mnt->mnt_fsnotify_mask = new_mask; } /* @@ -104,13 +101,12 @@ void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark) static struct fsnotify_mark *fsnotify_find_vfsmount_mark_locked(struct fsnotify_group *group, struct vfsmount *mnt) { - struct mount *m = real_mount(mnt); struct fsnotify_mark *mark; struct hlist_node *pos; assert_spin_locked(&mnt->mnt_root->d_lock); - hlist_for_each_entry(mark, pos, &m->mnt_fsnotify_marks, m.m_list) { + hlist_for_each_entry(mark, pos, &mnt->mnt_fsnotify_marks, m.m_list) { if (mark->group == group) { fsnotify_get_mark(mark); return mark; @@ -144,7 +140,6 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, struct vfsmount *mnt, int allow_dups) { - struct mount *m = real_mount(mnt); struct fsnotify_mark *lmark; struct hlist_node *node, *last = NULL; int ret = 0; @@ -159,13 +154,13 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, mark->m.mnt = mnt; /* is mark the first mark? */ - if (hlist_empty(&m->mnt_fsnotify_marks)) { - hlist_add_head_rcu(&mark->m.m_list, &m->mnt_fsnotify_marks); + if (hlist_empty(&mnt->mnt_fsnotify_marks)) { + hlist_add_head_rcu(&mark->m.m_list, &mnt->mnt_fsnotify_marks); goto out; } /* should mark be in the middle of the current list? */ - hlist_for_each_entry(lmark, node, &m->mnt_fsnotify_marks, m.m_list) { + hlist_for_each_entry(lmark, node, &mnt->mnt_fsnotify_marks, m.m_list) { last = node; if ((lmark->group == group) && !allow_dups) { diff --git a/trunk/fs/pnode.c b/trunk/fs/pnode.c index ab5fa9e1a79a..4d5a06ea57a2 100644 --- a/trunk/fs/pnode.c +++ b/trunk/fs/pnode.c @@ -13,30 +13,30 @@ #include "pnode.h" /* return the next shared peer mount of @p */ -static inline struct mount *next_peer(struct mount *p) +static inline struct vfsmount *next_peer(struct vfsmount *p) { - return list_entry(p->mnt_share.next, struct mount, mnt_share); + return list_entry(p->mnt_share.next, struct vfsmount, mnt_share); } -static inline struct mount *first_slave(struct mount *p) +static inline struct vfsmount *first_slave(struct vfsmount *p) { - return list_entry(p->mnt_slave_list.next, struct mount, mnt_slave); + return list_entry(p->mnt_slave_list.next, struct vfsmount, mnt_slave); } -static inline struct mount *next_slave(struct mount *p) +static inline struct vfsmount *next_slave(struct vfsmount *p) { - return list_entry(p->mnt_slave.next, struct mount, mnt_slave); + return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave); } -static struct mount *get_peer_under_root(struct mount *mnt, - struct mnt_namespace *ns, - const struct path *root) +static struct vfsmount *get_peer_under_root(struct vfsmount *mnt, + struct mnt_namespace *ns, + const struct path *root) { - struct mount *m = mnt; + struct vfsmount *m = mnt; do { /* Check the namespace first for optimization */ - if (m->mnt_ns == ns && is_path_reachable(m, m->mnt.mnt_root, root)) + if (m->mnt_ns == ns && is_path_reachable(m, m->mnt_root, root)) return m; m = next_peer(m); @@ -51,12 +51,12 @@ static struct mount *get_peer_under_root(struct mount *mnt, * * Caller must hold namespace_sem */ -int get_dominating_id(struct mount *mnt, const struct path *root) +int get_dominating_id(struct vfsmount *mnt, const struct path *root) { - struct mount *m; + struct vfsmount *m; for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) { - struct mount *d = get_peer_under_root(m, mnt->mnt_ns, root); + struct vfsmount *d = get_peer_under_root(m, mnt->mnt_ns, root); if (d) return d->mnt_group_id; } @@ -64,10 +64,10 @@ int get_dominating_id(struct mount *mnt, const struct path *root) return 0; } -static int do_make_slave(struct mount *mnt) +static int do_make_slave(struct vfsmount *mnt) { - struct mount *peer_mnt = mnt, *master = mnt->mnt_master; - struct mount *slave_mnt; + struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; + struct vfsmount *slave_mnt; /* * slave 'mnt' to a peer mount that has the @@ -75,7 +75,7 @@ static int do_make_slave(struct mount *mnt) * slave it to anything that is available. */ while ((peer_mnt = next_peer(peer_mnt)) != mnt && - peer_mnt->mnt.mnt_root != mnt->mnt.mnt_root) ; + peer_mnt->mnt_root != mnt->mnt_root) ; if (peer_mnt == mnt) { peer_mnt = next_peer(mnt); @@ -101,7 +101,7 @@ static int do_make_slave(struct mount *mnt) struct list_head *p = &mnt->mnt_slave_list; while (!list_empty(p)) { slave_mnt = list_first_entry(p, - struct mount, mnt_slave); + struct vfsmount, mnt_slave); list_del_init(&slave_mnt->mnt_slave); slave_mnt->mnt_master = NULL; } @@ -114,7 +114,7 @@ static int do_make_slave(struct mount *mnt) /* * vfsmount lock must be held for write */ -void change_mnt_propagation(struct mount *mnt, int type) +void change_mnt_propagation(struct vfsmount *mnt, int type) { if (type == MS_SHARED) { set_mnt_shared(mnt); @@ -125,9 +125,9 @@ void change_mnt_propagation(struct mount *mnt, int type) list_del_init(&mnt->mnt_slave); mnt->mnt_master = NULL; if (type == MS_UNBINDABLE) - mnt->mnt.mnt_flags |= MNT_UNBINDABLE; + mnt->mnt_flags |= MNT_UNBINDABLE; else - mnt->mnt.mnt_flags &= ~MNT_UNBINDABLE; + mnt->mnt_flags &= ~MNT_UNBINDABLE; } } @@ -141,19 +141,20 @@ void change_mnt_propagation(struct mount *mnt, int type) * vfsmount found while iterating with propagation_next() is * a peer of one we'd found earlier. */ -static struct mount *propagation_next(struct mount *m, - struct mount *origin) +static struct vfsmount *propagation_next(struct vfsmount *m, + struct vfsmount *origin) { /* are there any slaves of this mount? */ if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) return first_slave(m); while (1) { - struct mount *master = m->mnt_master; + struct vfsmount *next; + struct vfsmount *master = m->mnt_master; if (master == origin->mnt_master) { - struct mount *next = next_peer(m); - return (next == origin) ? NULL : next; + next = next_peer(m); + return ((next == origin) ? NULL : next); } else if (m->mnt_slave.next != &master->mnt_slave_list) return next_slave(m); @@ -171,13 +172,13 @@ static struct mount *propagation_next(struct mount *m, * @type return CL_SLAVE if the new mount has to be * cloned as a slave. */ -static struct mount *get_source(struct mount *dest, - struct mount *last_dest, - struct mount *last_src, - int *type) +static struct vfsmount *get_source(struct vfsmount *dest, + struct vfsmount *last_dest, + struct vfsmount *last_src, + int *type) { - struct mount *p_last_src = NULL; - struct mount *p_last_dest = NULL; + struct vfsmount *p_last_src = NULL; + struct vfsmount *p_last_dest = NULL; while (last_dest != dest->mnt_master) { p_last_dest = last_dest; @@ -217,33 +218,33 @@ static struct mount *get_source(struct mount *dest, * @source_mnt: source mount. * @tree_list : list of heads of trees to be attached. */ -int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry, - struct mount *source_mnt, struct list_head *tree_list) +int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, + struct vfsmount *source_mnt, struct list_head *tree_list) { - struct mount *m, *child; + struct vfsmount *m, *child; int ret = 0; - struct mount *prev_dest_mnt = dest_mnt; - struct mount *prev_src_mnt = source_mnt; + struct vfsmount *prev_dest_mnt = dest_mnt; + struct vfsmount *prev_src_mnt = source_mnt; LIST_HEAD(tmp_list); LIST_HEAD(umount_list); for (m = propagation_next(dest_mnt, dest_mnt); m; m = propagation_next(m, dest_mnt)) { int type; - struct mount *source; + struct vfsmount *source; if (IS_MNT_NEW(m)) continue; source = get_source(m, prev_dest_mnt, prev_src_mnt, &type); - if (!(child = copy_tree(source, source->mnt.mnt_root, type))) { + if (!(child = copy_tree(source, source->mnt_root, type))) { ret = -ENOMEM; list_splice(tree_list, tmp_list.prev); goto out; } - if (is_subdir(dest_dentry, m->mnt.mnt_root)) { + if (is_subdir(dest_dentry, m->mnt_root)) { mnt_set_mountpoint(m, dest_dentry, child); list_add_tail(&child->mnt_hash, tree_list); } else { @@ -259,7 +260,7 @@ int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry, out: br_write_lock(vfsmount_lock); while (!list_empty(&tmp_list)) { - child = list_first_entry(&tmp_list, struct mount, mnt_hash); + child = list_first_entry(&tmp_list, struct vfsmount, mnt_hash); umount_tree(child, 0, &umount_list); } br_write_unlock(vfsmount_lock); @@ -270,7 +271,7 @@ int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry, /* * return true if the refcount is greater than count */ -static inline int do_refcount_check(struct mount *mnt, int count) +static inline int do_refcount_check(struct vfsmount *mnt, int count) { int mycount = mnt_get_count(mnt) - mnt->mnt_ghosts; return (mycount > count); @@ -286,10 +287,10 @@ static inline int do_refcount_check(struct mount *mnt, int count) * * vfsmount lock must be held for write */ -int propagate_mount_busy(struct mount *mnt, int refcnt) +int propagate_mount_busy(struct vfsmount *mnt, int refcnt) { - struct mount *m, *child; - struct mount *parent = mnt->mnt_parent; + struct vfsmount *m, *child; + struct vfsmount *parent = mnt->mnt_parent; int ret = 0; if (mnt == parent) @@ -305,7 +306,7 @@ int propagate_mount_busy(struct mount *mnt, int refcnt) for (m = propagation_next(parent, parent); m; m = propagation_next(m, parent)) { - child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint, 0); + child = __lookup_mnt(m, mnt->mnt_mountpoint, 0); if (child && list_empty(&child->mnt_mounts) && (ret = do_refcount_check(child, 1))) break; @@ -317,17 +318,17 @@ int propagate_mount_busy(struct mount *mnt, int refcnt) * NOTE: unmounting 'mnt' naturally propagates to all other mounts its * parent propagates to. */ -static void __propagate_umount(struct mount *mnt) +static void __propagate_umount(struct vfsmount *mnt) { - struct mount *parent = mnt->mnt_parent; - struct mount *m; + struct vfsmount *parent = mnt->mnt_parent; + struct vfsmount *m; BUG_ON(parent == mnt); for (m = propagation_next(parent, parent); m; m = propagation_next(m, parent)) { - struct mount *child = __lookup_mnt(&m->mnt, + struct vfsmount *child = __lookup_mnt(m, mnt->mnt_mountpoint, 0); /* * umount the child only if the child has no @@ -347,7 +348,7 @@ static void __propagate_umount(struct mount *mnt) */ int propagate_umount(struct list_head *list) { - struct mount *mnt; + struct vfsmount *mnt; list_for_each_entry(mnt, list, mnt_hash) __propagate_umount(mnt); diff --git a/trunk/fs/pnode.h b/trunk/fs/pnode.h index 65c60979d541..5c234e742193 100644 --- a/trunk/fs/pnode.h +++ b/trunk/fs/pnode.h @@ -11,11 +11,11 @@ #include #include "mount.h" -#define IS_MNT_SHARED(m) ((m)->mnt.mnt_flags & MNT_SHARED) -#define IS_MNT_SLAVE(m) ((m)->mnt_master) -#define IS_MNT_NEW(m) (!(m)->mnt_ns) -#define CLEAR_MNT_SHARED(m) ((m)->mnt.mnt_flags &= ~MNT_SHARED) -#define IS_MNT_UNBINDABLE(m) ((m)->mnt.mnt_flags & MNT_UNBINDABLE) +#define IS_MNT_SHARED(mnt) ((mnt)->mnt_flags & MNT_SHARED) +#define IS_MNT_SLAVE(mnt) ((mnt)->mnt_master) +#define IS_MNT_NEW(mnt) (!(mnt)->mnt_ns) +#define CLEAR_MNT_SHARED(mnt) ((mnt)->mnt_flags &= ~MNT_SHARED) +#define IS_MNT_UNBINDABLE(mnt) ((mnt)->mnt_flags & MNT_UNBINDABLE) #define CL_EXPIRE 0x01 #define CL_SLAVE 0x02 @@ -23,25 +23,25 @@ #define CL_MAKE_SHARED 0x08 #define CL_PRIVATE 0x10 -static inline void set_mnt_shared(struct mount *mnt) +static inline void set_mnt_shared(struct vfsmount *mnt) { - mnt->mnt.mnt_flags &= ~MNT_SHARED_MASK; - mnt->mnt.mnt_flags |= MNT_SHARED; + mnt->mnt_flags &= ~MNT_SHARED_MASK; + mnt->mnt_flags |= MNT_SHARED; } -void change_mnt_propagation(struct mount *, int); -int propagate_mnt(struct mount *, struct dentry *, struct mount *, +void change_mnt_propagation(struct vfsmount *, int); +int propagate_mnt(struct vfsmount *, struct dentry *, struct vfsmount *, struct list_head *); int propagate_umount(struct list_head *); -int propagate_mount_busy(struct mount *, int); -void mnt_release_group_id(struct mount *); -int get_dominating_id(struct mount *mnt, const struct path *root); -unsigned int mnt_get_count(struct mount *mnt); -void mnt_set_mountpoint(struct mount *, struct dentry *, - struct mount *); +int propagate_mount_busy(struct vfsmount *, int); +void mnt_release_group_id(struct vfsmount *); +int get_dominating_id(struct vfsmount *mnt, const struct path *root); +unsigned int mnt_get_count(struct vfsmount *mnt); +void mnt_set_mountpoint(struct vfsmount *, struct dentry *, + struct vfsmount *); void release_mounts(struct list_head *); -void umount_tree(struct mount *, int, struct list_head *); -struct mount *copy_tree(struct mount *, struct dentry *, int); -bool is_path_reachable(struct mount *, struct dentry *, +void umount_tree(struct vfsmount *, int, struct list_head *); +struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); +bool is_path_reachable(struct vfsmount *, struct dentry *, const struct path *root); #endif /* _LINUX_PNODE_H */ diff --git a/trunk/fs/proc/base.c b/trunk/fs/proc/base.c index 07446b55b7cc..851ba3dcdc29 100644 --- a/trunk/fs/proc/base.c +++ b/trunk/fs/proc/base.c @@ -631,6 +631,120 @@ static const struct inode_operations proc_def_inode_operations = { .setattr = proc_setattr, }; +static int mounts_open_common(struct inode *inode, struct file *file, + const struct seq_operations *op) +{ + struct task_struct *task = get_proc_task(inode); + struct nsproxy *nsp; + struct mnt_namespace *ns = NULL; + struct path root; + struct proc_mounts *p; + int ret = -EINVAL; + + if (task) { + rcu_read_lock(); + nsp = task_nsproxy(task); + if (nsp) { + ns = nsp->mnt_ns; + if (ns) + get_mnt_ns(ns); + } + rcu_read_unlock(); + if (ns && get_task_root(task, &root) == 0) + ret = 0; + put_task_struct(task); + } + + if (!ns) + goto err; + if (ret) + goto err_put_ns; + + ret = -ENOMEM; + p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); + if (!p) + goto err_put_path; + + file->private_data = &p->m; + ret = seq_open(file, op); + if (ret) + goto err_free; + + p->m.private = p; + p->ns = ns; + p->root = root; + p->m.poll_event = ns->event; + + return 0; + + err_free: + kfree(p); + err_put_path: + path_put(&root); + err_put_ns: + put_mnt_ns(ns); + err: + return ret; +} + +static int mounts_release(struct inode *inode, struct file *file) +{ + struct proc_mounts *p = file->private_data; + path_put(&p->root); + put_mnt_ns(p->ns); + return seq_release(inode, file); +} + +static unsigned mounts_poll(struct file *file, poll_table *wait) +{ + struct proc_mounts *p = file->private_data; + unsigned res = POLLIN | POLLRDNORM; + + poll_wait(file, &p->ns->poll, wait); + if (mnt_had_events(p)) + res |= POLLERR | POLLPRI; + + return res; +} + +static int mounts_open(struct inode *inode, struct file *file) +{ + return mounts_open_common(inode, file, &mounts_op); +} + +static const struct file_operations proc_mounts_operations = { + .open = mounts_open, + .read = seq_read, + .llseek = seq_lseek, + .release = mounts_release, + .poll = mounts_poll, +}; + +static int mountinfo_open(struct inode *inode, struct file *file) +{ + return mounts_open_common(inode, file, &mountinfo_op); +} + +static const struct file_operations proc_mountinfo_operations = { + .open = mountinfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = mounts_release, + .poll = mounts_poll, +}; + +static int mountstats_open(struct inode *inode, struct file *file) +{ + return mounts_open_common(inode, file, &mountstats_op); +} + +static const struct file_operations proc_mountstats_operations = { + .open = mountstats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = mounts_release, +}; + #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ static ssize_t proc_info_read(struct file * file, char __user * buf, diff --git a/trunk/fs/proc/namespaces.c b/trunk/fs/proc/namespaces.c index 27da860115c6..be177f702acb 100644 --- a/trunk/fs/proc/namespaces.c +++ b/trunk/fs/proc/namespaces.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include "internal.h" diff --git a/trunk/fs/proc_namespace.c b/trunk/fs/proc_namespace.c deleted file mode 100644 index 9dcd9543ca12..000000000000 --- a/trunk/fs/proc_namespace.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * fs/proc_namespace.c - handling of /proc//{mounts,mountinfo,mountstats} - * - * In fact, that's a piece of procfs; it's *almost* isolated from - * the rest of fs/proc, but has rather close relationships with - * fs/namespace.c, thus here instead of fs/proc - * - */ -#include -#include -#include -#include -#include "proc/internal.h" /* only for get_proc_task() in ->open() */ - -#include "pnode.h" -#include "internal.h" - -static unsigned mounts_poll(struct file *file, poll_table *wait) -{ - struct proc_mounts *p = file->private_data; - struct mnt_namespace *ns = p->ns; - unsigned res = POLLIN | POLLRDNORM; - - poll_wait(file, &p->ns->poll, wait); - - br_read_lock(vfsmount_lock); - if (p->m.poll_event != ns->event) { - p->m.poll_event = ns->event; - res |= POLLERR | POLLPRI; - } - br_read_unlock(vfsmount_lock); - - return res; -} - -struct proc_fs_info { - int flag; - const char *str; -}; - -static int show_sb_opts(struct seq_file *m, struct super_block *sb) -{ - static const struct proc_fs_info fs_info[] = { - { MS_SYNCHRONOUS, ",sync" }, - { MS_DIRSYNC, ",dirsync" }, - { MS_MANDLOCK, ",mand" }, - { 0, NULL } - }; - const struct proc_fs_info *fs_infop; - - for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { - if (sb->s_flags & fs_infop->flag) - seq_puts(m, fs_infop->str); - } - - return security_sb_show_options(m, sb); -} - -static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) -{ - static const struct proc_fs_info mnt_info[] = { - { MNT_NOSUID, ",nosuid" }, - { MNT_NODEV, ",nodev" }, - { MNT_NOEXEC, ",noexec" }, - { MNT_NOATIME, ",noatime" }, - { MNT_NODIRATIME, ",nodiratime" }, - { MNT_RELATIME, ",relatime" }, - { 0, NULL } - }; - const struct proc_fs_info *fs_infop; - - for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { - if (mnt->mnt_flags & fs_infop->flag) - seq_puts(m, fs_infop->str); - } -} - -static inline void mangle(struct seq_file *m, const char *s) -{ - seq_escape(m, s, " \t\n\\"); -} - -static void show_type(struct seq_file *m, struct super_block *sb) -{ - mangle(m, sb->s_type->name); - if (sb->s_subtype && sb->s_subtype[0]) { - seq_putc(m, '.'); - mangle(m, sb->s_subtype); - } -} - -static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt) -{ - struct mount *r = real_mount(mnt); - int err = 0; - struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; - - if (mnt->mnt_sb->s_op->show_devname) { - err = mnt->mnt_sb->s_op->show_devname(m, mnt); - if (err) - goto out; - } else { - mangle(m, r->mnt_devname ? r->mnt_devname : "none"); - } - seq_putc(m, ' '); - seq_path(m, &mnt_path, " \t\n\\"); - seq_putc(m, ' '); - show_type(m, mnt->mnt_sb); - seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); - err = show_sb_opts(m, mnt->mnt_sb); - if (err) - goto out; - show_mnt_opts(m, mnt); - if (mnt->mnt_sb->s_op->show_options) - err = mnt->mnt_sb->s_op->show_options(m, mnt); - seq_puts(m, " 0 0\n"); -out: - return err; -} - -static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt) -{ - struct proc_mounts *p = m->private; - struct mount *r = real_mount(mnt); - struct super_block *sb = mnt->mnt_sb; - struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; - struct path root = p->root; - int err = 0; - - seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id, - MAJOR(sb->s_dev), MINOR(sb->s_dev)); - if (sb->s_op->show_path) - err = sb->s_op->show_path(m, mnt); - else - seq_dentry(m, mnt->mnt_root, " \t\n\\"); - if (err) - goto out; - seq_putc(m, ' '); - - /* mountpoints outside of chroot jail will give SEQ_SKIP on this */ - err = seq_path_root(m, &mnt_path, &root, " \t\n\\"); - if (err) - goto out; - - seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw"); - show_mnt_opts(m, mnt); - - /* Tagged fields ("foo:X" or "bar") */ - if (IS_MNT_SHARED(r)) - seq_printf(m, " shared:%i", r->mnt_group_id); - if (IS_MNT_SLAVE(r)) { - int master = r->mnt_master->mnt_group_id; - int dom = get_dominating_id(r, &p->root); - seq_printf(m, " master:%i", master); - if (dom && dom != master) - seq_printf(m, " propagate_from:%i", dom); - } - if (IS_MNT_UNBINDABLE(r)) - seq_puts(m, " unbindable"); - - /* Filesystem specific data */ - seq_puts(m, " - "); - show_type(m, sb); - seq_putc(m, ' '); - if (sb->s_op->show_devname) - err = sb->s_op->show_devname(m, mnt); - else - mangle(m, r->mnt_devname ? r->mnt_devname : "none"); - if (err) - goto out; - seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw"); - err = show_sb_opts(m, sb); - if (err) - goto out; - if (sb->s_op->show_options) - err = sb->s_op->show_options(m, mnt); - seq_putc(m, '\n'); -out: - return err; -} - -static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt) -{ - struct mount *r = real_mount(mnt); - struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; - int err = 0; - - /* device */ - if (mnt->mnt_sb->s_op->show_devname) { - seq_puts(m, "device "); - err = mnt->mnt_sb->s_op->show_devname(m, mnt); - } else { - if (r->mnt_devname) { - seq_puts(m, "device "); - mangle(m, r->mnt_devname); - } else - seq_puts(m, "no device"); - } - - /* mount point */ - seq_puts(m, " mounted on "); - seq_path(m, &mnt_path, " \t\n\\"); - seq_putc(m, ' '); - - /* file system type */ - seq_puts(m, "with fstype "); - show_type(m, mnt->mnt_sb); - - /* optional statistics */ - if (mnt->mnt_sb->s_op->show_stats) { - seq_putc(m, ' '); - if (!err) - err = mnt->mnt_sb->s_op->show_stats(m, mnt); - } - - seq_putc(m, '\n'); - return err; -} - -static int mounts_open_common(struct inode *inode, struct file *file, - int (*show)(struct seq_file *, struct vfsmount *)) -{ - struct task_struct *task = get_proc_task(inode); - struct nsproxy *nsp; - struct mnt_namespace *ns = NULL; - struct path root; - struct proc_mounts *p; - int ret = -EINVAL; - - if (!task) - goto err; - - rcu_read_lock(); - nsp = task_nsproxy(task); - if (!nsp) { - rcu_read_unlock(); - put_task_struct(task); - goto err; - } - ns = nsp->mnt_ns; - if (!ns) { - rcu_read_unlock(); - put_task_struct(task); - goto err; - } - get_mnt_ns(ns); - rcu_read_unlock(); - task_lock(task); - if (!task->fs) { - task_unlock(task); - put_task_struct(task); - ret = -ENOENT; - goto err_put_ns; - } - get_fs_root(task->fs, &root); - task_unlock(task); - put_task_struct(task); - - ret = -ENOMEM; - p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); - if (!p) - goto err_put_path; - - file->private_data = &p->m; - ret = seq_open(file, &mounts_op); - if (ret) - goto err_free; - - p->m.private = p; - p->ns = ns; - p->root = root; - p->m.poll_event = ns->event; - p->show = show; - - return 0; - - err_free: - kfree(p); - err_put_path: - path_put(&root); - err_put_ns: - put_mnt_ns(ns); - err: - return ret; -} - -static int mounts_release(struct inode *inode, struct file *file) -{ - struct proc_mounts *p = file->private_data; - path_put(&p->root); - put_mnt_ns(p->ns); - return seq_release(inode, file); -} - -static int mounts_open(struct inode *inode, struct file *file) -{ - return mounts_open_common(inode, file, show_vfsmnt); -} - -static int mountinfo_open(struct inode *inode, struct file *file) -{ - return mounts_open_common(inode, file, show_mountinfo); -} - -static int mountstats_open(struct inode *inode, struct file *file) -{ - return mounts_open_common(inode, file, show_vfsstat); -} - -const struct file_operations proc_mounts_operations = { - .open = mounts_open, - .read = seq_read, - .llseek = seq_lseek, - .release = mounts_release, - .poll = mounts_poll, -}; - -const struct file_operations proc_mountinfo_operations = { - .open = mountinfo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = mounts_release, - .poll = mounts_poll, -}; - -const struct file_operations proc_mountstats_operations = { - .open = mountstats_open, - .read = seq_read, - .llseek = seq_lseek, - .release = mounts_release, -}; diff --git a/trunk/include/linux/mnt_namespace.h b/trunk/include/linux/mnt_namespace.h index 5a8e3903d770..e87ec01aac9d 100644 --- a/trunk/include/linux/mnt_namespace.h +++ b/trunk/include/linux/mnt_namespace.h @@ -2,16 +2,38 @@ #define _NAMESPACE_H_ #ifdef __KERNEL__ -struct mnt_namespace; +#include +#include +#include + +struct mnt_namespace { + atomic_t count; + struct vfsmount * root; + struct list_head list; + wait_queue_head_t poll; + int event; +}; + +struct proc_mounts { + struct seq_file m; /* must be the first element */ + struct mnt_namespace *ns; + struct path root; +}; + struct fs_struct; extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, struct fs_struct *); extern void put_mnt_ns(struct mnt_namespace *ns); +static inline void get_mnt_ns(struct mnt_namespace *ns) +{ + atomic_inc(&ns->count); +} -extern const struct file_operations proc_mounts_operations; -extern const struct file_operations proc_mountinfo_operations; -extern const struct file_operations proc_mountstats_operations; +extern const struct seq_operations mounts_op; +extern const struct seq_operations mountinfo_op; +extern const struct seq_operations mountstats_op; +extern int mnt_had_events(struct proc_mounts *); #endif #endif diff --git a/trunk/include/linux/mount.h b/trunk/include/linux/mount.h index d7029f4a191a..00f5c4f2160b 100644 --- a/trunk/include/linux/mount.h +++ b/trunk/include/linux/mount.h @@ -47,10 +47,45 @@ struct mnt_namespace; #define MNT_INTERNAL 0x4000 +struct mnt_pcp { + int mnt_count; + int mnt_writers; +}; + struct vfsmount { + struct list_head mnt_hash; + struct vfsmount *mnt_parent; /* fs we are mounted on */ + struct dentry *mnt_mountpoint; /* dentry of mountpoint */ struct dentry *mnt_root; /* root of the mounted tree */ struct super_block *mnt_sb; /* pointer to superblock */ +#ifdef CONFIG_SMP + struct mnt_pcp __percpu *mnt_pcp; + atomic_t mnt_longterm; /* how many of the refs are longterm */ +#else + int mnt_count; + int mnt_writers; +#endif + struct list_head mnt_mounts; /* list of children, anchored here */ + struct list_head mnt_child; /* and going through their mnt_child */ int mnt_flags; + /* 4 bytes hole on 64bits arches without fsnotify */ +#ifdef CONFIG_FSNOTIFY + __u32 mnt_fsnotify_mask; + struct hlist_head mnt_fsnotify_marks; +#endif + const char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ + struct list_head mnt_list; + struct list_head mnt_expire; /* link in fs-specific expiry list */ + struct list_head mnt_share; /* circular list of shared mounts */ + struct list_head mnt_slave_list;/* list of slave mounts */ + struct list_head mnt_slave; /* slave list entry */ + struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */ + struct mnt_namespace *mnt_ns; /* containing namespace */ + int mnt_id; /* mount identifier */ + int mnt_group_id; /* peer group identifier */ + int mnt_expiry_mark; /* true if marked for expiry */ + int mnt_pinned; + int mnt_ghosts; }; struct file; /* forward dec */ diff --git a/trunk/include/linux/syscalls.h b/trunk/include/linux/syscalls.h index 86a24b1166d1..b3c16d8a6383 100644 --- a/trunk/include/linux/syscalls.h +++ b/trunk/include/linux/syscalls.h @@ -475,7 +475,7 @@ asmlinkage long sys_mincore(unsigned long start, size_t len, asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *put_old); asmlinkage long sys_chroot(const char __user *filename); -asmlinkage long sys_mknod(const char __user *filename, int mode, +asmlinkage long sys_mknod(const char __user *filename, umode_t mode, unsigned dev); asmlinkage long sys_link(const char __user *oldname, const char __user *newname); @@ -755,7 +755,7 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, asmlinkage long sys_spu_create(const char __user *name, unsigned int flags, mode_t mode, int fd); -asmlinkage long sys_mknodat(int dfd, const char __user * filename, int mode, +asmlinkage long sys_mknodat(int dfd, const char __user * filename, umode_t mode, unsigned dev); asmlinkage long sys_mkdirat(int dfd, const char __user * pathname, int mode); asmlinkage long sys_unlinkat(int dfd, const char __user * pathname, int flag); diff --git a/trunk/security/tomoyo/realpath.c b/trunk/security/tomoyo/realpath.c index 80a09c37cac8..2cb5db589c9d 100644 --- a/trunk/security/tomoyo/realpath.c +++ b/trunk/security/tomoyo/realpath.c @@ -5,7 +5,6 @@ */ #include "common.h" -#include /** * tomoyo_encode2 - Encode binary string to ascii string.