Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fsnotify: add mount notification infrastructure

This is just the plumbing between the event source (fs/namespace.c) and the
event consumer (fanotify). In itself it does nothing.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Link: https://lore.kernel.org/r/20250129165803.72138-2-mszeredi@redhat.com
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

Miklos Szeredi and committed by
Christian Brauner
b944249b 2014c95a

+128 -10
+4
fs/mount.h
··· 21 21 struct rcu_head mnt_ns_rcu; 22 22 }; 23 23 u64 event; 24 + #ifdef CONFIG_FSNOTIFY 25 + __u32 n_fsnotify_mask; 26 + struct fsnotify_mark_connector __rcu *n_fsnotify_marks; 27 + #endif 24 28 unsigned int nr_mounts; /* # of mounts in the namespace */ 25 29 unsigned int pending_mounts; 26 30 struct rb_node mnt_ns_tree_node; /* node in the mnt_ns_tree */
+40 -7
fs/notify/fsnotify.c
··· 28 28 fsnotify_clear_marks_by_mount(mnt); 29 29 } 30 30 31 + void __fsnotify_mntns_delete(struct mnt_namespace *mntns) 32 + { 33 + fsnotify_clear_marks_by_mntns(mntns); 34 + } 35 + 31 36 /** 32 37 * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes. 33 38 * @sb: superblock being unmounted. ··· 425 420 file_name, cookie, iter_info); 426 421 } 427 422 428 - static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector **connp) 423 + static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector *const *connp) 429 424 { 430 425 struct fsnotify_mark_connector *conn; 431 426 struct hlist_node *node = NULL; ··· 543 538 { 544 539 const struct path *path = fsnotify_data_path(data, data_type); 545 540 struct super_block *sb = fsnotify_data_sb(data, data_type); 546 - struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb); 541 + const struct fsnotify_mnt *mnt_data = fsnotify_data_mnt(data, data_type); 542 + struct fsnotify_sb_info *sbinfo = sb ? fsnotify_sb_info(sb) : NULL; 547 543 struct fsnotify_iter_info iter_info = {}; 548 544 struct mount *mnt = NULL; 549 545 struct inode *inode2 = NULL; 550 546 struct dentry *moved; 551 547 int inode2_type; 552 548 int ret = 0; 553 - __u32 test_mask, marks_mask; 549 + __u32 test_mask, marks_mask = 0; 554 550 555 551 if (path) 556 552 mnt = real_mount(path->mnt); ··· 584 578 if ((!sbinfo || !sbinfo->sb_marks) && 585 579 (!mnt || !mnt->mnt_fsnotify_marks) && 586 580 (!inode || !inode->i_fsnotify_marks) && 587 - (!inode2 || !inode2->i_fsnotify_marks)) 581 + (!inode2 || !inode2->i_fsnotify_marks) && 582 + (!mnt_data || !mnt_data->ns->n_fsnotify_marks)) 588 583 return 0; 589 584 590 - marks_mask = READ_ONCE(sb->s_fsnotify_mask); 585 + if (sb) 586 + marks_mask |= READ_ONCE(sb->s_fsnotify_mask); 591 587 if (mnt) 592 588 marks_mask |= READ_ONCE(mnt->mnt_fsnotify_mask); 593 589 if (inode) 594 590 marks_mask |= READ_ONCE(inode->i_fsnotify_mask); 595 591 if (inode2) 596 592 marks_mask |= READ_ONCE(inode2->i_fsnotify_mask); 597 - 593 + if (mnt_data) 594 + marks_mask |= READ_ONCE(mnt_data->ns->n_fsnotify_mask); 598 595 599 596 /* 600 597 * If this is a modify event we may need to clear some ignore masks. ··· 626 617 if (inode2) { 627 618 iter_info.marks[inode2_type] = 628 619 fsnotify_first_mark(&inode2->i_fsnotify_marks); 620 + } 621 + if (mnt_data) { 622 + iter_info.marks[FSNOTIFY_ITER_TYPE_MNTNS] = 623 + fsnotify_first_mark(&mnt_data->ns->n_fsnotify_marks); 629 624 } 630 625 631 626 /* ··· 715 702 } 716 703 #endif 717 704 705 + void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt) 706 + { 707 + struct fsnotify_mnt data = { 708 + .ns = ns, 709 + .mnt_id = real_mount(mnt)->mnt_id_unique, 710 + }; 711 + 712 + if (WARN_ON_ONCE(!ns)) 713 + return; 714 + 715 + /* 716 + * This is an optimization as well as making sure fsnotify_init() has 717 + * been called. 718 + */ 719 + if (!ns->n_fsnotify_marks) 720 + return; 721 + 722 + fsnotify(mask, &data, FSNOTIFY_EVENT_MNT, NULL, NULL, NULL, 0); 723 + } 724 + 718 725 static __init int fsnotify_init(void) 719 726 { 720 727 int ret; 721 728 722 - BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 24); 729 + BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 26); 723 730 724 731 ret = init_srcu_struct(&fsnotify_mark_srcu); 725 732 if (ret)
+11
fs/notify/fsnotify.h
··· 33 33 return conn->obj; 34 34 } 35 35 36 + static inline struct mnt_namespace *fsnotify_conn_mntns( 37 + struct fsnotify_mark_connector *conn) 38 + { 39 + return conn->obj; 40 + } 41 + 36 42 static inline struct super_block *fsnotify_object_sb(void *obj, 37 43 enum fsnotify_obj_type obj_type) 38 44 { ··· 93 87 static inline void fsnotify_clear_marks_by_sb(struct super_block *sb) 94 88 { 95 89 fsnotify_destroy_marks(fsnotify_sb_marks(sb)); 90 + } 91 + 92 + static inline void fsnotify_clear_marks_by_mntns(struct mnt_namespace *mntns) 93 + { 94 + fsnotify_destroy_marks(&mntns->n_fsnotify_marks); 96 95 } 97 96 98 97 /*
+11 -3
fs/notify/mark.c
··· 107 107 return &real_mount(obj)->mnt_fsnotify_marks; 108 108 case FSNOTIFY_OBJ_TYPE_SB: 109 109 return fsnotify_sb_marks(obj); 110 + case FSNOTIFY_OBJ_TYPE_MNTNS: 111 + return &((struct mnt_namespace *)obj)->n_fsnotify_marks; 110 112 default: 111 113 return NULL; 112 114 } ··· 122 120 return &fsnotify_conn_mount(conn)->mnt_fsnotify_mask; 123 121 else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) 124 122 return &fsnotify_conn_sb(conn)->s_fsnotify_mask; 123 + else if (conn->type == FSNOTIFY_OBJ_TYPE_MNTNS) 124 + return &fsnotify_conn_mntns(conn)->n_fsnotify_mask; 125 125 return NULL; 126 126 } 127 127 ··· 350 346 fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0; 351 347 } else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) { 352 348 fsnotify_conn_sb(conn)->s_fsnotify_mask = 0; 349 + } else if (conn->type == FSNOTIFY_OBJ_TYPE_MNTNS) { 350 + fsnotify_conn_mntns(conn)->n_fsnotify_mask = 0; 353 351 } 354 352 355 353 rcu_assign_pointer(*connp, NULL); 356 354 conn->obj = NULL; 357 355 conn->type = FSNOTIFY_OBJ_TYPE_DETACHED; 358 - fsnotify_update_sb_watchers(sb, conn); 356 + if (sb) 357 + fsnotify_update_sb_watchers(sb, conn); 359 358 360 359 return inode; 361 360 } ··· 731 724 * Attach the sb info before attaching a connector to any object on sb. 732 725 * The sb info will remain attached as long as sb lives. 733 726 */ 734 - if (!fsnotify_sb_info(sb)) { 727 + if (sb && !fsnotify_sb_info(sb)) { 735 728 err = fsnotify_attach_info_to_sb(sb); 736 729 if (err) 737 730 return err; ··· 777 770 /* mark should be the last entry. last is the current last entry */ 778 771 hlist_add_behind_rcu(&mark->obj_list, &last->obj_list); 779 772 added: 780 - fsnotify_update_sb_watchers(sb, conn); 773 + if (sb) 774 + fsnotify_update_sb_watchers(sb, conn); 781 775 /* 782 776 * Since connector is attached to object using cmpxchg() we are 783 777 * guaranteed that connector initialization is fully visible by anyone
+20
include/linux/fsnotify.h
··· 299 299 __fsnotify_vfsmount_delete(mnt); 300 300 } 301 301 302 + static inline void fsnotify_mntns_delete(struct mnt_namespace *mntns) 303 + { 304 + __fsnotify_mntns_delete(mntns); 305 + } 306 + 302 307 /* 303 308 * fsnotify_inoderemove - an inode is going away 304 309 */ ··· 510 505 511 506 return fsnotify(FS_ERROR, &report, FSNOTIFY_EVENT_ERROR, 512 507 NULL, NULL, NULL, 0); 508 + } 509 + 510 + static inline void fsnotify_mnt_attach(struct mnt_namespace *ns, struct vfsmount *mnt) 511 + { 512 + fsnotify_mnt(FS_MNT_ATTACH, ns, mnt); 513 + } 514 + 515 + static inline void fsnotify_mnt_detach(struct mnt_namespace *ns, struct vfsmount *mnt) 516 + { 517 + fsnotify_mnt(FS_MNT_DETACH, ns, mnt); 518 + } 519 + 520 + static inline void fsnotify_mnt_move(struct mnt_namespace *ns, struct vfsmount *mnt) 521 + { 522 + fsnotify_mnt(FS_MNT_MOVE, ns, mnt); 513 523 } 514 524 515 525 #endif /* _LINUX_FS_NOTIFY_H */
+42
include/linux/fsnotify_backend.h
··· 59 59 60 60 #define FS_PRE_ACCESS 0x00100000 /* Pre-content access hook */ 61 61 62 + #define FS_MNT_ATTACH 0x01000000 /* Mount was attached */ 63 + #define FS_MNT_DETACH 0x02000000 /* Mount was detached */ 64 + #define FS_MNT_MOVE (FS_MNT_ATTACH | FS_MNT_DETACH) 65 + 62 66 /* 63 67 * Set on inode mark that cares about things that happen to its children. 64 68 * Always set for dnotify and inotify. ··· 83 79 * when a directory entry inside a child subdir changes. 84 80 */ 85 81 #define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE | FS_RENAME) 82 + 83 + /* Mount namespace events */ 84 + #define FSNOTIFY_MNT_EVENTS (FS_MNT_ATTACH | FS_MNT_DETACH) 86 85 87 86 /* Content events can be used to inspect file content */ 88 87 #define FSNOTIFY_CONTENT_PERM_EVENTS (FS_OPEN_PERM | FS_OPEN_EXEC_PERM | \ ··· 115 108 116 109 /* Events that can be reported to backends */ 117 110 #define ALL_FSNOTIFY_EVENTS (ALL_FSNOTIFY_DIRENT_EVENTS | \ 111 + FSNOTIFY_MNT_EVENTS | \ 118 112 FS_EVENTS_POSS_ON_CHILD | \ 119 113 FS_DELETE_SELF | FS_MOVE_SELF | \ 120 114 FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \ ··· 306 298 FSNOTIFY_EVENT_PATH, 307 299 FSNOTIFY_EVENT_INODE, 308 300 FSNOTIFY_EVENT_DENTRY, 301 + FSNOTIFY_EVENT_MNT, 309 302 FSNOTIFY_EVENT_ERROR, 310 303 }; 311 304 ··· 326 317 { 327 318 return range->path; 328 319 } 320 + 321 + struct fsnotify_mnt { 322 + const struct mnt_namespace *ns; 323 + u64 mnt_id; 324 + }; 329 325 330 326 static inline struct inode *fsnotify_data_inode(const void *data, int data_type) 331 327 { ··· 397 383 } 398 384 } 399 385 386 + static inline const struct fsnotify_mnt *fsnotify_data_mnt(const void *data, 387 + int data_type) 388 + { 389 + switch (data_type) { 390 + case FSNOTIFY_EVENT_MNT: 391 + return data; 392 + default: 393 + return NULL; 394 + } 395 + } 396 + 397 + static inline u64 fsnotify_data_mnt_id(const void *data, int data_type) 398 + { 399 + const struct fsnotify_mnt *mnt_data = fsnotify_data_mnt(data, data_type); 400 + 401 + return mnt_data ? mnt_data->mnt_id : 0; 402 + } 403 + 400 404 static inline struct fs_error_report *fsnotify_data_error_report( 401 405 const void *data, 402 406 int data_type) ··· 452 420 FSNOTIFY_ITER_TYPE_SB, 453 421 FSNOTIFY_ITER_TYPE_PARENT, 454 422 FSNOTIFY_ITER_TYPE_INODE2, 423 + FSNOTIFY_ITER_TYPE_MNTNS, 455 424 FSNOTIFY_ITER_TYPE_COUNT 456 425 }; 457 426 ··· 462 429 FSNOTIFY_OBJ_TYPE_INODE, 463 430 FSNOTIFY_OBJ_TYPE_VFSMOUNT, 464 431 FSNOTIFY_OBJ_TYPE_SB, 432 + FSNOTIFY_OBJ_TYPE_MNTNS, 465 433 FSNOTIFY_OBJ_TYPE_COUNT, 466 434 FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT 467 435 }; ··· 647 613 extern void __fsnotify_inode_delete(struct inode *inode); 648 614 extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); 649 615 extern void fsnotify_sb_delete(struct super_block *sb); 616 + extern void __fsnotify_mntns_delete(struct mnt_namespace *mntns); 650 617 extern void fsnotify_sb_free(struct super_block *sb); 651 618 extern u32 fsnotify_get_cookie(void); 619 + extern void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt); 652 620 653 621 static inline __u32 fsnotify_parent_needed_mask(__u32 mask) 654 622 { ··· 964 928 static inline void fsnotify_sb_delete(struct super_block *sb) 965 929 {} 966 930 931 + static inline void __fsnotify_mntns_delete(struct mnt_namespace *mntns) 932 + {} 933 + 967 934 static inline void fsnotify_sb_free(struct super_block *sb) 968 935 {} 969 936 ··· 979 940 } 980 941 981 942 static inline void fsnotify_unmount_inodes(struct super_block *sb) 943 + {} 944 + 945 + static inline void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt) 982 946 {} 983 947 984 948 #endif /* CONFIG_FSNOTIFY */