@@ -154,20 +154,23 @@ static void fsnotify_put_inode_ref(struct inode *inode)
154154 iput (inode );
155155}
156156
157- static void fsnotify_get_sb_watchers (struct fsnotify_mark_connector * conn )
157+ /*
158+ * Grab or drop watched objects reference depending on whether the connector
159+ * is attached and has any marks attached.
160+ */
161+ static void fsnotify_update_sb_watchers (struct super_block * sb ,
162+ struct fsnotify_mark_connector * conn )
158163{
159- struct super_block * sb = fsnotify_connector_sb (conn );
164+ bool is_watched = conn -> flags & FSNOTIFY_CONN_FLAG_IS_WATCHED ;
165+ bool has_marks = conn -> obj && !hlist_empty (& conn -> list );
160166
161- if (sb )
167+ if (has_marks && !is_watched ) {
168+ conn -> flags |= FSNOTIFY_CONN_FLAG_IS_WATCHED ;
162169 fsnotify_get_sb_watched_objects (sb );
163- }
164-
165- static void fsnotify_put_sb_watchers (struct fsnotify_mark_connector * conn )
166- {
167- struct super_block * sb = fsnotify_connector_sb (conn );
168-
169- if (sb )
170+ } else if (!has_marks && is_watched ) {
171+ conn -> flags &= ~FSNOTIFY_CONN_FLAG_IS_WATCHED ;
170172 fsnotify_put_sb_watched_objects (sb );
173+ }
171174}
172175
173176/*
@@ -266,6 +269,7 @@ static void *fsnotify_detach_connector_from_object(
266269 unsigned int * type )
267270{
268271 fsnotify_connp_t * connp = fsnotify_object_connp (conn -> obj , conn -> type );
272+ struct super_block * sb = fsnotify_connector_sb (conn );
269273 struct inode * inode = NULL ;
270274
271275 * type = conn -> type ;
@@ -285,10 +289,10 @@ static void *fsnotify_detach_connector_from_object(
285289 fsnotify_conn_sb (conn )-> s_fsnotify_mask = 0 ;
286290 }
287291
288- fsnotify_put_sb_watchers (conn );
289292 rcu_assign_pointer (* connp , NULL );
290293 conn -> obj = NULL ;
291294 conn -> type = FSNOTIFY_OBJ_TYPE_DETACHED ;
295+ fsnotify_update_sb_watchers (sb , conn );
292296
293297 return inode ;
294298}
@@ -340,6 +344,11 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
340344 objp = fsnotify_detach_connector_from_object (conn , & type );
341345 free_conn = true;
342346 } else {
347+ struct super_block * sb = fsnotify_connector_sb (conn );
348+
349+ /* Update watched objects after detaching mark */
350+ if (sb )
351+ fsnotify_update_sb_watchers (sb , conn );
343352 objp = __fsnotify_recalc_mask (conn );
344353 type = conn -> type ;
345354 }
@@ -581,10 +590,7 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
581590 if (cmpxchg (connp , NULL , conn )) {
582591 /* Someone else created list structure for us */
583592 kmem_cache_free (fsnotify_mark_connector_cachep , conn );
584- return 0 ;
585593 }
586-
587- fsnotify_get_sb_watchers (conn );
588594 return 0 ;
589595}
590596
@@ -624,6 +630,7 @@ static struct fsnotify_mark_connector *fsnotify_grab_connector(
624630static int fsnotify_add_mark_list (struct fsnotify_mark * mark , void * obj ,
625631 unsigned int obj_type , int add_flags )
626632{
633+ struct super_block * sb = fsnotify_object_sb (obj , obj_type );
627634 struct fsnotify_mark * lmark , * last = NULL ;
628635 struct fsnotify_mark_connector * conn ;
629636 fsnotify_connp_t * connp ;
@@ -673,6 +680,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, void *obj,
673680 /* mark should be the last entry. last is the current last entry */
674681 hlist_add_behind_rcu (& mark -> obj_list , & last -> obj_list );
675682added :
683+ fsnotify_update_sb_watchers (sb , conn );
676684 /*
677685 * Since connector is attached to object using cmpxchg() we are
678686 * guaranteed that connector initialization is fully visible by anyone
0 commit comments