From: John McCutchan <ttb@tentacle.dhs.org>

People have run into a problem when they do this:

watch (file1, all_events);
watch (file2, some_events);

if file2 is a hard link to file1, some events will be missed because by
default we replace the mask.  The patch below adds a flag IN_MASK_ADD which
will cause inotify to add to the existing mask if present.

Signed-off-by: John McCutchan <ttb@tentacle.dhs.org>
Signed-off-by: Robert Love <rml@novell.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 fs/inotify.c            |    9 ++++++++-
 include/linux/inotify.h |    1 +
 2 files changed, 9 insertions(+), 1 deletion(-)

diff -puN fs/inotify.c~inotify-fix-event-loss-on-hardlinked-files fs/inotify.c
--- 25/fs/inotify.c~inotify-fix-event-loss-on-hardlinked-files	Wed Aug 31 13:14:45 2005
+++ 25-akpm/fs/inotify.c	Wed Aug 31 13:14:45 2005
@@ -925,6 +925,7 @@ asmlinkage long sys_inotify_add_watch(in
 	struct nameidata nd;
 	struct file *filp;
 	int ret, fput_needed;
+	int mask_add = 0;
 
 	filp = fget_light(fd, &fput_needed);
 	if (unlikely(!filp))
@@ -947,6 +948,9 @@ asmlinkage long sys_inotify_add_watch(in
 	down(&inode->inotify_sem);
 	down(&dev->sem);
 
+	if (mask & IN_MASK_ADD)
+		mask_add = 1;
+
 	/* don't let user-space set invalid bits: we don't want flags set */
 	mask &= IN_ALL_EVENTS;
 	if (unlikely(!mask)) {
@@ -960,7 +964,10 @@ asmlinkage long sys_inotify_add_watch(in
 	 */
 	old = inode_find_dev(inode, dev);
 	if (unlikely(old)) {
-		old->mask = mask;
+		if (mask_add)
+			old->mask |= mask;
+		else
+			old->mask = mask;
 		ret = old->wd;
 		goto out;
 	}
diff -puN include/linux/inotify.h~inotify-fix-event-loss-on-hardlinked-files include/linux/inotify.h
--- 25/include/linux/inotify.h~inotify-fix-event-loss-on-hardlinked-files	Wed Aug 31 13:14:45 2005
+++ 25-akpm/include/linux/inotify.h	Wed Aug 31 13:14:45 2005
@@ -47,6 +47,7 @@ struct inotify_event {
 #define IN_MOVE			(IN_MOVED_FROM | IN_MOVED_TO) /* moves */
 
 /* special flags */
+#define IN_MASK_ADD		0x20000000	/* add to the mask of an already existing watch */
 #define IN_ISDIR		0x40000000	/* event occurred against dir */
 #define IN_ONESHOT		0x80000000	/* only send event once */
 
_