7979#define FSNOTIFY_REAPER_DELAY (1) /* 1 jiffy */
8080
8181struct srcu_struct fsnotify_mark_srcu ;
82- struct kmem_cache * fsnotify_mark_connector_cachep ;
82+ static struct kmem_cache * fsnotify_mark_connector_cachep ;
83+ static struct kmem_cache * fsnotify_inode_mark_connector_cachep ;
8384
8485static DEFINE_SPINLOCK (destroy_lock );
8586static LIST_HEAD (destroy_list );
@@ -323,10 +324,12 @@ static void fsnotify_connector_destroy_workfn(struct work_struct *work)
323324 while (conn ) {
324325 free = conn ;
325326 conn = conn -> destroy_next ;
326- kmem_cache_free ( fsnotify_mark_connector_cachep , free );
327+ kfree ( free );
327328 }
328329}
329330
331+ static void fsnotify_untrack_connector (struct fsnotify_mark_connector * conn );
332+
330333static void * fsnotify_detach_connector_from_object (
331334 struct fsnotify_mark_connector * conn ,
332335 unsigned int * type )
@@ -342,6 +345,7 @@ static void *fsnotify_detach_connector_from_object(
342345 if (conn -> type == FSNOTIFY_OBJ_TYPE_INODE ) {
343346 inode = fsnotify_conn_inode (conn );
344347 inode -> i_fsnotify_mask = 0 ;
348+ fsnotify_untrack_connector (conn );
345349
346350 /* Unpin inode when detaching from connector */
347351 if (!(conn -> flags & FSNOTIFY_CONN_FLAG_HAS_IREF ))
@@ -644,6 +648,8 @@ static int fsnotify_attach_info_to_sb(struct super_block *sb)
644648 if (!sbinfo )
645649 return - ENOMEM ;
646650
651+ INIT_LIST_HEAD (& sbinfo -> inode_conn_list );
652+ spin_lock_init (& sbinfo -> list_lock );
647653 /*
648654 * cmpxchg() provides the barrier so that callers of fsnotify_sb_info()
649655 * will observe an initialized structure
@@ -655,28 +661,82 @@ static int fsnotify_attach_info_to_sb(struct super_block *sb)
655661 return 0 ;
656662}
657663
658- static int fsnotify_attach_connector_to_object ( fsnotify_connp_t * connp ,
659- void * obj , unsigned int obj_type )
660- {
661- struct fsnotify_mark_connector * conn ;
664+ struct fsnotify_inode_mark_connector {
665+ struct fsnotify_mark_connector common ;
666+ struct list_head conns_list ;
667+ } ;
662668
663- conn = kmem_cache_alloc ( fsnotify_mark_connector_cachep , GFP_KERNEL );
664- if (! conn )
665- return - ENOMEM ;
669+ static void fsnotify_init_connector ( struct fsnotify_mark_connector * conn ,
670+ void * obj , unsigned int obj_type )
671+ {
666672 spin_lock_init (& conn -> lock );
667673 INIT_HLIST_HEAD (& conn -> list );
668674 conn -> flags = 0 ;
669675 conn -> prio = 0 ;
670676 conn -> type = obj_type ;
671677 conn -> obj = obj ;
678+ }
679+
680+ static struct fsnotify_mark_connector *
681+ fsnotify_alloc_inode_connector (struct inode * inode )
682+ {
683+ struct fsnotify_inode_mark_connector * iconn ;
684+ struct fsnotify_sb_info * sbinfo = fsnotify_sb_info (inode -> i_sb );
685+
686+ iconn = kmem_cache_alloc (fsnotify_inode_mark_connector_cachep ,
687+ GFP_KERNEL );
688+ if (!iconn )
689+ return NULL ;
690+
691+ fsnotify_init_connector (& iconn -> common , inode , FSNOTIFY_OBJ_TYPE_INODE );
692+ spin_lock (& sbinfo -> list_lock );
693+ list_add (& iconn -> conns_list , & sbinfo -> inode_conn_list );
694+ spin_unlock (& sbinfo -> list_lock );
695+
696+ return & iconn -> common ;
697+ }
698+
699+ static void fsnotify_untrack_connector (struct fsnotify_mark_connector * conn )
700+ {
701+ struct fsnotify_inode_mark_connector * iconn ;
702+ struct fsnotify_sb_info * sbinfo ;
703+
704+ if (conn -> type != FSNOTIFY_OBJ_TYPE_INODE )
705+ return ;
706+
707+ iconn = container_of (conn , struct fsnotify_inode_mark_connector , common );
708+ sbinfo = fsnotify_sb_info (fsnotify_conn_inode (conn )-> i_sb );
709+ spin_lock (& sbinfo -> list_lock );
710+ list_del (& iconn -> conns_list );
711+ spin_unlock (& sbinfo -> list_lock );
712+ }
713+
714+ static int fsnotify_attach_connector_to_object (fsnotify_connp_t * connp ,
715+ void * obj , unsigned int obj_type )
716+ {
717+ struct fsnotify_mark_connector * conn ;
718+
719+ if (obj_type == FSNOTIFY_OBJ_TYPE_INODE ) {
720+ struct inode * inode = obj ;
721+
722+ conn = fsnotify_alloc_inode_connector (inode );
723+ } else {
724+ conn = kmem_cache_alloc (fsnotify_mark_connector_cachep ,
725+ GFP_KERNEL );
726+ if (conn )
727+ fsnotify_init_connector (conn , obj , obj_type );
728+ }
729+ if (!conn )
730+ return - ENOMEM ;
672731
673732 /*
674733 * cmpxchg() provides the barrier so that readers of *connp can see
675734 * only initialized structure
676735 */
677736 if (cmpxchg (connp , NULL , conn )) {
678737 /* Someone else created list structure for us */
679- kmem_cache_free (fsnotify_mark_connector_cachep , conn );
738+ fsnotify_untrack_connector (conn );
739+ kfree (conn );
680740 }
681741 return 0 ;
682742}
@@ -1007,3 +1067,12 @@ void fsnotify_wait_marks_destroyed(void)
10071067 flush_delayed_work (& reaper_work );
10081068}
10091069EXPORT_SYMBOL_GPL (fsnotify_wait_marks_destroyed );
1070+
1071+ __init void fsnotify_init_connector_caches (void )
1072+ {
1073+ fsnotify_mark_connector_cachep = KMEM_CACHE (fsnotify_mark_connector ,
1074+ SLAB_PANIC );
1075+ fsnotify_inode_mark_connector_cachep = KMEM_CACHE (
1076+ fsnotify_inode_mark_connector ,
1077+ SLAB_PANIC );
1078+ }
0 commit comments