mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-01 00:58:39 +02:00 
			
		
		
		
	split invalidate_inodes()
Pull removal of fsnotify marks into generic_shutdown_super(). Split umount-time work into a new function - evict_inodes(). Make sure that invalidate_inodes() will be able to cope with I_FREEING once we change locking in iput(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									9843b76aae
								
							
						
					
					
						commit
						63997e98a3
					
				
					 4 changed files with 51 additions and 6 deletions
				
			
		
							
								
								
									
										46
									
								
								fs/inode.c
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								fs/inode.c
									
									
									
									
									
								
							|  | @ -477,6 +477,49 @@ static void dispose_list(struct list_head *head) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * evict_inodes	- evict all evictable inodes for a superblock | ||||||
|  |  * @sb:		superblock to operate on | ||||||
|  |  * | ||||||
|  |  * Make sure that no inodes with zero refcount are retained.  This is | ||||||
|  |  * called by superblock shutdown after having MS_ACTIVE flag removed, | ||||||
|  |  * so any inode reaching zero refcount during or after that call will | ||||||
|  |  * be immediately evicted. | ||||||
|  |  */ | ||||||
|  | void evict_inodes(struct super_block *sb) | ||||||
|  | { | ||||||
|  | 	struct inode *inode, *next; | ||||||
|  | 	LIST_HEAD(dispose); | ||||||
|  | 
 | ||||||
|  | 	down_write(&iprune_sem); | ||||||
|  | 
 | ||||||
|  | 	spin_lock(&inode_lock); | ||||||
|  | 	list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { | ||||||
|  | 		if (atomic_read(&inode->i_count)) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { | ||||||
|  | 			WARN_ON(1); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		inode->i_state |= I_FREEING; | ||||||
|  | 
 | ||||||
|  | 		/*
 | ||||||
|  | 		 * Move the inode off the IO lists and LRU once I_FREEING is | ||||||
|  | 		 * set so that it won't get moved back on there if it is dirty. | ||||||
|  | 		 */ | ||||||
|  | 		list_move(&inode->i_lru, &dispose); | ||||||
|  | 		list_del_init(&inode->i_wb_list); | ||||||
|  | 		if (!(inode->i_state & (I_DIRTY | I_SYNC))) | ||||||
|  | 			percpu_counter_dec(&nr_inodes_unused); | ||||||
|  | 	} | ||||||
|  | 	spin_unlock(&inode_lock); | ||||||
|  | 
 | ||||||
|  | 	dispose_list(&dispose); | ||||||
|  | 	up_write(&iprune_sem); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * invalidate_inodes	- attempt to free all inodes on a superblock |  * invalidate_inodes	- attempt to free all inodes on a superblock | ||||||
|  * @sb:		superblock to operate on |  * @sb:		superblock to operate on | ||||||
|  | @ -493,9 +536,8 @@ int invalidate_inodes(struct super_block *sb) | ||||||
| 	down_write(&iprune_sem); | 	down_write(&iprune_sem); | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&inode_lock); | 	spin_lock(&inode_lock); | ||||||
| 	fsnotify_unmount_inodes(&sb->s_inodes); |  | ||||||
| 	list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { | 	list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { | ||||||
| 		if (inode->i_state & I_NEW) | 		if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) | ||||||
| 			continue; | 			continue; | ||||||
| 		if (atomic_read(&inode->i_count)) { | 		if (atomic_read(&inode->i_count)) { | ||||||
| 			busy = 1; | 			busy = 1; | ||||||
|  |  | ||||||
|  | @ -106,4 +106,5 @@ extern void release_open_intent(struct nameidata *); | ||||||
|  * inode.c |  * inode.c | ||||||
|  */ |  */ | ||||||
| extern int get_nr_dirty_inodes(void); | extern int get_nr_dirty_inodes(void); | ||||||
|  | extern int evict_inodes(struct super_block *); | ||||||
| extern int invalidate_inodes(struct super_block *); | extern int invalidate_inodes(struct super_block *); | ||||||
|  |  | ||||||
|  | @ -240,6 +240,7 @@ void fsnotify_unmount_inodes(struct list_head *list) | ||||||
| { | { | ||||||
| 	struct inode *inode, *next_i, *need_iput = NULL; | 	struct inode *inode, *next_i, *need_iput = NULL; | ||||||
| 
 | 
 | ||||||
|  | 	spin_lock(&inode_lock); | ||||||
| 	list_for_each_entry_safe(inode, next_i, list, i_sb_list) { | 	list_for_each_entry_safe(inode, next_i, list, i_sb_list) { | ||||||
| 		struct inode *need_iput_tmp; | 		struct inode *need_iput_tmp; | ||||||
| 
 | 
 | ||||||
|  | @ -297,4 +298,5 @@ void fsnotify_unmount_inodes(struct list_head *list) | ||||||
| 
 | 
 | ||||||
| 		spin_lock(&inode_lock); | 		spin_lock(&inode_lock); | ||||||
| 	} | 	} | ||||||
|  | 	spin_unlock(&inode_lock); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -273,14 +273,14 @@ void generic_shutdown_super(struct super_block *sb) | ||||||
| 		get_fs_excl(); | 		get_fs_excl(); | ||||||
| 		sb->s_flags &= ~MS_ACTIVE; | 		sb->s_flags &= ~MS_ACTIVE; | ||||||
| 
 | 
 | ||||||
| 		/* bad name - it should be evict_inodes() */ | 		fsnotify_unmount_inodes(&sb->s_inodes); | ||||||
| 		invalidate_inodes(sb); | 
 | ||||||
|  | 		evict_inodes(sb); | ||||||
| 
 | 
 | ||||||
| 		if (sop->put_super) | 		if (sop->put_super) | ||||||
| 			sop->put_super(sb); | 			sop->put_super(sb); | ||||||
| 
 | 
 | ||||||
| 		/* Forget any remaining inodes */ | 		if (!list_empty(&sb->s_inodes)) { | ||||||
| 		if (invalidate_inodes(sb)) { |  | ||||||
| 			printk("VFS: Busy inodes after unmount of %s. " | 			printk("VFS: Busy inodes after unmount of %s. " | ||||||
| 			   "Self-destruct in 5 seconds.  Have a nice day...\n", | 			   "Self-destruct in 5 seconds.  Have a nice day...\n", | ||||||
| 			   sb->s_id); | 			   sb->s_id); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Al Viro
						Al Viro