aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2009-12-17 21:24:33 -0500
committerEric Paris <eparis@redhat.com>2010-07-28 09:59:00 -0400
commitb9e4e3bd0495fea9e8f8e712889c9cd8ffa43c94 (patch)
tree914a16f5098cf0ee3e01e6d47e6c7c9bf3613899
parentfanotify: ignored_mask to ignore events (diff)
downloadlinux-dev-b9e4e3bd0495fea9e8f8e712889c9cd8ffa43c94.tar.xz
linux-dev-b9e4e3bd0495fea9e8f8e712889c9cd8ffa43c94.zip
fanotify: allow users to set an ignored_mask
Change the sys_fanotify_mark() system call so users can set ignored_masks on inodes. Remember, if a user new sets a real mask, and only sets ignored masks, the ignore will never be pinned in memory. Thus ignored_masks can be lost under memory pressure and the user may again get events they previously thought were ignored. Signed-off-by: Eric Paris <eparis@redhat.com>
-rw-r--r--fs/notify/fanotify/fanotify_user.c54
-rw-r--r--include/linux/fanotify.h4
2 files changed, 39 insertions, 19 deletions
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 3320f0c57e31..ad02d475770f 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -296,13 +296,20 @@ out:
return ret;
}
-static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, __u32 mask)
+static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
+ __u32 mask,
+ unsigned int flags)
{
__u32 oldmask;
spin_lock(&fsn_mark->lock);
- oldmask = fsn_mark->mask;
- fsnotify_set_mark_mask_locked(fsn_mark, (oldmask & ~mask));
+ if (!(flags & FAN_MARK_IGNORED_MASK)) {
+ oldmask = fsn_mark->mask;
+ fsnotify_set_mark_mask_locked(fsn_mark, (oldmask & ~mask));
+ } else {
+ oldmask = fsn_mark->ignored_mask;
+ fsnotify_set_mark_ignored_mask_locked(fsn_mark, (oldmask & ~mask));
+ }
spin_unlock(&fsn_mark->lock);
if (!(oldmask & ~mask))
@@ -312,7 +319,8 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, __u3
}
static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,
- struct vfsmount *mnt, __u32 mask)
+ struct vfsmount *mnt, __u32 mask,
+ unsigned int flags)
{
struct fsnotify_mark *fsn_mark = NULL;
__u32 removed;
@@ -321,7 +329,7 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,
if (!fsn_mark)
return -ENOENT;
- removed = fanotify_mark_remove_from_mask(fsn_mark, mask);
+ removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags);
fsnotify_put_mark(fsn_mark);
if (removed & group->mask)
fsnotify_recalc_group_mask(group);
@@ -332,7 +340,8 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,
}
static int fanotify_remove_inode_mark(struct fsnotify_group *group,
- struct inode *inode, __u32 mask)
+ struct inode *inode, __u32 mask,
+ unsigned int flags)
{
struct fsnotify_mark *fsn_mark = NULL;
__u32 removed;
@@ -341,7 +350,7 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group,
if (!fsn_mark)
return -ENOENT;
- removed = fanotify_mark_remove_from_mask(fsn_mark, mask);
+ removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags);
/* matches the fsnotify_find_inode_mark() */
fsnotify_put_mark(fsn_mark);
@@ -353,20 +362,28 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group,
return 0;
}
-static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, __u32 mask)
+static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
+ __u32 mask,
+ unsigned int flags)
{
__u32 oldmask;
spin_lock(&fsn_mark->lock);
- oldmask = fsn_mark->mask;
- fsnotify_set_mark_mask_locked(fsn_mark, (oldmask | mask));
+ if (!(flags & FAN_MARK_IGNORED_MASK)) {
+ oldmask = fsn_mark->mask;
+ fsnotify_set_mark_mask_locked(fsn_mark, (oldmask | mask));
+ } else {
+ oldmask = fsn_mark->ignored_mask;
+ fsnotify_set_mark_ignored_mask_locked(fsn_mark, (oldmask | mask));
+ }
spin_unlock(&fsn_mark->lock);
return mask & ~oldmask;
}
static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
- struct vfsmount *mnt, __u32 mask)
+ struct vfsmount *mnt, __u32 mask,
+ unsigned int flags)
{
struct fsnotify_mark *fsn_mark;
__u32 added;
@@ -386,7 +403,7 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
return ret;
}
}
- added = fanotify_mark_add_to_mask(fsn_mark, mask);
+ added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
fsnotify_put_mark(fsn_mark);
if (added) {
if (added & ~group->mask)
@@ -398,7 +415,8 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
}
static int fanotify_add_inode_mark(struct fsnotify_group *group,
- struct inode *inode, __u32 mask)
+ struct inode *inode, __u32 mask,
+ unsigned int flags)
{
struct fsnotify_mark *fsn_mark;
__u32 added;
@@ -420,7 +438,7 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,
return ret;
}
}
- added = fanotify_mark_add_to_mask(fsn_mark, mask);
+ added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
fsnotify_put_mark(fsn_mark);
if (added) {
if (added & ~group->mask)
@@ -528,15 +546,15 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) {
case FAN_MARK_ADD:
if (flags & FAN_MARK_MOUNT)
- ret = fanotify_add_vfsmount_mark(group, mnt, mask);
+ ret = fanotify_add_vfsmount_mark(group, mnt, mask, flags);
else
- ret = fanotify_add_inode_mark(group, inode, mask);
+ ret = fanotify_add_inode_mark(group, inode, mask, flags);
break;
case FAN_MARK_REMOVE:
if (flags & FAN_MARK_MOUNT)
- ret = fanotify_remove_vfsmount_mark(group, mnt, mask);
+ ret = fanotify_remove_vfsmount_mark(group, mnt, mask, flags);
else
- ret = fanotify_remove_inode_mark(group, inode, mask);
+ ret = fanotify_remove_inode_mark(group, inode, mask, flags);
break;
default:
ret = -EINVAL;
diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h
index 90e59b24fd04..b8daa9f9b560 100644
--- a/include/linux/fanotify.h
+++ b/include/linux/fanotify.h
@@ -30,12 +30,14 @@
#define FAN_MARK_DONT_FOLLOW 0x00000004
#define FAN_MARK_ONLYDIR 0x00000008
#define FAN_MARK_MOUNT 0x00000010
+#define FAN_MARK_IGNORED_MASK 0x00000020
#define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\
FAN_MARK_REMOVE |\
FAN_MARK_DONT_FOLLOW |\
FAN_MARK_ONLYDIR |\
- FAN_MARK_MOUNT)
+ FAN_MARK_MOUNT |\
+ FAN_MARK_IGNORED_MASK)
/*
* All of the events - we build the list by hand so that we can add flags in