fanotify: clear all fanotify marks
authorEric Paris <eparis@redhat.com>
Fri, 18 Dec 2009 02:24:34 +0000 (21:24 -0500)
committerEric Paris <eparis@redhat.com>
Wed, 28 Jul 2010 13:59:00 +0000 (09:59 -0400)
fanotify listeners may want to clear all marks.  They may want to do this
to destroy all of their inode marks which have nothing but ignores.
Realistically this is useful for av vendors who update policy and want to
clear all of their cached allows.

Signed-off-by: Eric Paris <eparis@redhat.com>
fs/notify/fanotify/fanotify_user.c
fs/notify/inode_mark.c
fs/notify/mark.c
fs/notify/vfsmount_mark.c
include/linux/fanotify.h
include/linux/fsnotify_backend.h

index 3e275f17e7b7573b2e01cff35f429cb551ccde50..9fe760baf69fcd35c9bd1e2cbc70d5045fad8815 100644 (file)
@@ -514,9 +514,10 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
 
        if (flags & ~FAN_ALL_MARK_FLAGS)
                return -EINVAL;
-       switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) {
+       switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
        case FAN_MARK_ADD:
        case FAN_MARK_REMOVE:
+       case FAN_MARK_FLUSH:
                break;
        default:
                return -EINVAL;
@@ -545,7 +546,7 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
        group = filp->private_data;
 
        /* create/update an inode mark */
-       switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) {
+       switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
        case FAN_MARK_ADD:
                if (flags & FAN_MARK_MOUNT)
                        ret = fanotify_add_vfsmount_mark(group, mnt, mask, flags);
@@ -558,6 +559,13 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
                else
                        ret = fanotify_remove_inode_mark(group, inode, mask, flags);
                break;
+       case FAN_MARK_FLUSH:
+               if (flags & FAN_MARK_MOUNT)
+                       fsnotify_clear_vfsmount_marks_by_group(group);
+               else
+                       fsnotify_clear_inode_marks_by_group(group);
+               fsnotify_recalc_group_mask(group);
+               break;
        default:
                ret = -EINVAL;
        }
index 4292f9e23ae85e99376ba32325a787d0a8b84bdd..0c0a48b1659ff52567c858aecf8e457d518ff41a 100644 (file)
@@ -103,6 +103,14 @@ void fsnotify_clear_marks_by_inode(struct inode *inode)
        }
 }
 
+/*
+ * Given a group clear all of the inode marks associated with that group.
+ */
+void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group)
+{
+       fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_MARK_FLAG_INODE);
+}
+
 /*
  * given a group and inode, find the mark associated with that combination.
  * if found take a reference to that mark and return it, else return NULL
index cb1d822f227fe53f9df1fb9ac3ac3e7dd093cb9b..1e824e64441d101d71916c52a26c6f355aacf4ca 100644 (file)
@@ -270,18 +270,21 @@ err:
 }
 
 /*
- * Given a group, destroy all of the marks associated with that group.
+ * clear any marks in a group in which mark->flags & flags is true
  */
-void fsnotify_clear_marks_by_group(struct fsnotify_group *group)
+void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group,
+                                        unsigned int flags)
 {
        struct fsnotify_mark *lmark, *mark;
        LIST_HEAD(free_list);
 
        spin_lock(&group->mark_lock);
        list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
-               list_add(&mark->free_g_list, &free_list);
-               list_del_init(&mark->g_list);
-               fsnotify_get_mark(mark);
+               if (mark->flags & flags) {
+                       list_add(&mark->free_g_list, &free_list);
+                       list_del_init(&mark->g_list);
+                       fsnotify_get_mark(mark);
+               }
        }
        spin_unlock(&group->mark_lock);
 
@@ -291,6 +294,14 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group)
        }
 }
 
+/*
+ * Given a group, destroy all of the marks associated with that group.
+ */
+void fsnotify_clear_marks_by_group(struct fsnotify_group *group)
+{
+       fsnotify_clear_marks_by_group_flags(group, (unsigned int)-1);
+}
+
 void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old)
 {
        assert_spin_locked(&old->lock);
index 1b61d0a942de56b0ce1d98de9e821589385219f0..8f1aa02f4f02a8968ac800ec4cb2a4bef9dc50ad 100644 (file)
@@ -51,6 +51,11 @@ void fsnotify_clear_marks_by_mount(struct vfsmount *mnt)
        }
 }
 
+void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group)
+{
+       fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_MARK_FLAG_VFSMOUNT);
+}
+
 /*
  * Recalculate the mask of events relevant to a given vfsmount locked.
  */
index e43934d0b74c26d880f3bd2929cadb0641d827f8..385896c9f8289ec4f5dc38f72f9d26bb7ac1e718 100644 (file)
@@ -32,6 +32,7 @@
 #define FAN_MARK_MOUNT         0x00000010
 #define FAN_MARK_IGNORED_MASK  0x00000020
 #define FAN_MARK_IGNORED_SURV_MODIFY   0x00000040
+#define FAN_MARK_FLUSH         0x00000080
 
 #define FAN_ALL_MARK_FLAGS     (FAN_MARK_ADD |\
                                 FAN_MARK_REMOVE |\
index 8ca19df8a1713197bf5c4c22d598c373d994a273..be4a36ed2008331fc6d4a20b0e55789c7f5c5b5d 100644 (file)
@@ -384,6 +384,12 @@ extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *
                             struct inode *inode, struct vfsmount *mnt, int allow_dups);
 /* given a mark, flag it to be freed when all references are dropped */
 extern void fsnotify_destroy_mark(struct fsnotify_mark *mark);
+/* run all the marks in a group, and clear all of the vfsmount marks */
+extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group);
+/* run all the marks in a group, and clear all of the inode marks */
+extern void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group);
+/* run all the marks in a group, and clear all of the marks where mark->flags & flags is true*/
+extern void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, unsigned int flags);
 /* run all the marks in a group, and flag them to be freed */
 extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group);
 extern void fsnotify_get_mark(struct fsnotify_mark *mark);