aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2009-12-17 21:24:25 -0500
committerEric Paris <eparis@redhat.com>2010-07-28 09:58:54 -0400
commitecf081d1a73b077916f514f2ec744ded32b88ca1 (patch)
treef1a9892131a297d0f67cb0fd9189e3aac83e2219
parent35566087099c3ff8901d65ee98af56347ee66e5a (diff)
vfs: introduce FMODE_NONOTIFY
This is a new f_mode which can only be set by the kernel. It indicates that the fd was opened by fanotify and should not cause future fanotify events. This is needed to prevent fanotify livelock. An example of obvious livelock is from fanotify close events. Process A closes file1 This creates a close event for file1. fanotify opens file1 for Listener X Listener X deals with the event and closes its fd for file1. This creates a close event for file1. fanotify opens file1 for Listener X Listener X deals with the event and closes its fd for file1. This creates a close event for file1. fanotify opens file1 for Listener X Listener X deals with the event and closes its fd for file1. notice a pattern? The fix is to add the FMODE_NONOTIFY bit to the open filp done by the kernel for fanotify. Thus when that file is used it will not generate future events. This patch simply defines the bit. Signed-off-by: Eric Paris <eparis@redhat.com>
-rw-r--r--include/asm-generic/fcntl.h8
-rw-r--r--include/linux/fs.h6
-rw-r--r--include/linux/fsnotify.h24
3 files changed, 29 insertions, 9 deletions
diff --git a/include/asm-generic/fcntl.h b/include/asm-generic/fcntl.h
index fcd268ce0674..009bd6149d99 100644
--- a/include/asm-generic/fcntl.h
+++ b/include/asm-generic/fcntl.h
@@ -3,6 +3,14 @@
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5 5
6/*
7 * FMODE_EXEC is 0x20
8 * FMODE_NONOTIFY is 0x800000
9 * These cannot be used by userspace O_* until internal and external open
10 * flags are split.
11 * -Eric Paris
12 */
13
6#define O_ACCMODE 00000003 14#define O_ACCMODE 00000003
7#define O_RDONLY 00000000 15#define O_RDONLY 00000000
8#define O_WRONLY 00000001 16#define O_WRONLY 00000001
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 85fe89c43487..50ef4d4c95bf 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -90,6 +90,9 @@ struct inodes_stat_t {
90/* Expect random access pattern */ 90/* Expect random access pattern */
91#define FMODE_RANDOM ((__force fmode_t)0x1000) 91#define FMODE_RANDOM ((__force fmode_t)0x1000)
92 92
93/* File was opened by fanotify and shouldn't generate fanotify events */
94#define FMODE_NONOTIFY ((__force fmode_t)8388608)
95
93/* 96/*
94 * The below are the various read and write types that we support. Some of 97 * The below are the various read and write types that we support. Some of
95 * them include behavioral modifiers that send information down to the 98 * them include behavioral modifiers that send information down to the
@@ -2508,7 +2511,8 @@ int proc_nr_files(struct ctl_table *table, int write,
2508int __init get_filesystem_list(char *buf); 2511int __init get_filesystem_list(char *buf);
2509 2512
2510#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE]) 2513#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE])
2511#define OPEN_FMODE(flag) ((__force fmode_t)((flag + 1) & O_ACCMODE)) 2514#define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \
2515 (flag & FMODE_NONOTIFY)))
2512 2516
2513#endif /* __KERNEL__ */ 2517#endif /* __KERNEL__ */
2514#endif /* _LINUX_FS_H */ 2518#endif /* _LINUX_FS_H */
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 62e93a9dd115..5184a2b786c1 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -165,8 +165,10 @@ static inline void fsnotify_access(struct file *file)
165 if (S_ISDIR(inode->i_mode)) 165 if (S_ISDIR(inode->i_mode))
166 mask |= FS_IN_ISDIR; 166 mask |= FS_IN_ISDIR;
167 167
168 fsnotify_parent(path, NULL, mask); 168 if (!(file->f_mode & FMODE_NONOTIFY)) {
169 fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); 169 fsnotify_parent(path, NULL, mask);
170 fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
171 }
170} 172}
171 173
172/* 174/*
@@ -181,8 +183,10 @@ static inline void fsnotify_modify(struct file *file)
181 if (S_ISDIR(inode->i_mode)) 183 if (S_ISDIR(inode->i_mode))
182 mask |= FS_IN_ISDIR; 184 mask |= FS_IN_ISDIR;
183 185
184 fsnotify_parent(path, NULL, mask); 186 if (!(file->f_mode & FMODE_NONOTIFY)) {
185 fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); 187 fsnotify_parent(path, NULL, mask);
188 fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
189 }
186} 190}
187 191
188/* 192/*
@@ -197,8 +201,10 @@ static inline void fsnotify_open(struct file *file)
197 if (S_ISDIR(inode->i_mode)) 201 if (S_ISDIR(inode->i_mode))
198 mask |= FS_IN_ISDIR; 202 mask |= FS_IN_ISDIR;
199 203
200 fsnotify_parent(path, NULL, mask); 204 if (!(file->f_mode & FMODE_NONOTIFY)) {
201 fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); 205 fsnotify_parent(path, NULL, mask);
206 fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
207 }
202} 208}
203 209
204/* 210/*
@@ -214,8 +220,10 @@ static inline void fsnotify_close(struct file *file)
214 if (S_ISDIR(inode->i_mode)) 220 if (S_ISDIR(inode->i_mode))
215 mask |= FS_IN_ISDIR; 221 mask |= FS_IN_ISDIR;
216 222
217 fsnotify_parent(path, NULL, mask); 223 if (!(file->f_mode & FMODE_NONOTIFY)) {
218 fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); 224 fsnotify_parent(path, NULL, mask);
225 fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
226 }
219} 227}
220 228
221/* 229/*