aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/fanotify/fanotify.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/notify/fanotify/fanotify.c')
-rw-r--r--fs/notify/fanotify/fanotify.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 95a330d2f8a1..4feed8601e29 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -27,6 +27,7 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new)
27 return false; 27 return false;
28} 28}
29 29
30/* Note, if we return an event in *arg that a reference is being held... */
30static int fanotify_merge(struct list_head *list, 31static int fanotify_merge(struct list_head *list,
31 struct fsnotify_event *event, 32 struct fsnotify_event *event,
32 void **arg) 33 void **arg)
@@ -34,17 +35,22 @@ static int fanotify_merge(struct list_head *list,
34 struct fsnotify_event_holder *test_holder; 35 struct fsnotify_event_holder *test_holder;
35 struct fsnotify_event *test_event; 36 struct fsnotify_event *test_event;
36 struct fsnotify_event *new_event; 37 struct fsnotify_event *new_event;
38 struct fsnotify_event **return_event = (struct fsnotify_event **)arg;
37 int ret = 0; 39 int ret = 0;
38 40
39 pr_debug("%s: list=%p event=%p\n", __func__, list, event); 41 pr_debug("%s: list=%p event=%p\n", __func__, list, event);
40 42
43 *return_event = NULL;
44
41 /* and the list better be locked by something too! */ 45 /* and the list better be locked by something too! */
42 46
43 list_for_each_entry_reverse(test_holder, list, event_list) { 47 list_for_each_entry_reverse(test_holder, list, event_list) {
44 test_event = test_holder->event; 48 test_event = test_holder->event;
45 if (should_merge(test_event, event)) { 49 if (should_merge(test_event, event)) {
46 ret = -EEXIST; 50 fsnotify_get_event(test_event);
51 *return_event = test_event;
47 52
53 ret = -EEXIST;
48 /* if they are exactly the same we are done */ 54 /* if they are exactly the same we are done */
49 if (test_event->mask == event->mask) 55 if (test_event->mask == event->mask)
50 goto out; 56 goto out;
@@ -66,11 +72,14 @@ static int fanotify_merge(struct list_head *list,
66 goto out; 72 goto out;
67 } 73 }
68 74
75 /* we didn't return the test_event, so drop that ref */
76 fsnotify_put_event(test_event);
77 /* the reference we return on new_event is from clone */
78 *return_event = new_event;
79
69 /* build new event and replace it on the list */ 80 /* build new event and replace it on the list */
70 new_event->mask = (test_event->mask | event->mask); 81 new_event->mask = (test_event->mask | event->mask);
71 fsnotify_replace_event(test_holder, new_event); 82 fsnotify_replace_event(test_holder, new_event);
72 /* match ref from fsnotify_clone_event() */
73 fsnotify_put_event(new_event);
74 83
75 break; 84 break;
76 } 85 }
@@ -82,7 +91,7 @@ out:
82static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event) 91static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
83{ 92{
84 int ret; 93 int ret;
85 94 struct fsnotify_event *used_event;
86 95
87 BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS); 96 BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS);
88 BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY); 97 BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY);
@@ -94,10 +103,12 @@ static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_e
94 103
95 pr_debug("%s: group=%p event=%p\n", __func__, group, event); 104 pr_debug("%s: group=%p event=%p\n", __func__, group, event);
96 105
97 ret = fsnotify_add_notify_event(group, event, NULL, fanotify_merge, NULL); 106 ret = fsnotify_add_notify_event(group, event, NULL, fanotify_merge, (void **)&used_event);
98 /* -EEXIST means this event was merged with another, not that it was an error */ 107 /* -EEXIST means this event was merged with another, not that it was an error */
99 if (ret == -EEXIST) 108 if (ret == -EEXIST)
100 ret = 0; 109 ret = 0;
110 if (used_event)
111 fsnotify_put_event(used_event);
101 return ret; 112 return ret;
102} 113}
103 114