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

fsnotify: Use connector list for destroying inode marks

Instead of iterating all inodes belonging to a superblock to find inode
marks and remove them on umount, iterate all inode connectors for the
superblock. This may be substantially faster since there are generally
much less inodes with fsnotify marks than all inodes. It also removes
one use of sb->s_inodes list which we strive to ultimately remove.

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

Jan Kara a05fc7ed 94bd0125

+54 -60
+1 -60
fs/notify/fsnotify.c
··· 33 33 fsnotify_clear_marks_by_mntns(mntns); 34 34 } 35 35 36 - /** 37 - * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes. 38 - * @sb: superblock being unmounted. 39 - * 40 - * Called during unmount with no locks held, so needs to be safe against 41 - * concurrent modifiers. We temporarily drop sb->s_inode_list_lock and CAN block. 42 - */ 43 - static void fsnotify_unmount_inodes(struct super_block *sb) 44 - { 45 - struct inode *inode, *iput_inode = NULL; 46 - 47 - spin_lock(&sb->s_inode_list_lock); 48 - list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { 49 - /* 50 - * We cannot __iget() an inode in state I_FREEING, 51 - * I_WILL_FREE, or I_NEW which is fine because by that point 52 - * the inode cannot have any associated watches. 53 - */ 54 - spin_lock(&inode->i_lock); 55 - if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) { 56 - spin_unlock(&inode->i_lock); 57 - continue; 58 - } 59 - 60 - /* 61 - * If i_count is zero, the inode cannot have any watches and 62 - * doing an __iget/iput with SB_ACTIVE clear would actually 63 - * evict all inodes with zero i_count from icache which is 64 - * unnecessarily violent and may in fact be illegal to do. 65 - * However, we should have been called /after/ evict_inodes 66 - * removed all zero refcount inodes, in any case. Test to 67 - * be sure. 68 - */ 69 - if (!icount_read(inode)) { 70 - spin_unlock(&inode->i_lock); 71 - continue; 72 - } 73 - 74 - __iget(inode); 75 - spin_unlock(&inode->i_lock); 76 - spin_unlock(&sb->s_inode_list_lock); 77 - 78 - iput(iput_inode); 79 - 80 - /* for each watch, send FS_UNMOUNT and then remove it */ 81 - fsnotify_inode(inode, FS_UNMOUNT); 82 - 83 - fsnotify_inode_delete(inode); 84 - 85 - iput_inode = inode; 86 - 87 - cond_resched(); 88 - spin_lock(&sb->s_inode_list_lock); 89 - } 90 - spin_unlock(&sb->s_inode_list_lock); 91 - 92 - iput(iput_inode); 93 - } 94 - 95 36 void fsnotify_sb_delete(struct super_block *sb) 96 37 { 97 38 struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb); ··· 41 100 if (!sbinfo) 42 101 return; 43 102 44 - fsnotify_unmount_inodes(sb); 103 + fsnotify_unmount_inodes(sbinfo); 45 104 fsnotify_clear_marks_by_sb(sb); 46 105 /* Wait for outstanding object references from connectors */ 47 106 wait_var_event(fsnotify_sb_watched_objects(sb),
+3
fs/notify/fsnotify.h
··· 77 77 extern int fsnotify_compare_groups(struct fsnotify_group *a, 78 78 struct fsnotify_group *b); 79 79 80 + /* Destroy all inode marks for given superblock */ 81 + void fsnotify_unmount_inodes(struct fsnotify_sb_info *sbinfo); 82 + 80 83 /* Destroy all marks attached to an object via connector */ 81 84 extern void fsnotify_destroy_marks(fsnotify_connp_t *connp); 82 85 /* run the list of all marks associated with inode and destroy them */
+50
fs/notify/mark.c
··· 666 666 struct list_head conns_list; 667 667 }; 668 668 669 + static struct inode *fsnotify_get_living_inode(struct fsnotify_sb_info *sbinfo) 670 + { 671 + struct fsnotify_inode_mark_connector *iconn; 672 + struct inode *inode; 673 + 674 + spin_lock(&sbinfo->list_lock); 675 + /* Find the first non-evicting inode */ 676 + list_for_each_entry(iconn, &sbinfo->inode_conn_list, conns_list) { 677 + /* All connectors on the list are still attached to an inode */ 678 + inode = iconn->common.obj; 679 + /* 680 + * For connectors without FSNOTIFY_CONN_FLAG_HAS_IREF 681 + * (evictable marks) corresponding inode may well have 0 682 + * refcount and can be undergoing eviction. OTOH list_lock 683 + * protects us from the connector getting detached and inode 684 + * freed. So we can poke around the inode safely. 685 + */ 686 + spin_lock(&inode->i_lock); 687 + if (likely( 688 + !(inode_state_read(inode) & (I_FREEING | I_WILL_FREE)))) { 689 + __iget(inode); 690 + spin_unlock(&inode->i_lock); 691 + spin_unlock(&sbinfo->list_lock); 692 + return inode; 693 + } 694 + spin_unlock(&inode->i_lock); 695 + } 696 + spin_unlock(&sbinfo->list_lock); 697 + 698 + return NULL; 699 + } 700 + 701 + /** 702 + * fsnotify_unmount_inodes - an sb is unmounting. Handle any watched inodes. 703 + * @sbinfo: fsnotify info for superblock being unmounted. 704 + * 705 + * Walk all inode connectors for the superblock and free all associated marks. 706 + */ 707 + void fsnotify_unmount_inodes(struct fsnotify_sb_info *sbinfo) 708 + { 709 + struct inode *inode; 710 + 711 + while ((inode = fsnotify_get_living_inode(sbinfo))) { 712 + fsnotify_inode(inode, FS_UNMOUNT); 713 + fsnotify_clear_marks_by_inode(inode); 714 + iput(inode); 715 + cond_resched(); 716 + } 717 + } 718 + 669 719 static void fsnotify_init_connector(struct fsnotify_mark_connector *conn, 670 720 void *obj, unsigned int obj_type) 671 721 {