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.

Merge tag 'fsnotify_for_v6.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull fsnotify updates from Jan Kara:
"A set of fixes to shutdown fsnotify subsystem before invalidating
dcache thus addressing some nasty possible races"

* tag 'fsnotify_for_v6.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
fsnotify: Shutdown fsnotify before destroying sb's dcache
fsnotify: Use connector list for destroying inode marks
fsnotify: Track inode connectors for a superblock

+145 -77
+6 -63
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), ··· 53 112 54 113 void fsnotify_sb_free(struct super_block *sb) 55 114 { 56 - 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 + } 57 119 } 58 120 59 121 /* ··· 721 777 if (ret) 722 778 panic("initializing fsnotify_mark_srcu"); 723 779 724 - fsnotify_mark_connector_cachep = KMEM_CACHE(fsnotify_mark_connector, 725 - SLAB_PANIC); 780 + fsnotify_init_connector_caches(); 726 781 727 782 return 0; 728 783 }
+4 -1
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 */ ··· 109 106 */ 110 107 extern void fsnotify_set_children_dentry_flags(struct inode *inode); 111 108 112 - extern struct kmem_cache *fsnotify_mark_connector_cachep; 109 + void fsnotify_init_connector_caches(void); 113 110 114 111 #endif /* __FS_NOTIFY_FSNOTIFY_H_ */
+129 -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 struct inode *fsnotify_get_living_inode(struct fsnotify_sb_info *sbinfo) 664 + { 665 + struct fsnotify_inode_mark_connector *iconn; 666 + struct inode *inode; 667 + 668 + spin_lock(&sbinfo->list_lock); 669 + /* Find the first non-evicting inode */ 670 + list_for_each_entry(iconn, &sbinfo->inode_conn_list, conns_list) { 671 + /* All connectors on the list are still attached to an inode */ 672 + inode = iconn->common.obj; 673 + /* 674 + * For connectors without FSNOTIFY_CONN_FLAG_HAS_IREF 675 + * (evictable marks) corresponding inode may well have 0 676 + * refcount and can be undergoing eviction. OTOH list_lock 677 + * protects us from the connector getting detached and inode 678 + * freed. So we can poke around the inode safely. 679 + */ 680 + spin_lock(&inode->i_lock); 681 + if (likely( 682 + !(inode_state_read(inode) & (I_FREEING | I_WILL_FREE)))) { 683 + __iget(inode); 684 + spin_unlock(&inode->i_lock); 685 + spin_unlock(&sbinfo->list_lock); 686 + return inode; 687 + } 688 + spin_unlock(&inode->i_lock); 689 + } 690 + spin_unlock(&sbinfo->list_lock); 691 + 692 + return NULL; 693 + } 694 + 695 + /** 696 + * fsnotify_unmount_inodes - an sb is unmounting. Handle any watched inodes. 697 + * @sbinfo: fsnotify info for superblock being unmounted. 698 + * 699 + * Walk all inode connectors for the superblock and free all associated marks. 700 + */ 701 + void fsnotify_unmount_inodes(struct fsnotify_sb_info *sbinfo) 702 + { 703 + struct inode *inode; 704 + 705 + while ((inode = fsnotify_get_living_inode(sbinfo))) { 706 + fsnotify_inode(inode, FS_UNMOUNT); 707 + fsnotify_clear_marks_by_inode(inode); 708 + iput(inode); 709 + cond_resched(); 710 + } 711 + } 712 + 713 + static void fsnotify_init_connector(struct fsnotify_mark_connector *conn, 714 + void *obj, unsigned int obj_type) 715 + { 672 716 spin_lock_init(&conn->lock); 673 717 INIT_HLIST_HEAD(&conn->list); 674 718 conn->flags = 0; 675 719 conn->prio = 0; 676 720 conn->type = obj_type; 677 721 conn->obj = obj; 722 + } 723 + 724 + static struct fsnotify_mark_connector * 725 + fsnotify_alloc_inode_connector(struct inode *inode) 726 + { 727 + struct fsnotify_inode_mark_connector *iconn; 728 + struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(inode->i_sb); 729 + 730 + iconn = kmem_cache_alloc(fsnotify_inode_mark_connector_cachep, 731 + GFP_KERNEL); 732 + if (!iconn) 733 + return NULL; 734 + 735 + fsnotify_init_connector(&iconn->common, inode, FSNOTIFY_OBJ_TYPE_INODE); 736 + spin_lock(&sbinfo->list_lock); 737 + list_add(&iconn->conns_list, &sbinfo->inode_conn_list); 738 + spin_unlock(&sbinfo->list_lock); 739 + 740 + return &iconn->common; 741 + } 742 + 743 + static void fsnotify_untrack_connector(struct fsnotify_mark_connector *conn) 744 + { 745 + struct fsnotify_inode_mark_connector *iconn; 746 + struct fsnotify_sb_info *sbinfo; 747 + 748 + if (conn->type != FSNOTIFY_OBJ_TYPE_INODE) 749 + return; 750 + 751 + iconn = container_of(conn, struct fsnotify_inode_mark_connector, common); 752 + sbinfo = fsnotify_sb_info(fsnotify_conn_inode(conn)->i_sb); 753 + spin_lock(&sbinfo->list_lock); 754 + list_del(&iconn->conns_list); 755 + spin_unlock(&sbinfo->list_lock); 756 + } 757 + 758 + static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, 759 + void *obj, unsigned int obj_type) 760 + { 761 + struct fsnotify_mark_connector *conn; 762 + 763 + if (obj_type == FSNOTIFY_OBJ_TYPE_INODE) { 764 + struct inode *inode = obj; 765 + 766 + conn = fsnotify_alloc_inode_connector(inode); 767 + } else { 768 + conn = kmem_cache_alloc(fsnotify_mark_connector_cachep, 769 + GFP_KERNEL); 770 + if (conn) 771 + fsnotify_init_connector(conn, obj, obj_type); 772 + } 773 + if (!conn) 774 + return -ENOMEM; 678 775 679 776 /* 680 777 * cmpxchg() provides the barrier so that readers of *connp can see ··· 785 676 */ 786 677 if (cmpxchg(connp, NULL, conn)) { 787 678 /* Someone else created list structure for us */ 788 - kmem_cache_free(fsnotify_mark_connector_cachep, conn); 679 + fsnotify_untrack_connector(conn); 680 + kfree(conn); 789 681 } 790 682 return 0; 791 683 } ··· 1117 1007 flush_delayed_work(&reaper_work); 1118 1008 } 1119 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 + }
+2 -2
fs/super.c
··· 620 620 const struct super_operations *sop = sb->s_op; 621 621 622 622 if (sb->s_root) { 623 + fsnotify_sb_delete(sb); 623 624 shrink_dcache_for_umount(sb); 624 625 sync_filesystem(sb); 625 626 sb->s_flags &= ~SB_ACTIVE; ··· 633 632 634 633 /* 635 634 * Clean up and evict any inodes that still have references due 636 - * to fsnotify or the security policy. 635 + * to the security policy. 637 636 */ 638 - fsnotify_sb_delete(sb); 639 637 security_sb_delete(sb); 640 638 641 639 if (sb->s_dio_done_wq) {
+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.