Currently number of watched objects is equal to the number of existing connectors. However in the future when connectors will no longer pin inodes these counts can differ. Introduce a separate counter of the number of existing connectors and use it what waiting for all marks and connectors to be freed. Signed-off-by: Jan Kara --- fs/notify/fsnotify.c | 5 +++-- fs/notify/mark.c | 13 ++++++++----- include/linux/fsnotify_backend.h | 2 ++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 46db712c83ec..f7f1d9ff3e38 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -103,8 +103,9 @@ 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(fsnotify_sb_watched_objects(sb), - !atomic_long_read(fsnotify_sb_watched_objects(sb))); + wait_var_event(&sbinfo->connector_count, + !atomic_long_read(&sbinfo->connector_count)); + WARN_ON(fsnotify_sb_has_watchers(sb)); WARN_ON(fsnotify_sb_has_priority_watchers(sb, FSNOTIFY_PRIO_CONTENT)); WARN_ON(fsnotify_sb_has_priority_watchers(sb, FSNOTIFY_PRIO_PRE_CONTENT)); diff --git a/fs/notify/mark.c b/fs/notify/mark.c index fd1fe8d37c36..3df230e218fb 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -145,11 +145,7 @@ static void fsnotify_get_sb_watched_objects(struct super_block *sb) static void fsnotify_put_sb_watched_objects(struct super_block *sb) { - atomic_long_t *watched_objects = fsnotify_sb_watched_objects(sb); - - /* the superblock can go away after this decrement */ - if (atomic_long_dec_and_test(watched_objects)) - wake_up_var(watched_objects); + atomic_long_dec(fsnotify_sb_watched_objects(sb)); } static void fsnotify_get_inode_ref(struct inode *inode) @@ -390,6 +386,11 @@ static void fsnotify_drop_object(unsigned int type, void *objp) static void fsnotify_free_connector(struct fsnotify_mark_connector *conn) { + struct fsnotify_sb_info *sbinfo = + fsnotify_sb_info(fsnotify_connector_sb(conn)); + + if (atomic_long_dec_and_test(&sbinfo->connector_count)) + wake_up_var(&sbinfo->connector_count); spin_lock(&destroy_lock); conn->destroy_next = connector_destroy_list; connector_destroy_list = conn; @@ -798,6 +799,8 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, if (!conn) return -ENOMEM; + atomic_long_inc( + &fsnotify_sb_info(fsnotify_connector_sb(conn))->connector_count); /* * cmpxchg() provides the barrier so that readers of *connp can see * only initialized structure diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 0a163c10b5e2..41d913c328fa 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -564,6 +564,8 @@ struct fsnotify_sb_info { struct fsnotify_mark_connector __rcu *sb_marks; /* Hash of connectors for inode marks */ struct rhashtable inode_conn_hash; + /* Number of connectors to objects in the superblock */ + atomic_long_t connector_count; /* * Number of inode/mount/sb objects that are being watched in this sb. * Note that inodes objects are currently double-accounted. -- 2.51.0