aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/notify/fanotify/fanotify_user.c12
-rw-r--r--fs/notify/inode_mark.c8
-rw-r--r--fs/notify/mark.c21
-rw-r--r--fs/notify/vfsmount_mark.c5
-rw-r--r--include/linux/fanotify.h1
-rw-r--r--include/linux/fsnotify_backend.h6
6 files changed, 46 insertions, 7 deletions
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 3e275f17e7b7..9fe760baf69f 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -514,9 +514,10 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
514 514
515 if (flags & ~FAN_ALL_MARK_FLAGS) 515 if (flags & ~FAN_ALL_MARK_FLAGS)
516 return -EINVAL; 516 return -EINVAL;
517 switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) { 517 switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
518 case FAN_MARK_ADD: 518 case FAN_MARK_ADD:
519 case FAN_MARK_REMOVE: 519 case FAN_MARK_REMOVE:
520 case FAN_MARK_FLUSH:
520 break; 521 break;
521 default: 522 default:
522 return -EINVAL; 523 return -EINVAL;
@@ -545,7 +546,7 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
545 group = filp->private_data; 546 group = filp->private_data;
546 547
547 /* create/update an inode mark */ 548 /* create/update an inode mark */
548 switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) { 549 switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
549 case FAN_MARK_ADD: 550 case FAN_MARK_ADD:
550 if (flags & FAN_MARK_MOUNT) 551 if (flags & FAN_MARK_MOUNT)
551 ret = fanotify_add_vfsmount_mark(group, mnt, mask, flags); 552 ret = fanotify_add_vfsmount_mark(group, mnt, mask, flags);
@@ -558,6 +559,13 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
558 else 559 else
559 ret = fanotify_remove_inode_mark(group, inode, mask, flags); 560 ret = fanotify_remove_inode_mark(group, inode, mask, flags);
560 break; 561 break;
562 case FAN_MARK_FLUSH:
563 if (flags & FAN_MARK_MOUNT)
564 fsnotify_clear_vfsmount_marks_by_group(group);
565 else
566 fsnotify_clear_inode_marks_by_group(group);
567 fsnotify_recalc_group_mask(group);
568 break;
561 default: 569 default:
562 ret = -EINVAL; 570 ret = -EINVAL;
563 } 571 }
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c
index 4292f9e23ae8..0c0a48b1659f 100644
--- a/fs/notify/inode_mark.c
+++ b/fs/notify/inode_mark.c
@@ -104,6 +104,14 @@ void fsnotify_clear_marks_by_inode(struct inode *inode)
104} 104}
105 105
106/* 106/*
107 * Given a group clear all of the inode marks associated with that group.
108 */
109void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group)
110{
111 fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_MARK_FLAG_INODE);
112}
113
114/*
107 * given a group and inode, find the mark associated with that combination. 115 * given a group and inode, find the mark associated with that combination.
108 * if found take a reference to that mark and return it, else return NULL 116 * if found take a reference to that mark and return it, else return NULL
109 */ 117 */
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index cb1d822f227f..1e824e64441d 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -270,18 +270,21 @@ err:
270} 270}
271 271
272/* 272/*
273 * Given a group, destroy all of the marks associated with that group. 273 * clear any marks in a group in which mark->flags & flags is true
274 */ 274 */
275void fsnotify_clear_marks_by_group(struct fsnotify_group *group) 275void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group,
276 unsigned int flags)
276{ 277{
277 struct fsnotify_mark *lmark, *mark; 278 struct fsnotify_mark *lmark, *mark;
278 LIST_HEAD(free_list); 279 LIST_HEAD(free_list);
279 280
280 spin_lock(&group->mark_lock); 281 spin_lock(&group->mark_lock);
281 list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { 282 list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
282 list_add(&mark->free_g_list, &free_list); 283 if (mark->flags & flags) {
283 list_del_init(&mark->g_list); 284 list_add(&mark->free_g_list, &free_list);
284 fsnotify_get_mark(mark); 285 list_del_init(&mark->g_list);
286 fsnotify_get_mark(mark);
287 }
285 } 288 }
286 spin_unlock(&group->mark_lock); 289 spin_unlock(&group->mark_lock);
287 290
@@ -291,6 +294,14 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group)
291 } 294 }
292} 295}
293 296
297/*
298 * Given a group, destroy all of the marks associated with that group.
299 */
300void fsnotify_clear_marks_by_group(struct fsnotify_group *group)
301{
302 fsnotify_clear_marks_by_group_flags(group, (unsigned int)-1);
303}
304
294void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old) 305void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old)
295{ 306{
296 assert_spin_locked(&old->lock); 307 assert_spin_locked(&old->lock);
diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c
index 1b61d0a942de..8f1aa02f4f02 100644
--- a/fs/notify/vfsmount_mark.c
+++ b/fs/notify/vfsmount_mark.c
@@ -51,6 +51,11 @@ void fsnotify_clear_marks_by_mount(struct vfsmount *mnt)
51 } 51 }
52} 52}
53 53
54void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group)
55{
56 fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_MARK_FLAG_VFSMOUNT);
57}
58
54/* 59/*
55 * Recalculate the mask of events relevant to a given vfsmount locked. 60 * Recalculate the mask of events relevant to a given vfsmount locked.
56 */ 61 */
diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h
index e43934d0b74c..385896c9f828 100644
--- a/include/linux/fanotify.h
+++ b/include/linux/fanotify.h
@@ -32,6 +32,7 @@
32#define FAN_MARK_MOUNT 0x00000010 32#define FAN_MARK_MOUNT 0x00000010
33#define FAN_MARK_IGNORED_MASK 0x00000020 33#define FAN_MARK_IGNORED_MASK 0x00000020
34#define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040 34#define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040
35#define FAN_MARK_FLUSH 0x00000080
35 36
36#define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\ 37#define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\
37 FAN_MARK_REMOVE |\ 38 FAN_MARK_REMOVE |\
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 8ca19df8a171..be4a36ed2008 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -384,6 +384,12 @@ extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *
384 struct inode *inode, struct vfsmount *mnt, int allow_dups); 384 struct inode *inode, struct vfsmount *mnt, int allow_dups);
385/* given a mark, flag it to be freed when all references are dropped */ 385/* given a mark, flag it to be freed when all references are dropped */
386extern void fsnotify_destroy_mark(struct fsnotify_mark *mark); 386extern void fsnotify_destroy_mark(struct fsnotify_mark *mark);
387/* run all the marks in a group, and clear all of the vfsmount marks */
388extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group);
389/* run all the marks in a group, and clear all of the inode marks */
390extern void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group);
391/* run all the marks in a group, and clear all of the marks where mark->flags & flags is true*/
392extern void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, unsigned int flags);
387/* run all the marks in a group, and flag them to be freed */ 393/* run all the marks in a group, and flag them to be freed */
388extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group); 394extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group);
389extern void fsnotify_get_mark(struct fsnotify_mark *mark); 395extern void fsnotify_get_mark(struct fsnotify_mark *mark);