Skip to content

Commit 2cc0b7f

Browse files
committed
Merge patch series "mount notification"
Miklos Szeredi <mszeredi@redhat.com> says: This should be ready for adding to the v6.15 queue. I don't see the SELinux discussion converging, so I took the simpler version out of the two that were suggested. * patches from https://lore.kernel.org/r/20250129165803.72138-1-mszeredi@redhat.com: vfs: add notifications for mount attach and detach fanotify: notify on mount attach and detach fsnotify: add mount notification infrastructure Link: https://lore.kernel.org/r/20250129165803.72138-1-mszeredi@redhat.com Signed-off-by: Christian Brauner <brauner@kernel.org>
2 parents 2014c95 + bf630c4 commit 2cc0b7f

14 files changed

Lines changed: 393 additions & 36 deletions

File tree

fs/mount.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <linux/ns_common.h>
66
#include <linux/fs_pin.h>
77

8+
extern struct list_head notify_list;
9+
810
struct mnt_namespace {
911
struct ns_common ns;
1012
struct mount * root;
@@ -21,6 +23,10 @@ struct mnt_namespace {
2123
struct rcu_head mnt_ns_rcu;
2224
};
2325
u64 event;
26+
#ifdef CONFIG_FSNOTIFY
27+
__u32 n_fsnotify_mask;
28+
struct fsnotify_mark_connector __rcu *n_fsnotify_marks;
29+
#endif
2430
unsigned int nr_mounts; /* # of mounts in the namespace */
2531
unsigned int pending_mounts;
2632
struct rb_node mnt_ns_tree_node; /* node in the mnt_ns_tree */
@@ -76,6 +82,8 @@ struct mount {
7682
#ifdef CONFIG_FSNOTIFY
7783
struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;
7884
__u32 mnt_fsnotify_mask;
85+
struct list_head to_notify; /* need to queue notification */
86+
struct mnt_namespace *prev_ns; /* previous namespace (NULL if none) */
7987
#endif
8088
int mnt_id; /* mount identifier, reused */
8189
u64 mnt_id_unique; /* mount ID unique until reboot */
@@ -177,3 +185,21 @@ static inline struct mnt_namespace *to_mnt_ns(struct ns_common *ns)
177185
{
178186
return container_of(ns, struct mnt_namespace, ns);
179187
}
188+
189+
#ifdef CONFIG_FSNOTIFY
190+
static inline void mnt_notify_add(struct mount *m)
191+
{
192+
/* Optimize the case where there are no watches */
193+
if ((m->mnt_ns && m->mnt_ns->n_fsnotify_marks) ||
194+
(m->prev_ns && m->prev_ns->n_fsnotify_marks))
195+
list_add_tail(&m->to_notify, &notify_list);
196+
else
197+
m->prev_ns = m->mnt_ns;
198+
}
199+
#else
200+
static inline void mnt_notify_add(struct mount *m)
201+
{
202+
}
203+
#endif
204+
205+
struct mnt_namespace *mnt_ns_from_dentry(struct dentry *dentry);

fs/namespace.c

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ static HLIST_HEAD(unmounted); /* protected by namespace_sem */
8181
static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */
8282
static DEFINE_SEQLOCK(mnt_ns_tree_lock);
8383

84+
#ifdef CONFIG_FSNOTIFY
85+
LIST_HEAD(notify_list); /* protected by namespace_sem */
86+
#endif
8487
static struct rb_root mnt_ns_tree = RB_ROOT; /* protected by mnt_ns_tree_lock */
8588
static LIST_HEAD(mnt_ns_list); /* protected by mnt_ns_tree_lock */
8689

@@ -163,6 +166,7 @@ static void mnt_ns_release(struct mnt_namespace *ns)
163166
{
164167
/* keep alive for {list,stat}mount() */
165168
if (refcount_dec_and_test(&ns->passive)) {
169+
fsnotify_mntns_delete(ns);
166170
put_user_ns(ns->user_ns);
167171
kfree(ns);
168172
}
@@ -1176,6 +1180,8 @@ static void mnt_add_to_ns(struct mnt_namespace *ns, struct mount *mnt)
11761180
ns->mnt_first_node = &mnt->mnt_node;
11771181
rb_link_node(&mnt->mnt_node, parent, link);
11781182
rb_insert_color(&mnt->mnt_node, &ns->mounts);
1183+
1184+
mnt_notify_add(mnt);
11791185
}
11801186

11811187
/*
@@ -1723,6 +1729,50 @@ int may_umount(struct vfsmount *mnt)
17231729

17241730
EXPORT_SYMBOL(may_umount);
17251731

1732+
#ifdef CONFIG_FSNOTIFY
1733+
static void mnt_notify(struct mount *p)
1734+
{
1735+
if (!p->prev_ns && p->mnt_ns) {
1736+
fsnotify_mnt_attach(p->mnt_ns, &p->mnt);
1737+
} else if (p->prev_ns && !p->mnt_ns) {
1738+
fsnotify_mnt_detach(p->prev_ns, &p->mnt);
1739+
} else if (p->prev_ns == p->mnt_ns) {
1740+
fsnotify_mnt_move(p->mnt_ns, &p->mnt);
1741+
} else {
1742+
fsnotify_mnt_detach(p->prev_ns, &p->mnt);
1743+
fsnotify_mnt_attach(p->mnt_ns, &p->mnt);
1744+
}
1745+
p->prev_ns = p->mnt_ns;
1746+
}
1747+
1748+
static void notify_mnt_list(void)
1749+
{
1750+
struct mount *m, *tmp;
1751+
/*
1752+
* Notify about mounts that were added/reparented/detached/remain
1753+
* connected after unmount.
1754+
*/
1755+
list_for_each_entry_safe(m, tmp, &notify_list, to_notify) {
1756+
mnt_notify(m);
1757+
list_del_init(&m->to_notify);
1758+
}
1759+
}
1760+
1761+
static bool need_notify_mnt_list(void)
1762+
{
1763+
return !list_empty(&notify_list);
1764+
}
1765+
#else
1766+
static void notify_mnt_list(void)
1767+
{
1768+
}
1769+
1770+
static bool need_notify_mnt_list(void)
1771+
{
1772+
return false;
1773+
}
1774+
#endif
1775+
17261776
static void namespace_unlock(void)
17271777
{
17281778
struct hlist_head head;
@@ -1733,7 +1783,18 @@ static void namespace_unlock(void)
17331783
hlist_move_list(&unmounted, &head);
17341784
list_splice_init(&ex_mountpoints, &list);
17351785

1736-
up_write(&namespace_sem);
1786+
if (need_notify_mnt_list()) {
1787+
/*
1788+
* No point blocking out concurrent readers while notifications
1789+
* are sent. This will also allow statmount()/listmount() to run
1790+
* concurrently.
1791+
*/
1792+
downgrade_write(&namespace_sem);
1793+
notify_mnt_list();
1794+
up_read(&namespace_sem);
1795+
} else {
1796+
up_write(&namespace_sem);
1797+
}
17371798

17381799
shrink_dentry_list(&list);
17391800

@@ -1846,6 +1907,19 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
18461907
change_mnt_propagation(p, MS_PRIVATE);
18471908
if (disconnect)
18481909
hlist_add_head(&p->mnt_umount, &unmounted);
1910+
1911+
/*
1912+
* At this point p->mnt_ns is NULL, notification will be queued
1913+
* only if
1914+
*
1915+
* - p->prev_ns is non-NULL *and*
1916+
* - p->prev_ns->n_fsnotify_marks is non-NULL
1917+
*
1918+
* This will preclude queuing the mount if this is a cleanup
1919+
* after a failed copy_tree() or destruction of an anonymous
1920+
* namespace, etc.
1921+
*/
1922+
mnt_notify_add(p);
18491923
}
18501924
}
18511925

@@ -2145,16 +2219,24 @@ struct mnt_namespace *get_sequential_mnt_ns(struct mnt_namespace *mntns, bool pr
21452219
}
21462220
}
21472221

2222+
struct mnt_namespace *mnt_ns_from_dentry(struct dentry *dentry)
2223+
{
2224+
if (!is_mnt_ns_file(dentry))
2225+
return NULL;
2226+
2227+
return to_mnt_ns(get_proc_ns(dentry->d_inode));
2228+
}
2229+
21482230
static bool mnt_ns_loop(struct dentry *dentry)
21492231
{
21502232
/* Could bind mounting the mount namespace inode cause a
21512233
* mount namespace loop?
21522234
*/
2153-
struct mnt_namespace *mnt_ns;
2154-
if (!is_mnt_ns_file(dentry))
2235+
struct mnt_namespace *mnt_ns = mnt_ns_from_dentry(dentry);
2236+
2237+
if (!mnt_ns)
21552238
return false;
21562239

2157-
mnt_ns = to_mnt_ns(get_proc_ns(dentry->d_inode));
21582240
return current->nsproxy->mnt_ns->seq >= mnt_ns->seq;
21592241
}
21602242

@@ -2547,6 +2629,7 @@ static int attach_recursive_mnt(struct mount *source_mnt,
25472629
dest_mp = smp;
25482630
unhash_mnt(source_mnt);
25492631
attach_mnt(source_mnt, top_mnt, dest_mp, beneath);
2632+
mnt_notify_add(source_mnt);
25502633
touch_mnt_namespace(source_mnt->mnt_ns);
25512634
} else {
25522635
if (source_mnt->mnt_ns) {
@@ -4468,6 +4551,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
44684551
list_del_init(&new_mnt->mnt_expire);
44694552
put_mountpoint(root_mp);
44704553
unlock_mount_hash();
4554+
mnt_notify_add(root_mnt);
4555+
mnt_notify_add(new_mnt);
44714556
chroot_fs_refs(&root, &new);
44724557
error = 0;
44734558
out4:

fs/notify/fanotify/fanotify.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ static bool fanotify_should_merge(struct fanotify_event *old,
166166
case FANOTIFY_EVENT_TYPE_FS_ERROR:
167167
return fanotify_error_event_equal(FANOTIFY_EE(old),
168168
FANOTIFY_EE(new));
169+
case FANOTIFY_EVENT_TYPE_MNT:
170+
return false;
169171
default:
170172
WARN_ON_ONCE(1);
171173
}
@@ -312,7 +314,10 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
312314
pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n",
313315
__func__, iter_info->report_mask, event_mask, data, data_type);
314316

315-
if (!fid_mode) {
317+
if (FAN_GROUP_FLAG(group, FAN_REPORT_MNT)) {
318+
if (data_type != FSNOTIFY_EVENT_MNT)
319+
return 0;
320+
} else if (!fid_mode) {
316321
/* Do we have path to open a file descriptor? */
317322
if (!path)
318323
return 0;
@@ -557,6 +562,20 @@ static struct fanotify_event *fanotify_alloc_path_event(const struct path *path,
557562
return &pevent->fae;
558563
}
559564

565+
static struct fanotify_event *fanotify_alloc_mnt_event(u64 mnt_id, gfp_t gfp)
566+
{
567+
struct fanotify_mnt_event *pevent;
568+
569+
pevent = kmem_cache_alloc(fanotify_mnt_event_cachep, gfp);
570+
if (!pevent)
571+
return NULL;
572+
573+
pevent->fae.type = FANOTIFY_EVENT_TYPE_MNT;
574+
pevent->mnt_id = mnt_id;
575+
576+
return &pevent->fae;
577+
}
578+
560579
static struct fanotify_event *fanotify_alloc_perm_event(const void *data,
561580
int data_type,
562581
gfp_t gfp)
@@ -731,6 +750,7 @@ static struct fanotify_event *fanotify_alloc_event(
731750
fid_mode);
732751
struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir);
733752
const struct path *path = fsnotify_data_path(data, data_type);
753+
u64 mnt_id = fsnotify_data_mnt_id(data, data_type);
734754
struct mem_cgroup *old_memcg;
735755
struct dentry *moved = NULL;
736756
struct inode *child = NULL;
@@ -826,8 +846,12 @@ static struct fanotify_event *fanotify_alloc_event(
826846
moved, &hash, gfp);
827847
} else if (fid_mode) {
828848
event = fanotify_alloc_fid_event(id, fsid, &hash, gfp);
829-
} else {
849+
} else if (path) {
830850
event = fanotify_alloc_path_event(path, &hash, gfp);
851+
} else if (mnt_id) {
852+
event = fanotify_alloc_mnt_event(mnt_id, gfp);
853+
} else {
854+
WARN_ON_ONCE(1);
831855
}
832856

833857
if (!event)
@@ -927,7 +951,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
927951
BUILD_BUG_ON(FAN_RENAME != FS_RENAME);
928952
BUILD_BUG_ON(FAN_PRE_ACCESS != FS_PRE_ACCESS);
929953

930-
BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 22);
954+
BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 24);
931955

932956
mask = fanotify_group_event_mask(group, iter_info, &match_mask,
933957
mask, data, data_type, dir);
@@ -1028,6 +1052,11 @@ static void fanotify_free_error_event(struct fsnotify_group *group,
10281052
mempool_free(fee, &group->fanotify_data.error_events_pool);
10291053
}
10301054

1055+
static void fanotify_free_mnt_event(struct fanotify_event *event)
1056+
{
1057+
kmem_cache_free(fanotify_mnt_event_cachep, FANOTIFY_ME(event));
1058+
}
1059+
10311060
static void fanotify_free_event(struct fsnotify_group *group,
10321061
struct fsnotify_event *fsn_event)
10331062
{
@@ -1054,6 +1083,9 @@ static void fanotify_free_event(struct fsnotify_group *group,
10541083
case FANOTIFY_EVENT_TYPE_FS_ERROR:
10551084
fanotify_free_error_event(group, event);
10561085
break;
1086+
case FANOTIFY_EVENT_TYPE_MNT:
1087+
fanotify_free_mnt_event(event);
1088+
break;
10571089
default:
10581090
WARN_ON_ONCE(1);
10591091
}

fs/notify/fanotify/fanotify.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ extern struct kmem_cache *fanotify_mark_cache;
99
extern struct kmem_cache *fanotify_fid_event_cachep;
1010
extern struct kmem_cache *fanotify_path_event_cachep;
1111
extern struct kmem_cache *fanotify_perm_event_cachep;
12+
extern struct kmem_cache *fanotify_mnt_event_cachep;
1213

1314
/* Possible states of the permission event */
1415
enum {
@@ -244,6 +245,7 @@ enum fanotify_event_type {
244245
FANOTIFY_EVENT_TYPE_PATH_PERM,
245246
FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */
246247
FANOTIFY_EVENT_TYPE_FS_ERROR, /* struct fanotify_error_event */
248+
FANOTIFY_EVENT_TYPE_MNT,
247249
__FANOTIFY_EVENT_TYPE_NUM
248250
};
249251

@@ -409,12 +411,23 @@ struct fanotify_path_event {
409411
struct path path;
410412
};
411413

414+
struct fanotify_mnt_event {
415+
struct fanotify_event fae;
416+
u64 mnt_id;
417+
};
418+
412419
static inline struct fanotify_path_event *
413420
FANOTIFY_PE(struct fanotify_event *event)
414421
{
415422
return container_of(event, struct fanotify_path_event, fae);
416423
}
417424

425+
static inline struct fanotify_mnt_event *
426+
FANOTIFY_ME(struct fanotify_event *event)
427+
{
428+
return container_of(event, struct fanotify_mnt_event, fae);
429+
}
430+
418431
/*
419432
* Structure for permission fanotify events. It gets allocated and freed in
420433
* fanotify_handle_event() since we wait there for user response. When the
@@ -466,6 +479,11 @@ static inline bool fanotify_is_error_event(u32 mask)
466479
return mask & FAN_FS_ERROR;
467480
}
468481

482+
static inline bool fanotify_is_mnt_event(u32 mask)
483+
{
484+
return mask & (FAN_MNT_ATTACH | FAN_MNT_DETACH);
485+
}
486+
469487
static inline const struct path *fanotify_event_path(struct fanotify_event *event)
470488
{
471489
if (event->type == FANOTIFY_EVENT_TYPE_PATH)

0 commit comments

Comments
 (0)