Skip to content

Commit 07a3b8d

Browse files
amir73iljankara
authored andcommitted
fsnotify: lazy attach fsnotify_sb_info state to sb
Define a container struct fsnotify_sb_info to hold per-sb state, including the reference to sb marks connector. Allocate the fsnotify_sb_info state before attaching connector to any object on the sb and free it only when killing sb. This state is going to be used for storing per priority watched objects counters. Suggested-by: Jan Kara <[email protected]> Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Jan Kara <[email protected]> Message-Id: <[email protected]>
1 parent c9d4603 commit 07a3b8d

File tree

5 files changed

+73
-9
lines changed

5 files changed

+73
-9
lines changed

fs/notify/fsnotify.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,18 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
8989

9090
void fsnotify_sb_delete(struct super_block *sb)
9191
{
92+
struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb);
93+
94+
/* Were any marks ever added to any object on this sb? */
95+
if (!sbinfo)
96+
return;
97+
9298
fsnotify_unmount_inodes(sb);
9399
fsnotify_clear_marks_by_sb(sb);
94100
/* Wait for outstanding object references from connectors */
95101
wait_var_event(fsnotify_sb_watched_objects(sb),
96102
!atomic_long_read(fsnotify_sb_watched_objects(sb)));
103+
kfree(sbinfo);
97104
}
98105

99106
/*
@@ -489,6 +496,7 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
489496
{
490497
const struct path *path = fsnotify_data_path(data, data_type);
491498
struct super_block *sb = fsnotify_data_sb(data, data_type);
499+
struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb);
492500
struct fsnotify_iter_info iter_info = {};
493501
struct mount *mnt = NULL;
494502
struct inode *inode2 = NULL;
@@ -525,7 +533,7 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
525533
* SRCU because we have no references to any objects and do not
526534
* need SRCU to keep them "alive".
527535
*/
528-
if (!sb->s_fsnotify_marks &&
536+
if ((!sbinfo || !sbinfo->sb_marks) &&
529537
(!mnt || !mnt->mnt_fsnotify_marks) &&
530538
(!inode || !inode->i_fsnotify_marks) &&
531539
(!inode2 || !inode2->i_fsnotify_marks))
@@ -552,8 +560,10 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
552560

553561
iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);
554562

555-
iter_info.marks[FSNOTIFY_ITER_TYPE_SB] =
556-
fsnotify_first_mark(&sb->s_fsnotify_marks);
563+
if (sbinfo) {
564+
iter_info.marks[FSNOTIFY_ITER_TYPE_SB] =
565+
fsnotify_first_mark(&sbinfo->sb_marks);
566+
}
557567
if (mnt) {
558568
iter_info.marks[FSNOTIFY_ITER_TYPE_VFSMOUNT] =
559569
fsnotify_first_mark(&mnt->mnt_fsnotify_marks);

fs/notify/fsnotify.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ static inline struct super_block *fsnotify_connector_sb(
5454
return fsnotify_object_sb(conn->obj, conn->type);
5555
}
5656

57+
static inline fsnotify_connp_t *fsnotify_sb_marks(struct super_block *sb)
58+
{
59+
struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb);
60+
61+
return sbinfo ? &sbinfo->sb_marks : NULL;
62+
}
63+
5764
/* destroy all events sitting in this groups notification queue */
5865
extern void fsnotify_flush_notify(struct fsnotify_group *group);
5966

@@ -79,7 +86,7 @@ static inline void fsnotify_clear_marks_by_mount(struct vfsmount *mnt)
7986
/* run the list of all marks associated with sb and destroy them */
8087
static inline void fsnotify_clear_marks_by_sb(struct super_block *sb)
8188
{
82-
fsnotify_destroy_marks(&sb->s_fsnotify_marks);
89+
fsnotify_destroy_marks(fsnotify_sb_marks(sb));
8390
}
8491

8592
/*

fs/notify/mark.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ static fsnotify_connp_t *fsnotify_object_connp(void *obj,
106106
case FSNOTIFY_OBJ_TYPE_VFSMOUNT:
107107
return &real_mount(obj)->mnt_fsnotify_marks;
108108
case FSNOTIFY_OBJ_TYPE_SB:
109-
return &((struct super_block *)obj)->s_fsnotify_marks;
109+
return fsnotify_sb_marks(obj);
110110
default:
111111
return NULL;
112112
}
@@ -569,6 +569,26 @@ int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b)
569569
return -1;
570570
}
571571

572+
static int fsnotify_attach_info_to_sb(struct super_block *sb)
573+
{
574+
struct fsnotify_sb_info *sbinfo;
575+
576+
/* sb info is freed on fsnotify_sb_delete() */
577+
sbinfo = kzalloc(sizeof(*sbinfo), GFP_KERNEL);
578+
if (!sbinfo)
579+
return -ENOMEM;
580+
581+
/*
582+
* cmpxchg() provides the barrier so that callers of fsnotify_sb_info()
583+
* will observe an initialized structure
584+
*/
585+
if (cmpxchg(&sb->s_fsnotify_info, NULL, sbinfo)) {
586+
/* Someone else created sbinfo for us */
587+
kfree(sbinfo);
588+
}
589+
return 0;
590+
}
591+
572592
static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
573593
void *obj, unsigned int obj_type)
574594
{
@@ -640,6 +660,16 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, void *obj,
640660
if (WARN_ON(!fsnotify_valid_obj_type(obj_type)))
641661
return -EINVAL;
642662

663+
/*
664+
* Attach the sb info before attaching a connector to any object on sb.
665+
* The sb info will remain attached as long as sb lives.
666+
*/
667+
if (!fsnotify_sb_info(sb)) {
668+
err = fsnotify_attach_info_to_sb(sb);
669+
if (err)
670+
return err;
671+
}
672+
643673
connp = fsnotify_object_connp(obj, obj_type);
644674
restart:
645675
spin_lock(&mark->lock);

include/linux/fs.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ struct fscrypt_inode_info;
7373
struct fscrypt_operations;
7474
struct fsverity_info;
7575
struct fsverity_operations;
76+
struct fsnotify_mark_connector;
77+
struct fsnotify_sb_info;
7678
struct fs_context;
7779
struct fs_parameter_spec;
7880
struct fileattr;
@@ -620,8 +622,6 @@ is_uncached_acl(struct posix_acl *acl)
620622
#define IOP_XATTR 0x0008
621623
#define IOP_DEFAULT_READLINK 0x0010
622624

623-
struct fsnotify_mark_connector;
624-
625625
/*
626626
* Keep mostly read-only and often accessed (especially for
627627
* the RCU path lookup and 'stat' data) fields at the beginning
@@ -1249,7 +1249,7 @@ struct super_block {
12491249

12501250
/*
12511251
* Keep s_fs_info, s_time_gran, s_fsnotify_mask, and
1252-
* s_fsnotify_marks together for cache efficiency. They are frequently
1252+
* s_fsnotify_info together for cache efficiency. They are frequently
12531253
* accessed and rarely modified.
12541254
*/
12551255
void *s_fs_info; /* Filesystem private info */
@@ -1261,7 +1261,7 @@ struct super_block {
12611261
time64_t s_time_max;
12621262
#ifdef CONFIG_FSNOTIFY
12631263
__u32 s_fsnotify_mask;
1264-
struct fsnotify_mark_connector __rcu *s_fsnotify_marks;
1264+
struct fsnotify_sb_info *s_fsnotify_info;
12651265
#endif
12661266

12671267
/*

include/linux/fsnotify_backend.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,23 @@ struct fsnotify_mark_connector {
477477
struct hlist_head list;
478478
};
479479

480+
/*
481+
* Container for per-sb fsnotify state (sb marks and more).
482+
* Attached lazily on first marked object on the sb and freed when killing sb.
483+
*/
484+
struct fsnotify_sb_info {
485+
struct fsnotify_mark_connector __rcu *sb_marks;
486+
};
487+
488+
static inline struct fsnotify_sb_info *fsnotify_sb_info(struct super_block *sb)
489+
{
490+
#ifdef CONFIG_FSNOTIFY
491+
return READ_ONCE(sb->s_fsnotify_info);
492+
#else
493+
return NULL;
494+
#endif
495+
}
496+
480497
static inline atomic_long_t *fsnotify_sb_watched_objects(struct super_block *sb)
481498
{
482499
return &sb->s_fsnotify_connectors;

0 commit comments

Comments
 (0)