Commit ece95912db94d98e202cbedb8f35206deb29d83d

Authored by Jan Kara
Committed by Linus Torvalds
1 parent 6d98516181

inotify: send IN_ATTRIB events when link count changes

Currently, no notification event has been sent when inode's link count
changed.  This is inconvenient for the application in some cases:

Suppose you have the following directory structure

    foo/test
    bar/

and you watch test.  If someone does "mv foo/test bar/", you get event
IN_MOVE_SELF and you know something has happened with the file "test".
However if someone does "ln foo/test bar/test" and "rm foo/test" you get no
inotify event for the file "test" (only directories "foo" and "bar" receive
events).

Furthermore it could be argued that link count belongs to file's metadata and
thus IN_ATTRIB should be sent when it changes.

The following patch implements sending of IN_ATTRIB inotify events when link
count of the inode changes, i.e., when a hardlink to the inode is created or
when it is removed.  This event is sent in addition to all the events sent so
far.  In particular, when a last link to a file is removed, IN_ATTRIB event is
sent in addition to IN_DELETE_SELF event.

Signed-off-by: Jan Kara <jack@suse.cz>
Acked-by: Morten Welinder <mwelinder@gmail.com>
Cc: Robert Love <rlove@google.com>
Cc: John McCutchan <ttb@tentacle.dhs.org>
Cc: Steven French <sfrench@us.ibm.com>
Cc: Kamalesh Babulal <kamalesh@linux.vnet.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 2 changed files with 24 additions and 1 deletions Side-by-side Diff

... ... @@ -2188,6 +2188,7 @@
2188 2188  
2189 2189 /* We don't d_delete() NFS sillyrenamed files--they still exist. */
2190 2190 if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
  2191 + fsnotify_link_count(dentry->d_inode);
2191 2192 d_delete(dentry);
2192 2193 }
2193 2194  
... ... @@ -2360,7 +2361,7 @@
2360 2361 error = dir->i_op->link(old_dentry, dir, new_dentry);
2361 2362 mutex_unlock(&old_dentry->d_inode->i_mutex);
2362 2363 if (!error)
2363   - fsnotify_create(dir, new_dentry);
  2364 + fsnotify_link(dir, old_dentry->d_inode, new_dentry);
2364 2365 return error;
2365 2366 }
2366 2367  
include/linux/fsnotify.h
... ... @@ -92,6 +92,14 @@
92 92 }
93 93  
94 94 /*
  95 + * fsnotify_link_count - inode's link count changed
  96 + */
  97 +static inline void fsnotify_link_count(struct inode *inode)
  98 +{
  99 + inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL);
  100 +}
  101 +
  102 +/*
95 103 * fsnotify_create - 'name' was linked in
96 104 */
97 105 static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
... ... @@ -100,6 +108,20 @@
100 108 inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name,
101 109 dentry->d_inode);
102 110 audit_inode_child(dentry->d_name.name, dentry, inode);
  111 +}
  112 +
  113 +/*
  114 + * fsnotify_link - new hardlink in 'inode' directory
  115 + * Note: We have to pass also the linked inode ptr as some filesystems leave
  116 + * new_dentry->d_inode NULL and instantiate inode pointer later
  117 + */
  118 +static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
  119 +{
  120 + inode_dir_notify(dir, DN_CREATE);
  121 + inotify_inode_queue_event(dir, IN_CREATE, 0, new_dentry->d_name.name,
  122 + inode);
  123 + fsnotify_link_count(inode);
  124 + audit_inode_child(new_dentry->d_name.name, new_dentry, dir);
103 125 }
104 126  
105 127 /*