Skip to content

Commit 75db7fd

Browse files
author
Al Viro
committed
umount_tree(): take all victims out of propagation graph at once
For each removed mount we need to calculate where the slaves will end up. To avoid duplicating that work, do it for all mounts to be removed at once, taking the mounts themselves out of propagation graph as we go, then do all transfers; the duplicate work on finding destinations is avoided since if we run into a mount that already had destination found, we don't need to trace the rest of the way. That's guaranteed O(removed mounts) for finding destinations and removing from propagation graph and O(surviving mounts that have master removed) for transfers. Reviewed-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent fc9d5ef commit 75db7fd

3 files changed

Lines changed: 55 additions & 16 deletions

File tree

fs/namespace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1846,6 +1846,8 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
18461846
if (how & UMOUNT_PROPAGATE)
18471847
propagate_umount(&tmp_list);
18481848

1849+
bulk_make_private(&tmp_list);
1850+
18491851
while (!list_empty(&tmp_list)) {
18501852
struct mnt_namespace *ns;
18511853
bool disconnect;
@@ -1870,7 +1872,6 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
18701872
umount_mnt(p);
18711873
}
18721874
}
1873-
change_mnt_propagation(p, MS_PRIVATE);
18741875
if (disconnect)
18751876
hlist_add_head(&p->mnt_umount, &unmounted);
18761877

fs/pnode.c

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,6 @@ static inline bool will_be_unmounted(struct mount *m)
7171
return m->mnt.mnt_flags & MNT_UMOUNT;
7272
}
7373

74-
static struct mount *propagation_source(struct mount *mnt)
75-
{
76-
do {
77-
struct mount *m;
78-
for (m = next_peer(mnt); m != mnt; m = next_peer(m)) {
79-
if (!will_be_unmounted(m))
80-
return m;
81-
}
82-
mnt = mnt->mnt_master;
83-
} while (mnt && will_be_unmounted(mnt));
84-
return mnt;
85-
}
86-
8774
static void transfer_propagation(struct mount *mnt, struct mount *to)
8875
{
8976
struct hlist_node *p = NULL, *n;
@@ -112,11 +99,10 @@ void change_mnt_propagation(struct mount *mnt, int type)
11299
return;
113100
}
114101
if (IS_MNT_SHARED(mnt)) {
115-
if (type == MS_SLAVE || !hlist_empty(&mnt->mnt_slave_list))
116-
m = propagation_source(mnt);
117102
if (list_empty(&mnt->mnt_share)) {
118103
mnt_release_group_id(mnt);
119104
} else {
105+
m = next_peer(mnt);
120106
list_del_init(&mnt->mnt_share);
121107
mnt->mnt_group_id = 0;
122108
}
@@ -137,6 +123,57 @@ void change_mnt_propagation(struct mount *mnt, int type)
137123
}
138124
}
139125

126+
static struct mount *trace_transfers(struct mount *m)
127+
{
128+
while (1) {
129+
struct mount *next = next_peer(m);
130+
131+
if (next != m) {
132+
list_del_init(&m->mnt_share);
133+
m->mnt_group_id = 0;
134+
m->mnt_master = next;
135+
} else {
136+
if (IS_MNT_SHARED(m))
137+
mnt_release_group_id(m);
138+
next = m->mnt_master;
139+
}
140+
hlist_del_init(&m->mnt_slave);
141+
CLEAR_MNT_SHARED(m);
142+
SET_MNT_MARK(m);
143+
144+
if (!next || !will_be_unmounted(next))
145+
return next;
146+
if (IS_MNT_MARKED(next))
147+
return next->mnt_master;
148+
m = next;
149+
}
150+
}
151+
152+
static void set_destinations(struct mount *m, struct mount *master)
153+
{
154+
struct mount *next;
155+
156+
while ((next = m->mnt_master) != master) {
157+
m->mnt_master = master;
158+
m = next;
159+
}
160+
}
161+
162+
void bulk_make_private(struct list_head *set)
163+
{
164+
struct mount *m;
165+
166+
list_for_each_entry(m, set, mnt_list)
167+
if (!IS_MNT_MARKED(m))
168+
set_destinations(m, trace_transfers(m));
169+
170+
list_for_each_entry(m, set, mnt_list) {
171+
transfer_propagation(m, m->mnt_master);
172+
m->mnt_master = NULL;
173+
CLEAR_MNT_MARK(m);
174+
}
175+
}
176+
140177
static struct mount *__propagation_next(struct mount *m,
141178
struct mount *origin)
142179
{

fs/pnode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ static inline bool peers(const struct mount *m1, const struct mount *m2)
4242
}
4343

4444
void change_mnt_propagation(struct mount *, int);
45+
void bulk_make_private(struct list_head *);
4546
int propagate_mnt(struct mount *, struct mountpoint *, struct mount *,
4647
struct hlist_head *);
4748
void propagate_umount(struct list_head *);

0 commit comments

Comments
 (0)