inotify: send IN_ATTRIB events when link count changes
Jan Kara [Wed, 6 Feb 2008 09:37:13 +0000 (01:37 -0800)]
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


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

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 <>
Acked-by: Morten Welinder <>
Cc: Robert Love <>
Cc: John McCutchan <>
Cc: Steven French <>
Cc: Kamalesh Babulal <>
Signed-off-by: Andrew Morton <>
Signed-off-by: Linus Torvalds <>


index 73e2e66..241cff4 100644 (file)
@@ -2188,6 +2188,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
        /* We don't d_delete() NFS sillyrenamed files--they still exist. */
        if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
+               fsnotify_link_count(dentry->d_inode);
@@ -2360,7 +2361,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
        error = dir->i_op->link(old_dentry, dir, new_dentry);
        if (!error)
-               fsnotify_create(dir, new_dentry);
+               fsnotify_link(dir, old_dentry->d_inode, new_dentry);
        return error;
index 2bd31fa..d4b7c4a 100644 (file)
@@ -92,6 +92,14 @@ static inline void fsnotify_inoderemove(struct inode *inode)
+ * fsnotify_link_count - inode's link count changed
+ */
+static inline void fsnotify_link_count(struct inode *inode)
+       inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL);
  * fsnotify_create - 'name' was linked in
 static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
@@ -103,6 +111,20 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
+ * fsnotify_link - new hardlink in 'inode' directory
+ * Note: We have to pass also the linked inode ptr as some filesystems leave
+ *   new_dentry->d_inode NULL and instantiate inode pointer later
+ */
+static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
+       inode_dir_notify(dir, DN_CREATE);
+       inotify_inode_queue_event(dir, IN_CREATE, 0, new_dentry->,
+                                 inode);
+       fsnotify_link_count(inode);
+       audit_inode_child(new_dentry->, new_dentry, dir);
  * fsnotify_mkdir - directory 'name' was created
 static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)