Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 91950
b: refs/heads/master
c: 719f5d7
h: refs/heads/master
v: v3
  • Loading branch information
Miklos Szeredi authored and Al Viro committed Apr 23, 2008
1 parent 6bbabd8 commit 3a000bf
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 73cd49ecdde92fdce131938bdaff4993010d181b
refs/heads/master: 719f5d7f0b90ac2c8f8ca4232eb322b266fea01e
93 changes: 90 additions & 3 deletions trunk/fs/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);

static int event;
static DEFINE_IDA(mnt_id_ida);
static DEFINE_IDA(mnt_group_ida);

static struct list_head *mount_hashtable __read_mostly;
static struct kmem_cache *mnt_cache __read_mostly;
Expand Down Expand Up @@ -83,6 +84,28 @@ static void mnt_free_id(struct vfsmount *mnt)
spin_unlock(&vfsmount_lock);
}

/*
* Allocate a new peer group ID
*
* mnt_group_ida is protected by namespace_sem
*/
static int mnt_alloc_group_id(struct vfsmount *mnt)
{
if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL))
return -ENOMEM;

return ida_get_new_above(&mnt_group_ida, 1, &mnt->mnt_group_id);
}

/*
* Release a peer group ID
*/
void mnt_release_group_id(struct vfsmount *mnt)
{
ida_remove(&mnt_group_ida, mnt->mnt_group_id);
mnt->mnt_group_id = 0;
}

struct vfsmount *alloc_vfsmnt(const char *name)
{
struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
Expand Down Expand Up @@ -533,6 +556,17 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname);

if (mnt) {
if (flag & (CL_SLAVE | CL_PRIVATE))
mnt->mnt_group_id = 0; /* not a peer of original */
else
mnt->mnt_group_id = old->mnt_group_id;

if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) {
int err = mnt_alloc_group_id(mnt);
if (err)
goto out_free;
}

mnt->mnt_flags = old->mnt_flags;
atomic_inc(&sb->s_active);
mnt->mnt_sb = sb;
Expand Down Expand Up @@ -562,6 +596,10 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
}
}
return mnt;

out_free:
free_vfsmnt(mnt);
return NULL;
}

static inline void __mntput(struct vfsmount *mnt)
Expand Down Expand Up @@ -1142,6 +1180,33 @@ void drop_collected_mounts(struct vfsmount *mnt)
release_mounts(&umount_list);
}

static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end)
{
struct vfsmount *p;

for (p = mnt; p != end; p = next_mnt(p, mnt)) {
if (p->mnt_group_id && !IS_MNT_SHARED(p))
mnt_release_group_id(p);
}
}

static int invent_group_ids(struct vfsmount *mnt, bool recurse)
{
struct vfsmount *p;

for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) {
if (!p->mnt_group_id && !IS_MNT_SHARED(p)) {
int err = mnt_alloc_group_id(p);
if (err) {
cleanup_group_ids(mnt, p);
return err;
}
}
}

return 0;
}

/*
* @source_mnt : mount tree to be attached
* @nd : place the mount tree @source_mnt is attached
Expand Down Expand Up @@ -1212,9 +1277,16 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
struct vfsmount *dest_mnt = path->mnt;
struct dentry *dest_dentry = path->dentry;
struct vfsmount *child, *p;
int err;

if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list))
return -EINVAL;
if (IS_MNT_SHARED(dest_mnt)) {
err = invent_group_ids(source_mnt, true);
if (err)
goto out;
}
err = propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list);
if (err)
goto out_cleanup_ids;

if (IS_MNT_SHARED(dest_mnt)) {
for (p = source_mnt; p; p = next_mnt(p, source_mnt))
Expand All @@ -1237,6 +1309,12 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
}
spin_unlock(&vfsmount_lock);
return 0;

out_cleanup_ids:
if (IS_MNT_SHARED(dest_mnt))
cleanup_group_ids(source_mnt, NULL);
out:
return err;
}

static int graft_tree(struct vfsmount *mnt, struct path *path)
Expand Down Expand Up @@ -1277,6 +1355,7 @@ static noinline int do_change_type(struct nameidata *nd, int flag)
struct vfsmount *m, *mnt = nd->path.mnt;
int recurse = flag & MS_REC;
int type = flag & ~MS_REC;
int err = 0;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;
Expand All @@ -1285,12 +1364,20 @@ static noinline int do_change_type(struct nameidata *nd, int flag)
return -EINVAL;

down_write(&namespace_sem);
if (type == MS_SHARED) {
err = invent_group_ids(mnt, recurse);
if (err)
goto out_unlock;
}

spin_lock(&vfsmount_lock);
for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL))
change_mnt_propagation(m, type);
spin_unlock(&vfsmount_lock);

out_unlock:
up_write(&namespace_sem);
return 0;
return err;
}

/*
Expand Down
5 changes: 4 additions & 1 deletion trunk/fs/pnode.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ static int do_make_slave(struct vfsmount *mnt)
if (peer_mnt == mnt)
peer_mnt = NULL;
}
if (IS_MNT_SHARED(mnt) && list_empty(&mnt->mnt_share))
mnt_release_group_id(mnt);

list_del_init(&mnt->mnt_share);
mnt->mnt_group_id = 0;

if (peer_mnt)
master = peer_mnt;
Expand All @@ -68,7 +72,6 @@ static int do_make_slave(struct vfsmount *mnt)
}
mnt->mnt_master = master;
CLEAR_MNT_SHARED(mnt);
INIT_LIST_HEAD(&mnt->mnt_slave_list);
return 0;
}

Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct vfsmount {
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 */
/*
* We put mnt_count & mnt_expiry_mark at the end of struct vfsmount
* to let these frequently modified fields in a separate cache line
Expand Down

0 comments on commit 3a000bf

Please sign in to comment.