Commit 164bc6195139047faaf5ada1278332e99494803b

Authored by Eric Paris
1 parent 1ef5f13c6c

fsnotify: handle filesystem unmounts with fsnotify marks

When an fs is unmounted with an fsnotify mark entry attached to one of its
inodes we need to destroy that mark entry and we also (like inotify) send
an unmount event.

Signed-off-by: Eric Paris <eparis@redhat.com>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch@lst.de>

Showing 3 changed files with 77 additions and 0 deletions Side-by-side Diff

... ... @@ -407,6 +407,7 @@
407 407 mutex_lock(&iprune_mutex);
408 408 spin_lock(&inode_lock);
409 409 inotify_unmount_inodes(&sb->s_inodes);
  410 + fsnotify_unmount_inodes(&sb->s_inodes);
410 411 busy = invalidate_list(&sb->s_inodes, &throw_away);
411 412 spin_unlock(&inode_lock);
412 413  
fs/notify/inode_mark.c
... ... @@ -89,6 +89,7 @@
89 89 #include <linux/mutex.h>
90 90 #include <linux/slab.h>
91 91 #include <linux/spinlock.h>
  92 +#include <linux/writeback.h> /* for inode_lock */
92 93  
93 94 #include <asm/atomic.h>
94 95  
... ... @@ -350,5 +351,76 @@
350 351 }
351 352  
352 353 return ret;
  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 + */
  364 +void 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 + }
353 425 }
include/linux/fsnotify_backend.h
... ... @@ -336,6 +336,7 @@
336 336 extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group);
337 337 extern void fsnotify_get_mark(struct fsnotify_mark_entry *entry);
338 338 extern void fsnotify_put_mark(struct fsnotify_mark_entry *entry);
  339 +extern void fsnotify_unmount_inodes(struct list_head *list);
339 340  
340 341 /* put here because inotify does some weird stuff when destroying watches */
341 342 extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
... ... @@ -364,6 +365,9 @@
364 365 {
365 366 return 0;
366 367 }
  368 +
  369 +static inline void fsnotify_unmount_inodes(struct list_head *list)
  370 +{}
367 371  
368 372 #endif /* CONFIG_FSNOTIFY */
369 373