Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fsnotify: Track inode connectors for a superblock

Introduce a linked list tracking all inode connectors for a superblock.
We will use this list when the superblock is getting shutdown to
properly clean up all the inode marks instead of relying on scanning all
inodes in the superblock which can get rather slow.

Suggested-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Jan Kara <jack@suse.cz>

Jan Kara 94bd0125 6c790212

+89 -15
+5 -3
fs/notify/fsnotify.c
··· 112 112 113 113 void fsnotify_sb_free(struct super_block *sb) 114 114 { 115 - kfree(sb->s_fsnotify_info); 115 + if (sb->s_fsnotify_info) { 116 + WARN_ON_ONCE(!list_empty(&sb->s_fsnotify_info->inode_conn_list)); 117 + kfree(sb->s_fsnotify_info); 118 + } 116 119 } 117 120 118 121 /* ··· 780 777 if (ret) 781 778 panic("initializing fsnotify_mark_srcu"); 782 779 783 - fsnotify_mark_connector_cachep = KMEM_CACHE(fsnotify_mark_connector, 784 - SLAB_PANIC); 780 + fsnotify_init_connector_caches(); 785 781 786 782 return 0; 787 783 }
+1 -1
fs/notify/fsnotify.h
··· 106 106 */ 107 107 extern void fsnotify_set_children_dentry_flags(struct inode *inode); 108 108 109 - extern struct kmem_cache *fsnotify_mark_connector_cachep; 109 + void fsnotify_init_connector_caches(void); 110 110 111 111 #endif /* __FS_NOTIFY_FSNOTIFY_H_ */
+79 -10
fs/notify/mark.c
··· 79 79 #define FSNOTIFY_REAPER_DELAY (1) /* 1 jiffy */ 80 80 81 81 struct 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; 83 84 84 85 static DEFINE_SPINLOCK(destroy_lock); 85 86 static LIST_HEAD(destroy_list); ··· 324 323 while (conn) { 325 324 free = conn; 326 325 conn = conn->destroy_next; 327 - kmem_cache_free(fsnotify_mark_connector_cachep, free); 326 + kfree(free); 328 327 } 329 328 } 329 + 330 + static void fsnotify_untrack_connector(struct fsnotify_mark_connector *conn); 330 331 331 332 static void *fsnotify_detach_connector_from_object( 332 333 struct fsnotify_mark_connector *conn, ··· 345 342 if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) { 346 343 inode = fsnotify_conn_inode(conn); 347 344 inode->i_fsnotify_mask = 0; 345 + fsnotify_untrack_connector(conn); 348 346 349 347 /* Unpin inode when detaching from connector */ 350 348 if (!(conn->flags & FSNOTIFY_CONN_FLAG_HAS_IREF)) ··· 648 644 if (!sbinfo) 649 645 return -ENOMEM; 650 646 647 + INIT_LIST_HEAD(&sbinfo->inode_conn_list); 648 + spin_lock_init(&sbinfo->list_lock); 651 649 /* 652 650 * cmpxchg() provides the barrier so that callers of fsnotify_sb_info() 653 651 * will observe an initialized structure ··· 661 655 return 0; 662 656 } 663 657 664 - static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, 665 - void *obj, unsigned int obj_type) 666 - { 667 - struct fsnotify_mark_connector *conn; 658 + struct fsnotify_inode_mark_connector { 659 + struct fsnotify_mark_connector common; 660 + struct list_head conns_list; 661 + }; 668 662 669 - conn = kmem_cache_alloc(fsnotify_mark_connector_cachep, GFP_KERNEL); 670 - if (!conn) 671 - return -ENOMEM; 663 + static void fsnotify_init_connector(struct fsnotify_mark_connector *conn, 664 + void *obj, unsigned int obj_type) 665 + { 672 666 spin_lock_init(&conn->lock); 673 667 INIT_HLIST_HEAD(&conn->list); 674 668 conn->flags = 0; 675 669 conn->prio = 0; 676 670 conn->type = obj_type; 677 671 conn->obj = obj; 672 + } 673 + 674 + static struct fsnotify_mark_connector * 675 + fsnotify_alloc_inode_connector(struct inode *inode) 676 + { 677 + struct fsnotify_inode_mark_connector *iconn; 678 + struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(inode->i_sb); 679 + 680 + iconn = kmem_cache_alloc(fsnotify_inode_mark_connector_cachep, 681 + GFP_KERNEL); 682 + if (!iconn) 683 + return NULL; 684 + 685 + fsnotify_init_connector(&iconn->common, inode, FSNOTIFY_OBJ_TYPE_INODE); 686 + spin_lock(&sbinfo->list_lock); 687 + list_add(&iconn->conns_list, &sbinfo->inode_conn_list); 688 + spin_unlock(&sbinfo->list_lock); 689 + 690 + return &iconn->common; 691 + } 692 + 693 + static void fsnotify_untrack_connector(struct fsnotify_mark_connector *conn) 694 + { 695 + struct fsnotify_inode_mark_connector *iconn; 696 + struct fsnotify_sb_info *sbinfo; 697 + 698 + if (conn->type != FSNOTIFY_OBJ_TYPE_INODE) 699 + return; 700 + 701 + iconn = container_of(conn, struct fsnotify_inode_mark_connector, common); 702 + sbinfo = fsnotify_sb_info(fsnotify_conn_inode(conn)->i_sb); 703 + spin_lock(&sbinfo->list_lock); 704 + list_del(&iconn->conns_list); 705 + spin_unlock(&sbinfo->list_lock); 706 + } 707 + 708 + static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, 709 + void *obj, unsigned int obj_type) 710 + { 711 + struct fsnotify_mark_connector *conn; 712 + 713 + if (obj_type == FSNOTIFY_OBJ_TYPE_INODE) { 714 + struct inode *inode = obj; 715 + 716 + conn = fsnotify_alloc_inode_connector(inode); 717 + } else { 718 + conn = kmem_cache_alloc(fsnotify_mark_connector_cachep, 719 + GFP_KERNEL); 720 + if (conn) 721 + fsnotify_init_connector(conn, obj, obj_type); 722 + } 723 + if (!conn) 724 + return -ENOMEM; 678 725 679 726 /* 680 727 * cmpxchg() provides the barrier so that readers of *connp can see ··· 735 676 */ 736 677 if (cmpxchg(connp, NULL, conn)) { 737 678 /* Someone else created list structure for us */ 738 - kmem_cache_free(fsnotify_mark_connector_cachep, conn); 679 + fsnotify_untrack_connector(conn); 680 + kfree(conn); 739 681 } 740 682 return 0; 741 683 } ··· 1067 1007 flush_delayed_work(&reaper_work); 1068 1008 } 1069 1009 EXPORT_SYMBOL_GPL(fsnotify_wait_marks_destroyed); 1010 + 1011 + __init void fsnotify_init_connector_caches(void) 1012 + { 1013 + fsnotify_mark_connector_cachep = KMEM_CACHE(fsnotify_mark_connector, 1014 + SLAB_PANIC); 1015 + fsnotify_inode_mark_connector_cachep = KMEM_CACHE( 1016 + fsnotify_inode_mark_connector, 1017 + SLAB_PANIC); 1018 + }
+4 -1
include/linux/fsnotify_backend.h
··· 553 553 /* Used listing heads to free after srcu period expires */ 554 554 struct fsnotify_mark_connector *destroy_next; 555 555 }; 556 - struct hlist_head list; 556 + struct hlist_head list; /* List of marks */ 557 557 }; 558 558 559 559 /* ··· 562 562 */ 563 563 struct fsnotify_sb_info { 564 564 struct fsnotify_mark_connector __rcu *sb_marks; 565 + /* List of connectors for inode marks */ 566 + struct list_head inode_conn_list; 567 + spinlock_t list_lock; /* Lock protecting inode_conn_list */ 565 568 /* 566 569 * Number of inode/mount/sb objects that are being watched in this sb. 567 570 * Note that inodes objects are currently double-accounted.