aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/inode.c1
-rw-r--r--fs/notify/inode_mark.c72
-rw-r--r--include/linux/fsnotify_backend.h4
3 files changed, 77 insertions, 0 deletions
diff --git a/fs/inode.c b/fs/inode.c
index 54c63ce3de25..ca337014ae29 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -407,6 +407,7 @@ int invalidate_inodes(struct super_block *sb)
407 mutex_lock(&iprune_mutex); 407 mutex_lock(&iprune_mutex);
408 spin_lock(&inode_lock); 408 spin_lock(&inode_lock);
409 inotify_unmount_inodes(&sb->s_inodes); 409 inotify_unmount_inodes(&sb->s_inodes);
410 fsnotify_unmount_inodes(&sb->s_inodes);
410 busy = invalidate_list(&sb->s_inodes, &throw_away); 411 busy = invalidate_list(&sb->s_inodes, &throw_away);
411 spin_unlock(&inode_lock); 412 spin_unlock(&inode_lock);
412 413
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c
index 282150f74cfa..0a499d2c6191 100644
--- a/fs/notify/inode_mark.c
+++ b/fs/notify/inode_mark.c
@@ -89,6 +89,7 @@
89#include <linux/mutex.h> 89#include <linux/mutex.h>
90#include <linux/slab.h> 90#include <linux/slab.h>
91#include <linux/spinlock.h> 91#include <linux/spinlock.h>
92#include <linux/writeback.h> /* for inode_lock */
92 93
93#include <asm/atomic.h> 94#include <asm/atomic.h>
94 95
@@ -351,3 +352,74 @@ int fsnotify_add_mark(struct fsnotify_mark_entry *entry,
351 352
352 return ret; 353 return ret;
353} 354}
355
356/**
357 * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes.
358 * @list: list of inodes being unmounted (sb->s_inodes)
359 *
360 * Called with inode_lock held, protecting the unmounting super block's list
361 * of inodes, and with iprune_mutex held, keeping shrink_icache_memory() at bay.
362 * We temporarily drop inode_lock, however, and CAN block.
363 */
364void fsnotify_unmount_inodes(struct list_head *list)
365{
366 struct inode *inode, *next_i, *need_iput = NULL;
367
368 list_for_each_entry_safe(inode, next_i, list, i_sb_list) {
369 struct inode *need_iput_tmp;
370
371 /*
372 * We cannot __iget() an inode in state I_CLEAR, I_FREEING,
373 * I_WILL_FREE, or I_NEW which is fine because by that point
374 * the inode cannot have any associated watches.
375 */
376 if (inode->i_state & (I_CLEAR|I_FREEING|I_WILL_FREE|I_NEW))
377 continue;
378
379 /*
380 * If i_count is zero, the inode cannot have any watches and
381 * doing an __iget/iput with MS_ACTIVE clear would actually
382 * evict all inodes with zero i_count from icache which is
383 * unnecessarily violent and may in fact be illegal to do.
384 */
385 if (!atomic_read(&inode->i_count))
386 continue;
387
388 need_iput_tmp = need_iput;
389 need_iput = NULL;
390
391 /* In case fsnotify_inode_delete() drops a reference. */
392 if (inode != need_iput_tmp)
393 __iget(inode);
394 else
395 need_iput_tmp = NULL;
396
397 /* In case the dropping of a reference would nuke next_i. */
398 if ((&next_i->i_sb_list != list) &&
399 atomic_read(&next_i->i_count) &&
400 !(next_i->i_state & (I_CLEAR | I_FREEING | I_WILL_FREE))) {
401 __iget(next_i);
402 need_iput = next_i;
403 }
404
405 /*
406 * We can safely drop inode_lock here because we hold
407 * references on both inode and next_i. Also no new inodes
408 * will be added since the umount has begun. Finally,
409 * iprune_mutex keeps shrink_icache_memory() away.
410 */
411 spin_unlock(&inode_lock);
412
413 if (need_iput_tmp)
414 iput(need_iput_tmp);
415
416 /* for each watch, send FS_UNMOUNT and then remove it */
417 fsnotify(inode, FS_UNMOUNT, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
418
419 fsnotify_inode_delete(inode);
420
421 iput(inode);
422
423 spin_lock(&inode_lock);
424 }
425}
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index efdf9e442d86..d2c0ee30e618 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -336,6 +336,7 @@ extern void fsnotify_destroy_mark_by_entry(struct fsnotify_mark_entry *entry);
336extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group); 336extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group);
337extern void fsnotify_get_mark(struct fsnotify_mark_entry *entry); 337extern void fsnotify_get_mark(struct fsnotify_mark_entry *entry);
338extern void fsnotify_put_mark(struct fsnotify_mark_entry *entry); 338extern void fsnotify_put_mark(struct fsnotify_mark_entry *entry);
339extern void fsnotify_unmount_inodes(struct list_head *list);
339 340
340/* put here because inotify does some weird stuff when destroying watches */ 341/* put here because inotify does some weird stuff when destroying watches */
341extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, 342extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
@@ -365,6 +366,9 @@ static inline u32 fsnotify_get_cookie(void)
365 return 0; 366 return 0;
366} 367}
367 368
369static inline void fsnotify_unmount_inodes(struct list_head *list)
370{}
371
368#endif /* CONFIG_FSNOTIFY */ 372#endif /* CONFIG_FSNOTIFY */
369 373
370#endif /* __KERNEL __ */ 374#endif /* __KERNEL __ */