aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2010-10-25 20:49:35 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2010-10-25 21:27:18 -0400
commit63997e98a3be68d7cec806d22bf9b02b2e1daabb (patch)
treeacd366273dc459d6b34e7f67216c06eb56117a4a /fs
parent9843b76aae80293f5b5a0e275360627508595ce5 (diff)
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/inode.c46
-rw-r--r--fs/internal.h1
-rw-r--r--fs/notify/inode_mark.c2
-rw-r--r--fs/super.c8
4 files changed, 51 insertions, 6 deletions
diff --git a/fs/inode.c b/fs/inode.c
index f6b3b52f1278..a6d60682f0fd 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -478,6 +478,49 @@ static void dispose_list(struct list_head *head)
478} 478}
479 479
480/** 480/**
481 * evict_inodes - evict all evictable inodes for a superblock
482 * @sb: superblock to operate on
483 *
484 * Make sure that no inodes with zero refcount are retained. This is
485 * called by superblock shutdown after having MS_ACTIVE flag removed,
486 * so any inode reaching zero refcount during or after that call will
487 * be immediately evicted.
488 */
489void evict_inodes(struct super_block *sb)
490{
491 struct inode *inode, *next;
492 LIST_HEAD(dispose);
493
494 down_write(&iprune_sem);
495
496 spin_lock(&inode_lock);
497 list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
498 if (atomic_read(&inode->i_count))
499 continue;
500
501 if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
502 WARN_ON(1);
503 continue;
504 }
505
506 inode->i_state |= I_FREEING;
507
508 /*
509 * Move the inode off the IO lists and LRU once I_FREEING is
510 * set so that it won't get moved back on there if it is dirty.
511 */
512 list_move(&inode->i_lru, &dispose);
513 list_del_init(&inode->i_wb_list);
514 if (!(inode->i_state & (I_DIRTY | I_SYNC)))
515 percpu_counter_dec(&nr_inodes_unused);
516 }
517 spin_unlock(&inode_lock);
518
519 dispose_list(&dispose);
520 up_write(&iprune_sem);
521}
522
523/**
481 * invalidate_inodes - attempt to free all inodes on a superblock 524 * invalidate_inodes - attempt to free all inodes on a superblock
482 * @sb: superblock to operate on 525 * @sb: superblock to operate on
483 * 526 *
@@ -493,9 +536,8 @@ int invalidate_inodes(struct super_block *sb)
493 down_write(&iprune_sem); 536 down_write(&iprune_sem);
494 537
495 spin_lock(&inode_lock); 538 spin_lock(&inode_lock);
496 fsnotify_unmount_inodes(&sb->s_inodes);
497 list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { 539 list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
498 if (inode->i_state & I_NEW) 540 if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE))
499 continue; 541 continue;
500 if (atomic_read(&inode->i_count)) { 542 if (atomic_read(&inode->i_count)) {
501 busy = 1; 543 busy = 1;
diff --git a/fs/internal.h b/fs/internal.h
index 4cc67eb6ed56..ebad3b90752d 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -106,4 +106,5 @@ extern void release_open_intent(struct nameidata *);
106 * inode.c 106 * inode.c
107 */ 107 */
108extern int get_nr_dirty_inodes(void); 108extern int get_nr_dirty_inodes(void);
109extern int evict_inodes(struct super_block *);
109extern int invalidate_inodes(struct super_block *); 110extern int invalidate_inodes(struct super_block *);
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c
index 33297c005060..21ed10660b80 100644
--- a/fs/notify/inode_mark.c
+++ b/fs/notify/inode_mark.c
@@ -240,6 +240,7 @@ void fsnotify_unmount_inodes(struct list_head *list)
240{ 240{
241 struct inode *inode, *next_i, *need_iput = NULL; 241 struct inode *inode, *next_i, *need_iput = NULL;
242 242
243 spin_lock(&inode_lock);
243 list_for_each_entry_safe(inode, next_i, list, i_sb_list) { 244 list_for_each_entry_safe(inode, next_i, list, i_sb_list) {
244 struct inode *need_iput_tmp; 245 struct inode *need_iput_tmp;
245 246
@@ -297,4 +298,5 @@ void fsnotify_unmount_inodes(struct list_head *list)
297 298
298 spin_lock(&inode_lock); 299 spin_lock(&inode_lock);
299 } 300 }
301 spin_unlock(&inode_lock);
300} 302}
diff --git a/fs/super.c b/fs/super.c
index 8819e3a7ff20..b9c9869165db 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -273,14 +273,14 @@ void generic_shutdown_super(struct super_block *sb)
273 get_fs_excl(); 273 get_fs_excl();
274 sb->s_flags &= ~MS_ACTIVE; 274 sb->s_flags &= ~MS_ACTIVE;
275 275
276 /* bad name - it should be evict_inodes() */ 276 fsnotify_unmount_inodes(&sb->s_inodes);
277 invalidate_inodes(sb); 277
278 evict_inodes(sb);
278 279
279 if (sop->put_super) 280 if (sop->put_super)
280 sop->put_super(sb); 281 sop->put_super(sb);
281 282
282 /* Forget any remaining inodes */ 283 if (!list_empty(&sb->s_inodes)) {
283 if (invalidate_inodes(sb)) {
284 printk("VFS: Busy inodes after unmount of %s. " 284 printk("VFS: Busy inodes after unmount of %s. "
285 "Self-destruct in 5 seconds. Have a nice day...\n", 285 "Self-destruct in 5 seconds. Have a nice day...\n",
286 sb->s_id); 286 sb->s_id);