fsnotify: rename fsnotify_{get,put}_sb_connectors()

Instead of counting the number of connectors in an sb, we would like
to count the number of watched objects per priority group.

As a start, create an accessor fsnotify_sb_watched_objects() to
s_fsnotify_connectors and rename the fsnotify_{get,put}_sb_connectors()
helpers to fsnotify_{get,put}_sb_watchers() to better describes the
counter.

Increment the counter at the end of fsnotify_attach_connector_to_object()
if connector was attached instead of decrementing it on race to connect.

This is fine, because fsnotify_delete_sb() cannot be running in parallel
to fsnotify_attach_connector_to_object() which requires a reference to
a filesystem object.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Message-Id: <20240317184154.1200192-2-amir73il@gmail.com>
This commit is contained in:
Amir Goldstein 2024-03-17 20:41:45 +02:00 committed by Jan Kara
parent 4d69c58ef2
commit d2f277e26f
4 changed files with 45 additions and 33 deletions

View file

@ -92,8 +92,8 @@ void fsnotify_sb_delete(struct super_block *sb)
fsnotify_unmount_inodes(sb);
fsnotify_clear_marks_by_sb(sb);
/* Wait for outstanding object references from connectors */
wait_var_event(&sb->s_fsnotify_connectors,
!atomic_long_read(&sb->s_fsnotify_connectors));
wait_var_event(fsnotify_sb_watched_objects(sb),
!atomic_long_read(fsnotify_sb_watched_objects(sb)));
}
/*

View file

@ -116,10 +116,43 @@ __u32 fsnotify_conn_mask(struct fsnotify_mark_connector *conn)
return *fsnotify_conn_mask_p(conn);
}
static void fsnotify_get_sb_watched_objects(struct super_block *sb)
{
atomic_long_inc(fsnotify_sb_watched_objects(sb));
}
static void fsnotify_put_sb_watched_objects(struct super_block *sb)
{
if (atomic_long_dec_and_test(fsnotify_sb_watched_objects(sb)))
wake_up_var(fsnotify_sb_watched_objects(sb));
}
static void fsnotify_get_inode_ref(struct inode *inode)
{
ihold(inode);
atomic_long_inc(&inode->i_sb->s_fsnotify_connectors);
fsnotify_get_sb_watched_objects(inode->i_sb);
}
static void fsnotify_put_inode_ref(struct inode *inode)
{
fsnotify_put_sb_watched_objects(inode->i_sb);
iput(inode);
}
static void fsnotify_get_sb_watchers(struct fsnotify_mark_connector *conn)
{
struct super_block *sb = fsnotify_connector_sb(conn);
if (sb)
fsnotify_get_sb_watched_objects(sb);
}
static void fsnotify_put_sb_watchers(struct fsnotify_mark_connector *conn)
{
struct super_block *sb = fsnotify_connector_sb(conn);
if (sb)
fsnotify_put_sb_watched_objects(sb);
}
/*
@ -213,31 +246,6 @@ static void fsnotify_connector_destroy_workfn(struct work_struct *work)
}
}
static void fsnotify_put_inode_ref(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
iput(inode);
if (atomic_long_dec_and_test(&sb->s_fsnotify_connectors))
wake_up_var(&sb->s_fsnotify_connectors);
}
static void fsnotify_get_sb_connectors(struct fsnotify_mark_connector *conn)
{
struct super_block *sb = fsnotify_connector_sb(conn);
if (sb)
atomic_long_inc(&sb->s_fsnotify_connectors);
}
static void fsnotify_put_sb_connectors(struct fsnotify_mark_connector *conn)
{
struct super_block *sb = fsnotify_connector_sb(conn);
if (sb && atomic_long_dec_and_test(&sb->s_fsnotify_connectors))
wake_up_var(&sb->s_fsnotify_connectors);
}
static void *fsnotify_detach_connector_from_object(
struct fsnotify_mark_connector *conn,
unsigned int *type)
@ -261,7 +269,7 @@ static void *fsnotify_detach_connector_from_object(
fsnotify_conn_sb(conn)->s_fsnotify_mask = 0;
}
fsnotify_put_sb_connectors(conn);
fsnotify_put_sb_watchers(conn);
rcu_assign_pointer(*(conn->obj), NULL);
conn->obj = NULL;
conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;
@ -549,8 +557,6 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
conn->flags = 0;
conn->type = obj_type;
conn->obj = connp;
conn->flags = 0;
fsnotify_get_sb_connectors(conn);
/*
* cmpxchg() provides the barrier so that readers of *connp can see
@ -558,10 +564,11 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
*/
if (cmpxchg(connp, NULL, conn)) {
/* Someone else created list structure for us */
fsnotify_put_sb_connectors(conn);
kmem_cache_free(fsnotify_mark_connector_cachep, conn);
return 0;
}
fsnotify_get_sb_watchers(conn);
return 0;
}

View file

@ -20,7 +20,7 @@
/* Are there any inode/mount/sb objects that are being watched at all? */
static inline bool fsnotify_sb_has_watchers(struct super_block *sb)
{
return atomic_long_read(&sb->s_fsnotify_connectors);
return atomic_long_read(fsnotify_sb_watched_objects(sb));
}
/*

View file

@ -483,6 +483,11 @@ struct fsnotify_mark_connector {
struct hlist_head list;
};
static inline atomic_long_t *fsnotify_sb_watched_objects(struct super_block *sb)
{
return &sb->s_fsnotify_connectors;
}
/*
* A mark is simply an object attached to an in core inode which allows an
* fsnotify listener to indicate they are either no longer interested in events