X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Fpnode.c;h=8d5f392ec3d39fa12a025ec3a6045b7ef8f790a4;hb=84814d642a4f1f294bd675ab11aae1ca54c6cedb;hp=aeeec8ba8dd28b9ac4a77ee513fb23423b55d458;hpb=9676f0c6389b62bd6b24d77d4b3abdbcfa32d0f2;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/pnode.c b/fs/pnode.c index aeeec8b..8d5f392 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -6,9 +6,10 @@ * Author : Ram Pai (linuxram@us.ibm.com) * */ -#include +#include #include #include +#include "internal.h" #include "pnode.h" /* return the next shared peer mount of @p */ @@ -27,6 +28,57 @@ static inline struct vfsmount *next_slave(struct vfsmount *p) return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave); } +/* + * Return true if path is reachable from root + * + * namespace_sem is held, and mnt is attached + */ +static bool is_path_reachable(struct vfsmount *mnt, struct dentry *dentry, + const struct path *root) +{ + while (mnt != root->mnt && mnt->mnt_parent != mnt) { + dentry = mnt->mnt_mountpoint; + mnt = mnt->mnt_parent; + } + return mnt == root->mnt && is_subdir(dentry, root->dentry); +} + +static struct vfsmount *get_peer_under_root(struct vfsmount *mnt, + struct mnt_namespace *ns, + const struct path *root) +{ + struct vfsmount *m = mnt; + + do { + /* Check the namespace first for optimization */ + if (m->mnt_ns == ns && is_path_reachable(m, m->mnt_root, root)) + return m; + + m = next_peer(m); + } while (m != mnt); + + return NULL; +} + +/* + * Get ID of closest dominating peer group having a representative + * under the given root. + * + * Caller must hold namespace_sem + */ +int get_dominating_id(struct vfsmount *mnt, const struct path *root) +{ + struct vfsmount *m; + + for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) { + struct vfsmount *d = get_peer_under_root(m, mnt->mnt_ns, root); + if (d) + return d->mnt_group_id; + } + + return 0; +} + static int do_make_slave(struct vfsmount *mnt) { struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; @@ -45,7 +97,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; @@ -53,14 +109,13 @@ static int do_make_slave(struct vfsmount *mnt) if (master) { list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave) slave_mnt->mnt_master = master; - list_del(&mnt->mnt_slave); - list_add(&mnt->mnt_slave, &master->mnt_slave_list); + list_move(&mnt->mnt_slave, &master->mnt_slave_list); list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev); INIT_LIST_HEAD(&mnt->mnt_slave_list); } else { struct list_head *p = &mnt->mnt_slave_list; while (!list_empty(p)) { - slave_mnt = list_entry(p->next, + slave_mnt = list_first_entry(p, struct vfsmount, mnt_slave); list_del_init(&slave_mnt->mnt_slave); slave_mnt->mnt_master = NULL; @@ -68,7 +123,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; } @@ -84,6 +138,8 @@ void change_mnt_propagation(struct vfsmount *mnt, int type) mnt->mnt_master = NULL; if (type == MS_UNBINDABLE) mnt->mnt_flags |= MNT_UNBINDABLE; + else + mnt->mnt_flags &= ~MNT_UNBINDABLE; } } @@ -103,7 +159,7 @@ static struct vfsmount *propagation_next(struct vfsmount *m, struct vfsmount *next; struct vfsmount *master = m->mnt_master; - if ( master == origin->mnt_master ) { + if (master == origin->mnt_master) { next = next_peer(m); return ((next == origin) ? NULL : next); } else if (m->mnt_slave.next != &master->mnt_slave_list) @@ -130,7 +186,7 @@ static struct vfsmount *get_source(struct vfsmount *dest, { struct vfsmount *p_last_src = NULL; struct vfsmount *p_last_dest = NULL; - *type = CL_PROPAGATION;; + *type = CL_PROPAGATION; if (IS_MNT_SHARED(dest)) *type |= CL_MAKE_SHARED; @@ -210,8 +266,7 @@ int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, out: spin_lock(&vfsmount_lock); while (!list_empty(&tmp_list)) { - child = list_entry(tmp_list.next, struct vfsmount, mnt_hash); - list_del_init(&child->mnt_hash); + child = list_first_entry(&tmp_list, struct vfsmount, mnt_hash); umount_tree(child, 0, &umount_list); } spin_unlock(&vfsmount_lock); @@ -224,7 +279,7 @@ out: */ static inline int do_refcount_check(struct vfsmount *mnt, int count) { - int mycount = atomic_read(&mnt->mnt_count); + int mycount = atomic_read(&mnt->mnt_count) - mnt->mnt_ghosts; return (mycount > count); } @@ -283,10 +338,8 @@ static void __propagate_umount(struct vfsmount *mnt) * umount the child only if the child has no * other children */ - if (child && list_empty(&child->mnt_mounts)) { - list_del(&child->mnt_hash); - list_add_tail(&child->mnt_hash, &mnt->mnt_hash); - } + if (child && list_empty(&child->mnt_mounts)) + list_move_tail(&child->mnt_hash, &mnt->mnt_hash); } }