Skip to content

Commit

Permalink
split invalidate_inodes()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Al Viro committed Oct 26, 2010
1 parent 9843b76 commit 63997e9
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 6 deletions.
46 changes: 44 additions & 2 deletions fs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
* @sb: superblock to operate on
Expand All @@ -493,9 +536,8 @@ int invalidate_inodes(struct super_block *sb)
down_write(&iprune_sem);

spin_lock(&inode_lock);
fsnotify_unmount_inodes(&sb->s_inodes);
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;
if (atomic_read(&inode->i_count)) {
busy = 1;
Expand Down
1 change: 1 addition & 0 deletions fs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,5 @@ extern void release_open_intent(struct nameidata *);
* inode.c
*/
extern int get_nr_dirty_inodes(void);
extern int evict_inodes(struct super_block *);
extern int invalidate_inodes(struct super_block *);
2 changes: 2 additions & 0 deletions fs/notify/inode_mark.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ void fsnotify_unmount_inodes(struct list_head *list)
{
struct inode *inode, *next_i, *need_iput = NULL;

spin_lock(&inode_lock);
list_for_each_entry_safe(inode, next_i, list, i_sb_list) {
struct inode *need_iput_tmp;

Expand Down Expand Up @@ -297,4 +298,5 @@ void fsnotify_unmount_inodes(struct list_head *list)

spin_lock(&inode_lock);
}
spin_unlock(&inode_lock);
}
8 changes: 4 additions & 4 deletions fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,14 +273,14 @@ void generic_shutdown_super(struct super_block *sb)
get_fs_excl();
sb->s_flags &= ~MS_ACTIVE;

/* bad name - it should be evict_inodes() */
invalidate_inodes(sb);
fsnotify_unmount_inodes(&sb->s_inodes);

evict_inodes(sb);

if (sop->put_super)
sop->put_super(sb);

/* Forget any remaining inodes */
if (invalidate_inodes(sb)) {
if (!list_empty(&sb->s_inodes)) {
printk("VFS: Busy inodes after unmount of %s. "
"Self-destruct in 5 seconds. Have a nice day...\n",
sb->s_id);
Expand Down

0 comments on commit 63997e9

Please sign in to comment.