Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 08991e83 authored by Jan Kara's avatar Jan Kara
Browse files

fsnotify: Free fsnotify_mark_connector when there is no mark attached



Currently we free fsnotify_mark_connector structure only when inode /
vfsmount is getting freed. This can however impose noticeable memory
overhead when marks get attached to inodes only temporarily. So free the
connector structure once the last mark is detached from the object.
Since notification infrastructure can be working with the connector
under the protection of fsnotify_mark_srcu, we have to be careful and
free the fsnotify_mark_connector only after SRCU period passes.

Reviewed-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
Reviewed-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 04662cab
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -234,9 +234,6 @@ void __destroy_inode(struct inode *inode)
	inode_detach_wb(inode);
	security_inode_free(inode);
	fsnotify_inode_delete(inode);
#ifdef CONFIG_FSNOTIFY
	fsnotify_connector_free(&inode->i_fsnotify_marks);
#endif
	locks_free_lock_context(inode);
	if (!inode->i_nlink) {
		WARN_ON(atomic_long_read(&inode->i_sb->s_remove_count) == 0);
+1 −1
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ struct mount {
	struct mountpoint *mnt_mp;	/* where is it mounted */
	struct hlist_node mnt_mp_list;	/* list mounts with the same mountpoint */
#ifdef CONFIG_FSNOTIFY
	struct fsnotify_mark_connector *mnt_fsnotify_marks;
	struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;
	__u32 mnt_fsnotify_mask;
#endif
	int mnt_id;			/* mount identifier */
+0 −3
Original line number Diff line number Diff line
@@ -1108,9 +1108,6 @@ static void cleanup_mnt(struct mount *mnt)
	if (unlikely(mnt->mnt_pins.first))
		mnt_pin_kill(mnt);
	fsnotify_vfsmount_delete(&mnt->mnt);
#ifdef CONFIG_FSNOTIFY
	fsnotify_connector_free(&mnt->mnt_fsnotify_marks);
#endif
	dput(mnt->mnt.mnt_root);
	deactivate_super(mnt->mnt.mnt_sb);
	mnt_free_id(mnt);
+6 −3
Original line number Diff line number Diff line
@@ -228,7 +228,8 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,

	if ((mask & FS_MODIFY) ||
	    (test_mask & to_tell->i_fsnotify_mask)) {
		inode_conn = lockless_dereference(to_tell->i_fsnotify_marks);
		inode_conn = srcu_dereference(to_tell->i_fsnotify_marks,
					      &fsnotify_mark_srcu);
		if (inode_conn)
			inode_node = srcu_dereference(inode_conn->list.first,
						      &fsnotify_mark_srcu);
@@ -236,11 +237,13 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,

	if (mnt && ((mask & FS_MODIFY) ||
		    (test_mask & mnt->mnt_fsnotify_mask))) {
		inode_conn = lockless_dereference(to_tell->i_fsnotify_marks);
		inode_conn = srcu_dereference(to_tell->i_fsnotify_marks,
					      &fsnotify_mark_srcu);
		if (inode_conn)
			inode_node = srcu_dereference(inode_conn->list.first,
						      &fsnotify_mark_srcu);
		vfsmount_conn = lockless_dereference(mnt->mnt_fsnotify_marks);
		vfsmount_conn = srcu_dereference(mnt->mnt_fsnotify_marks,
					         &fsnotify_mark_srcu);
		if (vfsmount_conn)
			vfsmount_node = srcu_dereference(
						vfsmount_conn->list.first,
+5 −5
Original line number Diff line number Diff line
@@ -20,19 +20,19 @@ extern int fsnotify_compare_groups(struct fsnotify_group *a,

/* Find mark belonging to given group in the list of marks */
extern struct fsnotify_mark *fsnotify_find_mark(
					struct fsnotify_mark_connector *conn,
				struct fsnotify_mark_connector __rcu **connp,
				struct fsnotify_group *group);
/* Destroy all marks connected via given connector */
extern void fsnotify_destroy_marks(struct fsnotify_mark_connector *conn);
extern void fsnotify_destroy_marks(struct fsnotify_mark_connector __rcu **connp);
/* run the list of all marks associated with inode and destroy them */
static inline void fsnotify_clear_marks_by_inode(struct inode *inode)
{
	fsnotify_destroy_marks(inode->i_fsnotify_marks);
	fsnotify_destroy_marks(&inode->i_fsnotify_marks);
}
/* run the list of all marks associated with vfsmount and destroy them */
static inline void fsnotify_clear_marks_by_mount(struct vfsmount *mnt)
{
	fsnotify_destroy_marks(real_mount(mnt)->mnt_fsnotify_marks);
	fsnotify_destroy_marks(&real_mount(mnt)->mnt_fsnotify_marks);
}
/* prepare for freeing all marks associated with given group */
extern void fsnotify_detach_group_marks(struct fsnotify_group *group);
Loading