Skip to content

Commit 406fea7

Browse files
author
Al Viro
committed
mount: separate the flags accessed only under namespace_sem
Several flags are updated and checked only under namespace_sem; we are already making use of that when we are checking them without mount_lock, but we have to hold mount_lock for all updates, which makes things clumsier than they have to be. Take MNT_SHARED, MNT_UNBINDABLE, MNT_MARKED and MNT_UMOUNT_CANDIDATE into a separate field (->mnt_t_flags), renaming them to T_SHARED, etc. to avoid confusion. All accesses must be under namespace_sem. That changes locking requirements for mnt_change_propagation() and set_mnt_shared() - only namespace_sem is needed now. The same goes for SET_MNT_MARKED et.al. There might be more flags moved from ->mnt_flags to that field; this is just the initial set. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent 493a4be commit 406fea7

File tree

6 files changed

+46
-46
lines changed

6 files changed

+46
-46
lines changed

Documentation/filesystems/propagate_umount.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -453,25 +453,25 @@ original set.
453453
So let's go for
454454
* original set ("set"). Linkage via mnt_list
455455
* undecided candidates ("candidates"). Subset of a list,
456-
consisting of all its elements marked with a new flag (MNT_UMOUNT_CANDIDATE).
456+
consisting of all its elements marked with a new flag (T_UMOUNT_CANDIDATE).
457457
Initially all elements of the list will be marked that way; in the
458458
end the list will become empty and no mounts will remain marked with
459459
that flag.
460-
* Reuse MNT_MARKED for "has been already seen by trim_ancestors()".
460+
* Reuse T_MARKED for "has been already seen by trim_ancestors()".
461461
* anything in U that hadn't been in the original set - elements of
462462
candidates will gradually be either discarded or moved there. In other
463463
words, it's the candidates we have already decided to unmount. Its role
464464
is reasonably close to the old "to_umount", so let's use that name.
465465
Linkage via mnt_list.
466466

467467
For gather_candidates() we'll need to maintain both candidates (S -
468-
set) and intersection of S with set. Use MNT_UMOUNT_CANDIDATE for
468+
set) and intersection of S with set. Use T_UMOUNT_CANDIDATE for
469469
all elements we encounter, putting the ones not already in the original
470470
set into the list of candidates. When we are done, strip that flag from
471471
all elements of the original set. That gives a cheap way to check
472472
if element belongs to S (in gather_candidates) and to candidates
473473
itself (at later stages). Call that predicate is_candidate(); it would
474-
be m->mnt_flags & MNT_UMOUNT_CANDIDATE.
474+
be m->mnt_t_flags & T_UMOUNT_CANDIDATE.
475475

476476
All elements of the original set are marked with MNT_UMOUNT and we'll
477477
need the same for elements added when joining the contents of to_umount
@@ -480,5 +480,5 @@ to to_umount; that's close to what the old 'umount_one' is doing, so
480480
let's keep that name. It also gives us another predicate we need -
481481
"belongs to union of set and to_umount"; will_be_unmounted() for now.
482482

483-
Removals from the candidates list should strip both MNT_MARKED and
484-
MNT_UMOUNT_CANDIDATE; call it remove_from_candidates_list().
483+
Removals from the candidates list should strip both T_MARKED and
484+
T_UMOUNT_CANDIDATE; call it remove_from_candidates_list().

fs/mount.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ struct mount {
8484
struct list_head to_notify; /* need to queue notification */
8585
struct mnt_namespace *prev_ns; /* previous namespace (NULL if none) */
8686
#endif
87+
int mnt_t_flags; /* namespace_sem-protected flags */
8788
int mnt_id; /* mount identifier, reused */
8889
u64 mnt_id_unique; /* mount ID unique until reboot */
8990
int mnt_group_id; /* peer group identifier */
@@ -93,6 +94,22 @@ struct mount {
9394
struct mount *overmount; /* mounted on ->mnt_root */
9495
} __randomize_layout;
9596

97+
enum {
98+
T_SHARED = 1, /* mount is shared */
99+
T_UNBINDABLE = 2, /* mount is unbindable */
100+
T_MARKED = 4, /* internal mark for propagate_... */
101+
T_UMOUNT_CANDIDATE = 8, /* for propagate_umount */
102+
103+
/*
104+
* T_SHARED_MASK is the set of flags that should be cleared when a
105+
* mount becomes shared. Currently, this is only the flag that says a
106+
* mount cannot be bind mounted, since this is how we create a mount
107+
* that shares events with another mount. If you add a new T_*
108+
* flag, consider how it interacts with shared mounts.
109+
*/
110+
T_SHARED_MASK = T_UNBINDABLE,
111+
};
112+
96113
#define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */
97114

98115
static inline struct mount *real_mount(struct vfsmount *mnt)

fs/namespace.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2917,10 +2917,8 @@ static int do_change_type(struct path *path, int ms_flags)
29172917
goto out_unlock;
29182918
}
29192919

2920-
lock_mount_hash();
29212920
for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL))
29222921
change_mnt_propagation(m, type);
2923-
unlock_mount_hash();
29242922

29252923
out_unlock:
29262924
namespace_unlock();
@@ -3409,9 +3407,7 @@ static int do_set_group(struct path *from_path, struct path *to_path)
34093407
if (IS_MNT_SHARED(from)) {
34103408
to->mnt_group_id = from->mnt_group_id;
34113409
list_add(&to->mnt_share, &from->mnt_share);
3412-
lock_mount_hash();
34133410
set_mnt_shared(to);
3414-
unlock_mount_hash();
34153411
}
34163412

34173413
err = 0;

fs/pnode.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ static int do_make_slave(struct mount *mnt)
112112
}
113113

114114
/*
115-
* vfsmount lock must be held for write
115+
* EXCL[namespace_sem]
116116
*/
117117
void change_mnt_propagation(struct mount *mnt, int type)
118118
{
@@ -125,9 +125,9 @@ void change_mnt_propagation(struct mount *mnt, int type)
125125
list_del_init(&mnt->mnt_slave);
126126
mnt->mnt_master = NULL;
127127
if (type == MS_UNBINDABLE)
128-
mnt->mnt.mnt_flags |= MNT_UNBINDABLE;
128+
mnt->mnt_t_flags |= T_UNBINDABLE;
129129
else
130-
mnt->mnt.mnt_flags &= ~MNT_UNBINDABLE;
130+
mnt->mnt_t_flags &= ~T_UNBINDABLE;
131131
}
132132
}
133133

@@ -263,9 +263,9 @@ static int propagate_one(struct mount *m, struct mountpoint *dest_mp)
263263
return PTR_ERR(child);
264264
read_seqlock_excl(&mount_lock);
265265
mnt_set_mountpoint(m, dest_mp, child);
266+
read_sequnlock_excl(&mount_lock);
266267
if (m->mnt_master != dest_master)
267268
SET_MNT_MARK(m->mnt_master);
268-
read_sequnlock_excl(&mount_lock);
269269
last_dest = m;
270270
last_source = child;
271271
hlist_add_head(&child->mnt_hash, list);
@@ -322,13 +322,11 @@ int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
322322
} while (n != m);
323323
}
324324
out:
325-
read_seqlock_excl(&mount_lock);
326325
hlist_for_each_entry(n, tree_list, mnt_hash) {
327326
m = n->mnt_parent;
328327
if (m->mnt_master != dest_mnt->mnt_master)
329328
CLEAR_MNT_MARK(m->mnt_master);
330329
}
331-
read_sequnlock_excl(&mount_lock);
332330
return ret;
333331
}
334332

@@ -447,7 +445,7 @@ void propagate_mount_unlock(struct mount *mnt)
447445

448446
static inline bool is_candidate(struct mount *m)
449447
{
450-
return m->mnt.mnt_flags & MNT_UMOUNT_CANDIDATE;
448+
return m->mnt_t_flags & T_UMOUNT_CANDIDATE;
451449
}
452450

453451
static inline bool will_be_unmounted(struct mount *m)
@@ -464,7 +462,7 @@ static void umount_one(struct mount *m, struct list_head *to_umount)
464462

465463
static void remove_from_candidate_list(struct mount *m)
466464
{
467-
m->mnt.mnt_flags &= ~(MNT_MARKED | MNT_UMOUNT_CANDIDATE);
465+
m->mnt_t_flags &= ~(T_MARKED | T_UMOUNT_CANDIDATE);
468466
list_del_init(&m->mnt_list);
469467
}
470468

@@ -476,7 +474,7 @@ static void gather_candidates(struct list_head *set,
476474
list_for_each_entry(m, set, mnt_list) {
477475
if (is_candidate(m))
478476
continue;
479-
m->mnt.mnt_flags |= MNT_UMOUNT_CANDIDATE;
477+
m->mnt_t_flags |= T_UMOUNT_CANDIDATE;
480478
p = m->mnt_parent;
481479
q = propagation_next(p, p);
482480
while (q) {
@@ -494,15 +492,15 @@ static void gather_candidates(struct list_head *set,
494492
q = skip_propagation_subtree(q, p);
495493
continue;
496494
}
497-
child->mnt.mnt_flags |= MNT_UMOUNT_CANDIDATE;
495+
child->mnt_t_flags |= T_UMOUNT_CANDIDATE;
498496
if (!will_be_unmounted(child))
499497
list_add(&child->mnt_list, candidates);
500498
}
501499
q = propagation_next(q, p);
502500
}
503501
}
504502
list_for_each_entry(m, set, mnt_list)
505-
m->mnt.mnt_flags &= ~MNT_UMOUNT_CANDIDATE;
503+
m->mnt_t_flags &= ~T_UMOUNT_CANDIDATE;
506504
}
507505

508506
/*
@@ -519,7 +517,7 @@ static void trim_ancestors(struct mount *m)
519517
return;
520518
SET_MNT_MARK(m);
521519
if (m != p->overmount)
522-
p->mnt.mnt_flags &= ~MNT_UMOUNT_CANDIDATE;
520+
p->mnt_t_flags &= ~T_UMOUNT_CANDIDATE;
523521
}
524522
}
525523

fs/pnode.h

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
#include <linux/list.h>
1111
#include "mount.h"
1212

13-
#define IS_MNT_SHARED(m) ((m)->mnt.mnt_flags & MNT_SHARED)
13+
#define IS_MNT_SHARED(m) ((m)->mnt_t_flags & T_SHARED)
1414
#define IS_MNT_SLAVE(m) ((m)->mnt_master)
1515
#define IS_MNT_NEW(m) (!(m)->mnt_ns)
16-
#define CLEAR_MNT_SHARED(m) ((m)->mnt.mnt_flags &= ~MNT_SHARED)
17-
#define IS_MNT_UNBINDABLE(m) ((m)->mnt.mnt_flags & MNT_UNBINDABLE)
18-
#define IS_MNT_MARKED(m) ((m)->mnt.mnt_flags & MNT_MARKED)
19-
#define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED)
20-
#define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED)
16+
#define CLEAR_MNT_SHARED(m) ((m)->mnt_t_flags &= ~T_SHARED)
17+
#define IS_MNT_UNBINDABLE(m) ((m)->mnt_t_flags & T_UNBINDABLE)
18+
#define IS_MNT_MARKED(m) ((m)->mnt_t_flags & T_MARKED)
19+
#define SET_MNT_MARK(m) ((m)->mnt_t_flags |= T_MARKED)
20+
#define CLEAR_MNT_MARK(m) ((m)->mnt_t_flags &= ~T_MARKED)
2121
#define IS_MNT_LOCKED(m) ((m)->mnt.mnt_flags & MNT_LOCKED)
2222

2323
#define CL_EXPIRE 0x01
@@ -28,10 +28,13 @@
2828
#define CL_SHARED_TO_SLAVE 0x20
2929
#define CL_COPY_MNT_NS_FILE 0x40
3030

31+
/*
32+
* EXCL[namespace_sem]
33+
*/
3134
static inline void set_mnt_shared(struct mount *mnt)
3235
{
33-
mnt->mnt.mnt_flags &= ~MNT_SHARED_MASK;
34-
mnt->mnt.mnt_flags |= MNT_SHARED;
36+
mnt->mnt_t_flags &= ~T_SHARED_MASK;
37+
mnt->mnt_t_flags |= T_SHARED;
3538
}
3639

3740
static inline bool peers(const struct mount *m1, const struct mount *m2)

include/linux/mount.h

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,8 @@ enum mount_flags {
3535
MNT_SHRINKABLE = 0x100,
3636
MNT_WRITE_HOLD = 0x200,
3737

38-
MNT_SHARED = 0x1000, /* if the vfsmount is a shared mount */
39-
MNT_UNBINDABLE = 0x2000, /* if the vfsmount is a unbindable mount */
40-
4138
MNT_INTERNAL = 0x4000,
4239

43-
MNT_UMOUNT_CANDIDATE = 0x020000,
4440
MNT_LOCK_ATIME = 0x040000,
4541
MNT_LOCK_NOEXEC = 0x080000,
4642
MNT_LOCK_NOSUID = 0x100000,
@@ -49,25 +45,15 @@ enum mount_flags {
4945
MNT_LOCKED = 0x800000,
5046
MNT_DOOMED = 0x1000000,
5147
MNT_SYNC_UMOUNT = 0x2000000,
52-
MNT_MARKED = 0x4000000,
5348
MNT_UMOUNT = 0x8000000,
5449

55-
/*
56-
* MNT_SHARED_MASK is the set of flags that should be cleared when a
57-
* mount becomes shared. Currently, this is only the flag that says a
58-
* mount cannot be bind mounted, since this is how we create a mount
59-
* that shares events with another mount. If you add a new MNT_*
60-
* flag, consider how it interacts with shared mounts.
61-
*/
62-
MNT_SHARED_MASK = MNT_UNBINDABLE,
6350
MNT_USER_SETTABLE_MASK = MNT_NOSUID | MNT_NODEV | MNT_NOEXEC
6451
| MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME
6552
| MNT_READONLY | MNT_NOSYMFOLLOW,
6653
MNT_ATIME_MASK = MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME,
6754

68-
MNT_INTERNAL_FLAGS = MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL |
69-
MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED |
70-
MNT_LOCKED | MNT_UMOUNT_CANDIDATE,
55+
MNT_INTERNAL_FLAGS = MNT_WRITE_HOLD | MNT_INTERNAL | MNT_DOOMED |
56+
MNT_SYNC_UMOUNT | MNT_LOCKED
7157
};
7258

7359
struct vfsmount {

0 commit comments

Comments
 (0)