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
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 New Issue
Block a user