aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2010-07-28 10:18:37 -0400
committerEric Paris <eparis@redhat.com>2010-07-28 10:18:50 -0400
commitf70ab54cc6c3907b0727ba332b3976f80f3846d0 (patch)
tree2a22097325a668a0d08d4ea3354d0e6c95fddd86
parent5ba08e2eeb06355f66ed62ae97bb87d145973a9a (diff)
fsnotify: fsnotify_add_notify_event should return an event
Rather than the horrific void ** argument and such just to pass the fanotify_merge event back to the caller of fsnotify_add_notify_event() have those things return an event if it was different than the event suggusted to be added. Signed-off-by: Eric Paris <eparis@redhat.com>
-rw-r--r--fs/notify/fanotify/fanotify.c103
-rw-r--r--fs/notify/inotify/inotify_fsnotify.c28
-rw-r--r--fs/notify/inotify/inotify_user.c11
-rw-r--r--fs/notify/notification.c42
-rw-r--r--include/linux/fsnotify_backend.h12
5 files changed, 101 insertions, 95 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index bbcfccd4a8ea..f3c40c0e2b86 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -30,65 +30,58 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new)
30 return false; 30 return false;
31} 31}
32 32
33/* Note, if we return an event in *arg that a reference is being held... */ 33/* and the list better be locked by something too! */
34static int fanotify_merge(struct list_head *list, 34static struct fsnotify_event *fanotify_merge(struct list_head *list,
35 struct fsnotify_event *event, 35 struct fsnotify_event *event)
36 void **arg)
37{ 36{
38 struct fsnotify_event_holder *test_holder; 37 struct fsnotify_event_holder *test_holder;
39 struct fsnotify_event *test_event; 38 struct fsnotify_event *test_event = NULL;
40 struct fsnotify_event *new_event; 39 struct fsnotify_event *new_event;
41 struct fsnotify_event **return_event = (struct fsnotify_event **)arg;
42 int ret = 0;
43 40
44 pr_debug("%s: list=%p event=%p\n", __func__, list, event); 41 pr_debug("%s: list=%p event=%p\n", __func__, list, event);
45 42
46 *return_event = NULL;
47
48 /* and the list better be locked by something too! */
49 43
50 list_for_each_entry_reverse(test_holder, list, event_list) { 44 list_for_each_entry_reverse(test_holder, list, event_list) {
51 test_event = test_holder->event; 45 if (should_merge(test_holder->event, event)) {
52 if (should_merge(test_event, event)) { 46 test_event = test_holder->event;
53 fsnotify_get_event(test_event);
54 *return_event = test_event;
55
56 ret = -EEXIST;
57 /* if they are exactly the same we are done */
58 if (test_event->mask == event->mask)
59 goto out;
60
61 /*
62 * if the refcnt == 1 this is the only queue
63 * for this event and so we can update the mask
64 * in place.
65 */
66 if (atomic_read(&test_event->refcnt) == 1) {
67 test_event->mask |= event->mask;
68 goto out;
69 }
70
71 /* can't allocate memory, merge was no possible */
72 new_event = fsnotify_clone_event(test_event);
73 if (unlikely(!new_event)) {
74 ret = 0;
75 goto out;
76 }
77
78 /* we didn't return the test_event, so drop that ref */
79 fsnotify_put_event(test_event);
80 /* the reference we return on new_event is from clone */
81 *return_event = new_event;
82
83 /* build new event and replace it on the list */
84 new_event->mask = (test_event->mask | event->mask);
85 fsnotify_replace_event(test_holder, new_event);
86
87 break; 47 break;
88 } 48 }
89 } 49 }
90out: 50
91 return ret; 51 if (!test_event)
52 return NULL;
53
54 fsnotify_get_event(test_event);
55
56 /* if they are exactly the same we are done */
57 if (test_event->mask == event->mask)
58 return test_event;
59
60 /*
61 * if the refcnt == 2 this is the only queue
62 * for this event and so we can update the mask
63 * in place.
64 */
65 if (atomic_read(&test_event->refcnt) == 2) {
66 test_event->mask |= event->mask;
67 return test_event;
68 }
69
70 new_event = fsnotify_clone_event(test_event);
71
72 /* done with test_event */
73 fsnotify_put_event(test_event);
74
75 /* couldn't allocate memory, merge was not possible */
76 if (unlikely(!new_event))
77 return ERR_PTR(-ENOMEM);
78
79 /* build new event and replace it on the list */
80 new_event->mask = (test_event->mask | event->mask);
81 fsnotify_replace_event(test_holder, new_event);
82
83 /* we hold a reference on new_event from clone_event */
84 return new_event;
92} 85}
93 86
94#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 87#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
@@ -123,7 +116,7 @@ static int fanotify_get_response_from_access(struct fsnotify_group *group,
123 116
124static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event) 117static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
125{ 118{
126 int ret; 119 int ret = 0;
127 struct fsnotify_event *notify_event = NULL; 120 struct fsnotify_event *notify_event = NULL;
128 121
129 BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS); 122 BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS);
@@ -138,13 +131,9 @@ static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_e
138 131
139 pr_debug("%s: group=%p event=%p\n", __func__, group, event); 132 pr_debug("%s: group=%p event=%p\n", __func__, group, event);
140 133
141 ret = fsnotify_add_notify_event(group, event, NULL, fanotify_merge, 134 notify_event = fsnotify_add_notify_event(group, event, NULL, fanotify_merge);
142 (void **)&notify_event); 135 if (IS_ERR(notify_event))
143 /* -EEXIST means this event was merged with another, not that it was an error */ 136 return PTR_ERR(notify_event);
144 if (ret == -EEXIST)
145 ret = 0;
146 if (ret)
147 goto out;
148 137
149#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 138#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
150 if (event->mask & FAN_ALL_PERM_EVENTS) { 139 if (event->mask & FAN_ALL_PERM_EVENTS) {
@@ -155,9 +144,9 @@ static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_e
155 } 144 }
156#endif 145#endif
157 146
158out:
159 if (notify_event) 147 if (notify_event)
160 fsnotify_put_event(notify_event); 148 fsnotify_put_event(notify_event);
149
161 return ret; 150 return ret;
162} 151}
163 152
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index 906b72761b17..73a1106b3542 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -68,13 +68,11 @@ static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new
68 return false; 68 return false;
69} 69}
70 70
71static int inotify_merge(struct list_head *list, 71static struct fsnotify_event *inotify_merge(struct list_head *list,
72 struct fsnotify_event *event, 72 struct fsnotify_event *event)
73 void **arg)
74{ 73{
75 struct fsnotify_event_holder *last_holder; 74 struct fsnotify_event_holder *last_holder;
76 struct fsnotify_event *last_event; 75 struct fsnotify_event *last_event;
77 int ret = 0;
78 76
79 /* and the list better be locked by something too */ 77 /* and the list better be locked by something too */
80 spin_lock(&event->lock); 78 spin_lock(&event->lock);
@@ -82,11 +80,13 @@ static int inotify_merge(struct list_head *list,
82 last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list); 80 last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list);
83 last_event = last_holder->event; 81 last_event = last_holder->event;
84 if (event_compare(last_event, event)) 82 if (event_compare(last_event, event))
85 ret = -EEXIST; 83 fsnotify_get_event(last_event);
84 else
85 last_event = NULL;
86 86
87 spin_unlock(&event->lock); 87 spin_unlock(&event->lock);
88 88
89 return ret; 89 return last_event;
90} 90}
91 91
92static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event) 92static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
@@ -96,7 +96,8 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev
96 struct inode *to_tell; 96 struct inode *to_tell;
97 struct inotify_event_private_data *event_priv; 97 struct inotify_event_private_data *event_priv;
98 struct fsnotify_event_private_data *fsn_event_priv; 98 struct fsnotify_event_private_data *fsn_event_priv;
99 int wd, ret; 99 struct fsnotify_event *added_event;
100 int wd, ret = 0;
100 101
101 pr_debug("%s: group=%p event=%p to_tell=%p mask=%x\n", __func__, group, 102 pr_debug("%s: group=%p event=%p to_tell=%p mask=%x\n", __func__, group,
102 event, event->to_tell, event->mask); 103 event, event->to_tell, event->mask);
@@ -120,14 +121,13 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev
120 fsn_event_priv->group = group; 121 fsn_event_priv->group = group;
121 event_priv->wd = wd; 122 event_priv->wd = wd;
122 123
123 ret = fsnotify_add_notify_event(group, event, fsn_event_priv, inotify_merge, NULL); 124 added_event = fsnotify_add_notify_event(group, event, fsn_event_priv, inotify_merge);
124 if (ret) { 125 if (added_event) {
125 inotify_free_event_priv(fsn_event_priv); 126 inotify_free_event_priv(fsn_event_priv);
126 /* EEXIST says we tail matched, EOVERFLOW isn't something 127 if (!IS_ERR(added_event))
127 * to report up the stack. */ 128 fsnotify_put_event(added_event);
128 if ((ret == -EEXIST) || 129 else
129 (ret == -EOVERFLOW)) 130 ret = PTR_ERR(added_event);
130 ret = 0;
131 } 131 }
132 132
133 if (fsn_mark->mask & IN_ONESHOT) 133 if (fsn_mark->mask & IN_ONESHOT)
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 1068e1ca9cb0..a4cd227c4c76 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -516,7 +516,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
516 struct fsnotify_group *group) 516 struct fsnotify_group *group)
517{ 517{
518 struct inotify_inode_mark *i_mark; 518 struct inotify_inode_mark *i_mark;
519 struct fsnotify_event *ignored_event; 519 struct fsnotify_event *ignored_event, *notify_event;
520 struct inotify_event_private_data *event_priv; 520 struct inotify_event_private_data *event_priv;
521 struct fsnotify_event_private_data *fsn_event_priv; 521 struct fsnotify_event_private_data *fsn_event_priv;
522 int ret; 522 int ret;
@@ -538,9 +538,14 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
538 fsn_event_priv->group = group; 538 fsn_event_priv->group = group;
539 event_priv->wd = i_mark->wd; 539 event_priv->wd = i_mark->wd;
540 540
541 ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv, NULL, NULL); 541 notify_event = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv, NULL);
542 if (ret) 542 if (notify_event) {
543 if (IS_ERR(notify_event))
544 ret = PTR_ERR(notify_event);
545 else
546 fsnotify_put_event(notify_event);
543 inotify_free_event_priv(fsn_event_priv); 547 inotify_free_event_priv(fsn_event_priv);
548 }
544 549
545skip_send_ignore: 550skip_send_ignore:
546 551
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index e6dde25fb99b..f39260f8f865 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -137,16 +137,14 @@ struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struct fsnot
137 * event off the queue to deal with. If the event is successfully added to the 137 * event off the queue to deal with. If the event is successfully added to the
138 * group's notification queue, a reference is taken on event. 138 * group's notification queue, a reference is taken on event.
139 */ 139 */
140int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event, 140struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
141 struct fsnotify_event_private_data *priv, 141 struct fsnotify_event_private_data *priv,
142 int (*merge)(struct list_head *, 142 struct fsnotify_event *(*merge)(struct list_head *,
143 struct fsnotify_event *, 143 struct fsnotify_event *))
144 void **arg),
145 void **arg)
146{ 144{
145 struct fsnotify_event *return_event = NULL;
147 struct fsnotify_event_holder *holder = NULL; 146 struct fsnotify_event_holder *holder = NULL;
148 struct list_head *list = &group->notification_list; 147 struct list_head *list = &group->notification_list;
149 int rc = 0;
150 148
151 pr_debug("%s: group=%p event=%p priv=%p\n", __func__, group, event, priv); 149 pr_debug("%s: group=%p event=%p priv=%p\n", __func__, group, event, priv);
152 150
@@ -162,27 +160,37 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_even
162alloc_holder: 160alloc_holder:
163 holder = fsnotify_alloc_event_holder(); 161 holder = fsnotify_alloc_event_holder();
164 if (!holder) 162 if (!holder)
165 return -ENOMEM; 163 return ERR_PTR(-ENOMEM);
166 } 164 }
167 165
168 mutex_lock(&group->notification_mutex); 166 mutex_lock(&group->notification_mutex);
169 167
170 if (group->q_len >= group->max_events) { 168 if (group->q_len >= group->max_events) {
171 event = q_overflow_event; 169 event = q_overflow_event;
172 rc = -EOVERFLOW; 170
171 /*
172 * we need to return the overflow event
173 * which means we need a ref
174 */
175 fsnotify_get_event(event);
176 return_event = event;
177
173 /* sorry, no private data on the overflow event */ 178 /* sorry, no private data on the overflow event */
174 priv = NULL; 179 priv = NULL;
175 } 180 }
176 181
177 if (!list_empty(list) && merge) { 182 if (!list_empty(list) && merge) {
178 int ret; 183 struct fsnotify_event *tmp;
179 184
180 ret = merge(list, event, arg); 185 tmp = merge(list, event);
181 if (ret) { 186 if (tmp) {
182 mutex_unlock(&group->notification_mutex); 187 mutex_unlock(&group->notification_mutex);
188
189 if (return_event)
190 fsnotify_put_event(return_event);
183 if (holder != &event->holder) 191 if (holder != &event->holder)
184 fsnotify_destroy_event_holder(holder); 192 fsnotify_destroy_event_holder(holder);
185 return ret; 193 return tmp;
186 } 194 }
187 } 195 }
188 196
@@ -197,6 +205,12 @@ alloc_holder:
197 * event holder was used, go back and get a new one */ 205 * event holder was used, go back and get a new one */
198 spin_unlock(&event->lock); 206 spin_unlock(&event->lock);
199 mutex_unlock(&group->notification_mutex); 207 mutex_unlock(&group->notification_mutex);
208
209 if (return_event) {
210 fsnotify_put_event(return_event);
211 return_event = NULL;
212 }
213
200 goto alloc_holder; 214 goto alloc_holder;
201 } 215 }
202 216
@@ -211,7 +225,7 @@ alloc_holder:
211 mutex_unlock(&group->notification_mutex); 225 mutex_unlock(&group->notification_mutex);
212 226
213 wake_up(&group->notification_waitq); 227 wake_up(&group->notification_waitq);
214 return rc; 228 return return_event;
215} 229}
216 230
217/* 231/*
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index a83859d7d36e..564b5ea4a831 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -379,13 +379,11 @@ extern struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struc
379 struct fsnotify_event *event); 379 struct fsnotify_event *event);
380 380
381/* attach the event to the group notification queue */ 381/* attach the event to the group notification queue */
382extern int fsnotify_add_notify_event(struct fsnotify_group *group, 382extern struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group,
383 struct fsnotify_event *event, 383 struct fsnotify_event *event,
384 struct fsnotify_event_private_data *priv, 384 struct fsnotify_event_private_data *priv,
385 int (*merge)(struct list_head *, 385 struct fsnotify_event *(*merge)(struct list_head *,
386 struct fsnotify_event *, 386 struct fsnotify_event *));
387 void **),
388 void **arg);
389/* true if the group notification queue is empty */ 387/* true if the group notification queue is empty */
390extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group); 388extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
391/* return, but do not dequeue the first event on the notification queue */ 389/* return, but do not dequeue the first event on the notification queue */