Skip to content
Snippets Groups Projects
  • Eric W. Biederman's avatar
    8823c079
    vfs: Add setns support for the mount namespace · 8823c079
    Eric W. Biederman authored
    
    setns support for the mount namespace is a little tricky as an
    arbitrary decision must be made about what to set fs->root and
    fs->pwd to, as there is no expectation of a relationship between
    the two mount namespaces.  Therefore I arbitrarily find the root
    mount point, and follow every mount on top of it to find the top
    of the mount stack.  Then I set fs->root and fs->pwd to that
    location.  The topmost root of the mount stack seems like a
    reasonable place to be.
    
    Bind mount support for the mount namespace inodes has the
    possibility of creating circular dependencies between mount
    namespaces.  Circular dependencies can result in loops that
    prevent mount namespaces from every being freed.  I avoid
    creating those circular dependencies by adding a sequence number
    to the mount namespace and require all bind mounts be of a
    younger mount namespace into an older mount namespace.
    
    Add a helper function proc_ns_inode so it is possible to
    detect when we are attempting to bind mound a namespace inode.
    
    Acked-by: default avatarSerge Hallyn <serge.hallyn@canonical.com>
    Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
    8823c079
    History
    vfs: Add setns support for the mount namespace
    Eric W. Biederman authored
    
    setns support for the mount namespace is a little tricky as an
    arbitrary decision must be made about what to set fs->root and
    fs->pwd to, as there is no expectation of a relationship between
    the two mount namespaces.  Therefore I arbitrarily find the root
    mount point, and follow every mount on top of it to find the top
    of the mount stack.  Then I set fs->root and fs->pwd to that
    location.  The topmost root of the mount stack seems like a
    reasonable place to be.
    
    Bind mount support for the mount namespace inodes has the
    possibility of creating circular dependencies between mount
    namespaces.  Circular dependencies can result in loops that
    prevent mount namespaces from every being freed.  I avoid
    creating those circular dependencies by adding a sequence number
    to the mount namespace and require all bind mounts be of a
    younger mount namespace into an older mount namespace.
    
    Add a helper function proc_ns_inode so it is possible to
    detect when we are attempting to bind mound a namespace inode.
    
    Acked-by: default avatarSerge Hallyn <serge.hallyn@canonical.com>
    Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
mount.h 2.26 KiB
#include <linux/mount.h>
#include <linux/seq_file.h>
#include <linux/poll.h>

struct mnt_namespace {
	atomic_t		count;
	struct mount *	root;
	struct list_head	list;
	u64			seq;	/* Sequence number to prevent loops */
	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;
#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 */
	struct list_head mnt_instance;	/* mount instance on sb->s_mounts */
	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;
};

#define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */

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)
{
	return mnt != mnt->mnt_parent;
}

static inline int is_mounted(struct vfsmount *mnt)
{
	/* neither detached nor internal? */
	return !IS_ERR_OR_NULL(real_mount(mnt));
}

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;
	struct mnt_namespace *ns;
	struct path root;
	int (*show)(struct seq_file *, struct vfsmount *);
};

#define proc_mounts(p) (container_of((p), struct proc_mounts, m))

extern const struct seq_operations mounts_op;