diff options
Diffstat (limited to 'fs/notify/fsnotify.c')
-rw-r--r-- | fs/notify/fsnotify.c | 25 |
1 files changed, 13 insertions, 12 deletions
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 272c8a1dab3c..9a8da7a02a6f 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -33,14 +33,19 @@ void __fsnotify_vfsmount_delete(struct vfsmount *mnt) * @sb: superblock being unmounted. * * Called during unmount with no locks held, so needs to be safe against - * concurrent modifiers. We temporarily drop sb->s_inode_list_lock and CAN block. + * concurrent modifiers. Can block. */ static void fsnotify_unmount_inodes(struct super_block *sb) { - struct inode *inode, *iput_inode = NULL; + struct genradix_iter iter; + void **i; + + rcu_read_lock(); + genradix_for_each(&sb->s_inodes.items, iter, i) { + struct inode *inode = *((struct inode **) i); + if (!inode) + continue; - spin_lock(&sb->s_inode_list_lock); - list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { /* * We cannot __iget() an inode in state I_FREEING, * I_WILL_FREE, or I_NEW which is fine because by that point @@ -68,23 +73,19 @@ static void fsnotify_unmount_inodes(struct super_block *sb) __iget(inode); spin_unlock(&inode->i_lock); - spin_unlock(&sb->s_inode_list_lock); - - iput(iput_inode); + rcu_read_unlock(); /* for each watch, send FS_UNMOUNT and then remove it */ fsnotify_inode(inode, FS_UNMOUNT); fsnotify_inode_delete(inode); - iput_inode = inode; + iput(inode); cond_resched(); - spin_lock(&sb->s_inode_list_lock); + rcu_read_lock(); } - spin_unlock(&sb->s_inode_list_lock); - - iput(iput_inode); + rcu_read_unlock(); } void fsnotify_sb_delete(struct super_block *sb) |