From: Jan Blunck <jblunck@xxxxxxx> Creates the proper struct union_mount when mounting something into a union. If the topmost filesystem isn't capable of handling the white-out filetype it could only be mount read-only. Signed-off-by: Jan Blunck <jblunck@xxxxxxx> Signed-off-by: Valerie Aurora <vaurora@xxxxxxxxxx> --- fs/namespace.c | 7 ++++++ fs/union.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/mount.h | 3 ++ include/linux/union.h | 10 +++++++- 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index dc01385..0280e5b 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -158,6 +158,9 @@ struct vfsmount *alloc_vfsmnt(const char *name) #else mnt->mnt_writers = 0; #endif +#ifdef CONFIG_UNION_MOUNT + INIT_LIST_HEAD(&mnt->mnt_unions); +#endif } return mnt; @@ -470,6 +473,7 @@ static void __touch_mnt_namespace(struct mnt_namespace *ns) static void detach_mnt(struct vfsmount *mnt, struct path *old_path) { + detach_mnt_union(mnt); old_path->dentry = mnt->mnt_mountpoint; old_path->mnt = mnt->mnt_parent; mnt->mnt_parent = mnt; @@ -493,6 +497,7 @@ static void attach_mnt(struct vfsmount *mnt, struct path *path) list_add_tail(&mnt->mnt_hash, mount_hashtable + hash(path->mnt, path->dentry)); list_add_tail(&mnt->mnt_child, &path->mnt->mnt_mounts); + attach_mnt_union(mnt, path->mnt, path->dentry); } /* @@ -515,6 +520,7 @@ static void commit_tree(struct vfsmount *mnt) list_add_tail(&mnt->mnt_hash, mount_hashtable + hash(parent, mnt->mnt_mountpoint)); list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); + attach_mnt_union(mnt, mnt->mnt_parent, mnt->mnt_mountpoint); touch_mnt_namespace(n); } @@ -986,6 +992,7 @@ void release_mounts(struct list_head *head) struct dentry *dentry; struct vfsmount *m; spin_lock(&vfsmount_lock); + detach_mnt_union(mnt); dentry = mnt->mnt_mountpoint; m = mnt->mnt_parent; mnt->mnt_mountpoint = mnt->mnt_root; diff --git a/fs/union.c b/fs/union.c index 6b99393..341fc03 100644 --- a/fs/union.c +++ b/fs/union.c @@ -113,6 +113,7 @@ struct union_mount *union_alloc(struct dentry *this, struct vfsmount *this_mnt, atomic_set(&um->u_count, 1); INIT_LIST_HEAD(&um->u_unions); + INIT_LIST_HEAD(&um->u_list); INIT_HLIST_NODE(&um->u_hash); INIT_HLIST_NODE(&um->u_rhash); @@ -256,6 +257,7 @@ int append_to_union(struct vfsmount *mnt, struct dentry *dentry, union_put(this); return 0; } + list_add(&this->u_list, &mnt->mnt_unions); list_add(&this->u_unions, &dentry->d_unions); dest_dentry->d_unionized++; __union_hash(this); @@ -365,6 +367,7 @@ repeat: list_for_each_entry_safe(this, next, &dentry->d_unions, u_unions) { BUG_ON(!hlist_unhashed(&this->u_hash)); BUG_ON(!hlist_unhashed(&this->u_rhash)); + list_del(&this->u_list); list_del(&this->u_unions); this->u_next.dentry->d_unionized--; spin_unlock(&union_lock); @@ -393,6 +396,7 @@ repeat: BUG_ON(!hlist_unhashed(&this->u_hash)); BUG_ON(!hlist_unhashed(&this->u_rhash)); + list_del(&this->u_list); list_del(&this->u_unions); this->u_next.dentry->d_unionized--; spin_unlock(&union_lock); @@ -404,3 +408,56 @@ repeat: } spin_unlock(&union_lock); } + +/* + * Remove all union_mounts structures belonging to this vfsmount from the + * union lookup hashtable and so on ... + */ +void shrink_mnt_unions(struct vfsmount *mnt) +{ + struct union_mount *this, *next; + +repeat: + spin_lock(&union_lock); + list_for_each_entry_safe(this, next, &mnt->mnt_unions, u_list) { + if (this->u_this.dentry == mnt->mnt_root) + continue; + __union_unhash(this); + list_del(&this->u_list); + list_del(&this->u_unions); + this->u_next.dentry->d_unionized--; + spin_unlock(&union_lock); + union_put(this); + goto repeat; + } + spin_unlock(&union_lock); +} + +int attach_mnt_union(struct vfsmount *mnt, struct vfsmount *dest_mnt, + struct dentry *dest_dentry) +{ + if (!IS_MNT_UNION(mnt)) + return 0; + + return append_to_union(mnt, mnt->mnt_root, dest_mnt, dest_dentry); +} + +void detach_mnt_union(struct vfsmount *mnt) +{ + struct union_mount *um; + + if (!IS_MNT_UNION(mnt)) + return; + + shrink_mnt_unions(mnt); + + spin_lock(&union_lock); + um = union_lookup(mnt->mnt_root, mnt); + __union_unhash(um); + list_del(&um->u_list); + list_del(&um->u_unions); + um->u_next.dentry->d_unionized--; + spin_unlock(&union_lock); + union_put(um); + return; +} diff --git a/include/linux/mount.h b/include/linux/mount.h index e175c47..70c4f1f 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -54,6 +54,9 @@ struct vfsmount { 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 */ +#ifdef CONFIG_UNION_MOUNT + struct list_head mnt_unions; /* list of union_mount structures */ +#endif struct mnt_namespace *mnt_ns; /* containing namespace */ int mnt_id; /* mount identifier */ int mnt_group_id; /* peer group identifier */ diff --git a/include/linux/union.h b/include/linux/union.h index b035a82..0b6f356 100644 --- a/include/linux/union.h +++ b/include/linux/union.h @@ -30,8 +30,9 @@ struct union_mount { atomic_t u_count; /* reference count */ struct mutex u_mutex; struct list_head u_unions; /* list head for d_unions */ - struct hlist_node u_hash; /* list head for searching */ - struct hlist_node u_rhash; /* list head for reverse searching */ + struct list_head u_list; /* list head for mnt_unions */ + struct hlist_node u_hash; /* list head for seaching */ + struct hlist_node u_rhash; /* list head for reverse seaching */ struct path u_this; /* this is me */ struct path u_next; /* this is what I overlay */ @@ -49,6 +50,9 @@ extern int follow_union_mount(struct vfsmount **, struct dentry **); extern void __d_drop_unions(struct dentry *); extern void shrink_d_unions(struct dentry *); extern void __shrink_d_unions(struct dentry *, struct list_head *); +extern int attach_mnt_union(struct vfsmount *, struct vfsmount *, + struct dentry *); +extern void detach_mnt_union(struct vfsmount *); #else /* CONFIG_UNION_MOUNT */ @@ -61,6 +65,8 @@ extern void __shrink_d_unions(struct dentry *, struct list_head *); #define __d_drop_unions(x) do { } while (0) #define shrink_d_unions(x) do { } while (0) #define __shrink_d_unions(x,y) do { } while (0) +#define attach_mnt_union(x, y, z) do { } while (0) +#define detach_mnt_union(x) do { } while (0) #endif /* CONFIG_UNION_MOUNT */ #endif /* __KERNEL__ */ -- 1.6.3.3 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html