diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-30 11:50:37 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-30 11:50:37 -0700 |
commit | 1792f17b7210280a3d7ff29da9614ba779cfcedb (patch) | |
tree | e45797137b7fc4877dd60b289d6fb75c6bdcdcf0 /include/linux | |
parent | f02a38d86a14b6e544e218d806ffb0442785f62b (diff) | |
parent | 6bff7eccb0d9bdef4123aad5399e73cbc26683a6 (diff) |
Merge branch 'for-linus' of git://git.infradead.org/users/eparis/notify
* 'for-linus' of git://git.infradead.org/users/eparis/notify: (22 commits)
Ensure FMODE_NONOTIFY is not set by userspace
make fanotify_read() restartable across signals
fsnotify: remove alignment padding from fsnotify_mark on 64 bit builds
fs/notify/fanotify/fanotify_user.c: fix warnings
fanotify: Fix FAN_CLOSE comments
fanotify: do not recalculate the mask if the ignored mask changed
fanotify: ignore events on directories unless specifically requested
fsnotify: rename FS_IN_ISDIR to FS_ISDIR
fanotify: do not send events for irregular files
fanotify: limit number of listeners per user
fanotify: allow userspace to override max marks
fanotify: limit the number of marks in a single fanotify group
fanotify: allow userspace to override max queue depth
fsnotify: implement a default maximum queue depth
fanotify: ignore fanotify ignore marks if open writers
fanotify: allow userspace to flush all marks
fsnotify: call fsnotify_parent in perm events
fsnotify: correctly handle return codes from listeners
fanotify: use __aligned_u64 in fanotify userspace metadata
fanotify: implement fanotify listener ordering
...
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/Kbuild | 1 | ||||
-rw-r--r-- | include/linux/fanotify.h | 36 | ||||
-rw-r--r-- | include/linux/fsnotify.h | 38 | ||||
-rw-r--r-- | include/linux/fsnotify_backend.h | 26 | ||||
-rw-r--r-- | include/linux/sched.h | 3 |
5 files changed, 73 insertions, 31 deletions
diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 90e3ed3a314..97319a8fc1e 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -118,6 +118,7 @@ header-y += eventpoll.h header-y += ext2_fs.h header-y += fadvise.h header-y += falloc.h +header-y += fanotify.h header-y += fb.h header-y += fcntl.h header-y += fd.h diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h index 63531a6b4d2..0f0121467fc 100644 --- a/include/linux/fanotify.h +++ b/include/linux/fanotify.h @@ -6,18 +6,19 @@ /* the following events that user-space can register for */ #define FAN_ACCESS 0x00000001 /* File was accessed */ #define FAN_MODIFY 0x00000002 /* File was modified */ -#define FAN_CLOSE_WRITE 0x00000008 /* Unwrittable file closed */ -#define FAN_CLOSE_NOWRITE 0x00000010 /* Writtable file closed */ +#define FAN_CLOSE_WRITE 0x00000008 /* Writtable file closed */ +#define FAN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */ #define FAN_OPEN 0x00000020 /* File was opened */ -#define FAN_EVENT_ON_CHILD 0x08000000 /* interested in child events */ - -/* FIXME currently Q's have no limit.... */ #define FAN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ #define FAN_OPEN_PERM 0x00010000 /* File open in perm check */ #define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */ +#define FAN_ONDIR 0x40000000 /* event occurred against dir */ + +#define FAN_EVENT_ON_CHILD 0x08000000 /* interested in child events */ + /* helper events */ #define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */ @@ -25,7 +26,19 @@ #define FAN_CLOEXEC 0x00000001 #define FAN_NONBLOCK 0x00000002 -#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK) +/* These are NOT bitwise flags. Both bits are used togther. */ +#define FAN_CLASS_NOTIF 0x00000000 +#define FAN_CLASS_CONTENT 0x00000004 +#define FAN_CLASS_PRE_CONTENT 0x00000008 +#define FAN_ALL_CLASS_BITS (FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | \ + FAN_CLASS_PRE_CONTENT) + +#define FAN_UNLIMITED_QUEUE 0x00000010 +#define FAN_UNLIMITED_MARKS 0x00000020 + +#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \ + FAN_ALL_CLASS_BITS | FAN_UNLIMITED_QUEUE |\ + FAN_UNLIMITED_MARKS) /* flags used for fanotify_modify_mark() */ #define FAN_MARK_ADD 0x00000001 @@ -36,6 +49,10 @@ #define FAN_MARK_IGNORED_MASK 0x00000020 #define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040 #define FAN_MARK_FLUSH 0x00000080 +#ifdef __KERNEL__ +/* not valid from userspace, only kernel internal */ +#define FAN_MARK_ONDIR 0x00000100 +#endif #define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\ FAN_MARK_REMOVE |\ @@ -43,7 +60,8 @@ FAN_MARK_ONLYDIR |\ FAN_MARK_MOUNT |\ FAN_MARK_IGNORED_MASK |\ - FAN_MARK_IGNORED_SURV_MODIFY) + FAN_MARK_IGNORED_SURV_MODIFY |\ + FAN_MARK_FLUSH) /* * All of the events - we build the list by hand so that we can add flags in @@ -70,10 +88,10 @@ struct fanotify_event_metadata { __u32 event_len; __u32 vers; - __u64 mask; + __aligned_u64 mask; __s32 fd; __s32 pid; -} __attribute__ ((packed)); +}; struct fanotify_response { __s32 fd; diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 59d0df43ff9..5c185fa2708 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -26,12 +26,12 @@ static inline void fsnotify_d_instantiate(struct dentry *dentry, } /* Notify this dentry's parent about a child's events. */ -static inline void fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask) +static inline int fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask) { if (!dentry) dentry = path->dentry; - __fsnotify_parent(path, dentry, mask); + return __fsnotify_parent(path, dentry, mask); } /* simple call site for access decisions */ @@ -40,6 +40,7 @@ static inline int fsnotify_perm(struct file *file, int mask) struct path *path = &file->f_path; struct inode *inode = path->dentry->d_inode; __u32 fsnotify_mask = 0; + int ret; if (file->f_mode & FMODE_NONOTIFY) return 0; @@ -52,6 +53,10 @@ static inline int fsnotify_perm(struct file *file, int mask) else BUG(); + ret = fsnotify_parent(path, NULL, fsnotify_mask); + if (ret) + return ret; + return fsnotify(inode, fsnotify_mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); } @@ -93,8 +98,8 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, old_dir_mask |= FS_DN_RENAME; if (isdir) { - old_dir_mask |= FS_IN_ISDIR; - new_dir_mask |= FS_IN_ISDIR; + old_dir_mask |= FS_ISDIR; + new_dir_mask |= FS_ISDIR; } fsnotify(old_dir, old_dir_mask, old_dir, FSNOTIFY_EVENT_INODE, old_name, fs_cookie); @@ -132,7 +137,7 @@ static inline void fsnotify_nameremove(struct dentry *dentry, int isdir) __u32 mask = FS_DELETE; if (isdir) - mask |= FS_IN_ISDIR; + mask |= FS_ISDIR; fsnotify_parent(NULL, dentry, mask); } @@ -174,7 +179,7 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct */ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) { - __u32 mask = (FS_CREATE | FS_IN_ISDIR); + __u32 mask = (FS_CREATE | FS_ISDIR); struct inode *d_inode = dentry->d_inode; audit_inode_child(dentry, inode); @@ -192,7 +197,7 @@ static inline void fsnotify_access(struct file *file) __u32 mask = FS_ACCESS; if (S_ISDIR(inode->i_mode)) - mask |= FS_IN_ISDIR; + mask |= FS_ISDIR; if (!(file->f_mode & FMODE_NONOTIFY)) { fsnotify_parent(path, NULL, mask); @@ -210,7 +215,7 @@ static inline void fsnotify_modify(struct file *file) __u32 mask = FS_MODIFY; if (S_ISDIR(inode->i_mode)) - mask |= FS_IN_ISDIR; + mask |= FS_ISDIR; if (!(file->f_mode & FMODE_NONOTIFY)) { fsnotify_parent(path, NULL, mask); @@ -228,12 +233,13 @@ static inline void fsnotify_open(struct file *file) __u32 mask = FS_OPEN; if (S_ISDIR(inode->i_mode)) - mask |= FS_IN_ISDIR; + mask |= FS_ISDIR; - if (!(file->f_mode & FMODE_NONOTIFY)) { - fsnotify_parent(path, NULL, mask); - fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); - } + /* FMODE_NONOTIFY must never be set from user */ + file->f_mode &= ~FMODE_NONOTIFY; + + fsnotify_parent(path, NULL, mask); + fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); } /* @@ -247,7 +253,7 @@ static inline void fsnotify_close(struct file *file) __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE; if (S_ISDIR(inode->i_mode)) - mask |= FS_IN_ISDIR; + mask |= FS_ISDIR; if (!(file->f_mode & FMODE_NONOTIFY)) { fsnotify_parent(path, NULL, mask); @@ -264,7 +270,7 @@ static inline void fsnotify_xattr(struct dentry *dentry) __u32 mask = FS_ATTRIB; if (S_ISDIR(inode->i_mode)) - mask |= FS_IN_ISDIR; + mask |= FS_ISDIR; fsnotify_parent(NULL, dentry, mask); fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0); @@ -299,7 +305,7 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid) if (mask) { if (S_ISDIR(inode->i_mode)) - mask |= FS_IN_ISDIR; + mask |= FS_ISDIR; fsnotify_parent(NULL, dentry, mask); fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0); diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index e40190d1687..0a68f924f06 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -45,7 +45,7 @@ #define FS_ACCESS_PERM 0x00020000 /* access event in a permissions hook */ #define FS_EXCL_UNLINK 0x04000000 /* do not send events if object is unlinked */ -#define FS_IN_ISDIR 0x40000000 /* event occurred against dir */ +#define FS_ISDIR 0x40000000 /* event occurred against dir */ #define FS_IN_ONESHOT 0x80000000 /* only send event once */ #define FS_DN_RENAME 0x10000000 /* file renamed */ @@ -64,13 +64,15 @@ #define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO) +#define ALL_FSNOTIFY_PERM_EVENTS (FS_OPEN_PERM | FS_ACCESS_PERM) + #define ALL_FSNOTIFY_EVENTS (FS_ACCESS | FS_MODIFY | FS_ATTRIB | \ FS_CLOSE_WRITE | FS_CLOSE_NOWRITE | FS_OPEN | \ FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE | \ FS_DELETE | FS_DELETE_SELF | FS_MOVE_SELF | \ FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \ FS_OPEN_PERM | FS_ACCESS_PERM | FS_EXCL_UNLINK | \ - FS_IN_ISDIR | FS_IN_ONESHOT | FS_DN_RENAME | \ + FS_ISDIR | FS_IN_ONESHOT | FS_DN_RENAME | \ FS_DN_MULTISHOT | FS_EVENT_ON_CHILD) struct fsnotify_group; @@ -129,6 +131,14 @@ struct fsnotify_group { wait_queue_head_t notification_waitq; /* read() on the notification file blocks on this waitq */ unsigned int q_len; /* events on the queue */ unsigned int max_events; /* maximum events allowed on the list */ + /* + * Valid fsnotify group priorities. Events are send in order from highest + * priority to lowest priority. We default to the lowest priority. + */ + #define FS_PRIO_0 0 /* normal notifiers, no permissions */ + #define FS_PRIO_1 1 /* fanotify content based access control */ + #define FS_PRIO_2 2 /* fanotify pre-content access */ + unsigned int priority; /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */ spinlock_t mark_lock; /* protect marks_list */ @@ -159,6 +169,8 @@ struct fsnotify_group { bool bypass_perm; /* protected by access_mutex */ #endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */ int f_flags; + unsigned int max_marks; + struct user_struct *user; } fanotify_data; #endif /* CONFIG_FANOTIFY */ }; @@ -275,8 +287,8 @@ struct fsnotify_mark { struct fsnotify_inode_mark i; struct fsnotify_vfsmount_mark m; }; - __u32 ignored_mask; /* events types to ignore */ struct list_head free_g_list; /* tmp list used when freeing this mark */ + __u32 ignored_mask; /* events types to ignore */ #define FSNOTIFY_MARK_FLAG_INODE 0x01 #define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02 #define FSNOTIFY_MARK_FLAG_OBJECT_PINNED 0x04 @@ -294,7 +306,7 @@ struct fsnotify_mark { /* main fsnotify call to send events */ extern int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const unsigned char *name, u32 cookie); -extern void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask); +extern int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask); extern void __fsnotify_inode_delete(struct inode *inode); extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); extern u32 fsnotify_get_cookie(void); @@ -423,8 +435,10 @@ static inline int fsnotify(struct inode *to_tell, __u32 mask, void *data, int da return 0; } -static inline void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask) -{} +static inline int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask) +{ + return 0; +} static inline void __fsnotify_inode_delete(struct inode *inode) {} diff --git a/include/linux/sched.h b/include/linux/sched.h index f53cdf216ce..d0036e52a24 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -672,6 +672,9 @@ struct user_struct { atomic_t inotify_watches; /* How many inotify watches does this user have? */ atomic_t inotify_devs; /* How many inotify devs does this user have opened? */ #endif +#ifdef CONFIG_FANOTIFY + atomic_t fanotify_listeners; +#endif #ifdef CONFIG_EPOLL atomic_t epoll_watches; /* The number of file descriptors currently watched */ #endif |