diff options
Diffstat (limited to 'fs/pnode.c')
| -rw-r--r-- | fs/pnode.c | 54 |
1 files changed, 51 insertions, 3 deletions
diff --git a/fs/pnode.c b/fs/pnode.c index 7bc942d047cd..f73eba24f1d1 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
| @@ -17,13 +17,61 @@ static inline struct vfsmount *next_peer(struct vfsmount *p) | |||
| 17 | return list_entry(p->mnt_share.next, struct vfsmount, mnt_share); | 17 | return list_entry(p->mnt_share.next, struct vfsmount, mnt_share); |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | static int do_make_slave(struct vfsmount *mnt) | ||
| 21 | { | ||
| 22 | struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; | ||
| 23 | struct vfsmount *slave_mnt; | ||
| 24 | |||
| 25 | /* | ||
| 26 | * slave 'mnt' to a peer mount that has the | ||
| 27 | * same root dentry. If none is available than | ||
| 28 | * slave it to anything that is available. | ||
| 29 | */ | ||
| 30 | while ((peer_mnt = next_peer(peer_mnt)) != mnt && | ||
| 31 | peer_mnt->mnt_root != mnt->mnt_root) ; | ||
| 32 | |||
| 33 | if (peer_mnt == mnt) { | ||
| 34 | peer_mnt = next_peer(mnt); | ||
| 35 | if (peer_mnt == mnt) | ||
| 36 | peer_mnt = NULL; | ||
| 37 | } | ||
| 38 | list_del_init(&mnt->mnt_share); | ||
| 39 | |||
| 40 | if (peer_mnt) | ||
| 41 | master = peer_mnt; | ||
| 42 | |||
| 43 | if (master) { | ||
| 44 | list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave) | ||
| 45 | slave_mnt->mnt_master = master; | ||
| 46 | list_del(&mnt->mnt_slave); | ||
| 47 | list_add(&mnt->mnt_slave, &master->mnt_slave_list); | ||
| 48 | list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev); | ||
| 49 | INIT_LIST_HEAD(&mnt->mnt_slave_list); | ||
| 50 | } else { | ||
| 51 | struct list_head *p = &mnt->mnt_slave_list; | ||
| 52 | while (!list_empty(p)) { | ||
| 53 | slave_mnt = list_entry(p->next, | ||
| 54 | struct vfsmount, mnt_slave); | ||
| 55 | list_del_init(&slave_mnt->mnt_slave); | ||
| 56 | slave_mnt->mnt_master = NULL; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | mnt->mnt_master = master; | ||
| 60 | CLEAR_MNT_SHARED(mnt); | ||
| 61 | INIT_LIST_HEAD(&mnt->mnt_slave_list); | ||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | |||
| 20 | void change_mnt_propagation(struct vfsmount *mnt, int type) | 65 | void change_mnt_propagation(struct vfsmount *mnt, int type) |
| 21 | { | 66 | { |
| 22 | if (type == MS_SHARED) { | 67 | if (type == MS_SHARED) { |
| 23 | set_mnt_shared(mnt); | 68 | set_mnt_shared(mnt); |
| 24 | } else { | 69 | return; |
| 25 | list_del_init(&mnt->mnt_share); | 70 | } |
| 26 | mnt->mnt_flags &= ~MNT_PNODE_MASK; | 71 | do_make_slave(mnt); |
| 72 | if (type != MS_SLAVE) { | ||
| 73 | list_del_init(&mnt->mnt_slave); | ||
| 74 | mnt->mnt_master = NULL; | ||
| 27 | } | 75 | } |
| 28 | } | 76 | } |
| 29 | 77 | ||
