aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/notification.c
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2009-12-17 21:24:22 -0500
committerEric Paris <eparis@redhat.com>2010-07-28 09:58:49 -0400
commit1201a5361b9bd6512ae01e6f2b7aa79d458cafb1 (patch)
treebfbb10b38b6b32b773a43cc371b5d31a9ce3fe51 /fs/notify/notification.c
parentb4e4e1407312ae5a267ed7d716e6d4e7120a8430 (diff)
fsnotify: replace an event on a list
fanotify would like to clone events already on its notification list, make changes to the new event, and then replace the old event on the list with the new event. This patch implements the replace functionality of that process. Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to 'fs/notify/notification.c')
-rw-r--r--fs/notify/notification.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index bc9470c7ece7..b493c378445f 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -287,6 +287,62 @@ static void initialize_event(struct fsnotify_event *event)
287 INIT_LIST_HEAD(&event->private_data_list); 287 INIT_LIST_HEAD(&event->private_data_list);
288} 288}
289 289
290/*
291 * Caller damn well better be holding whatever mutex is protecting the
292 * old_holder->event_list.
293 */
294int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
295 struct fsnotify_event *new_event)
296{
297 struct fsnotify_event *old_event = old_holder->event;
298 struct fsnotify_event_holder *new_holder = NULL;
299
300 /*
301 * There is one fsnotify_event_holder embedded inside each fsnotify_event.
302 * Check if we expect to be able to use that holder. If not alloc a new
303 * holder.
304 * For the overflow event it's possible that something will use the in
305 * event holder before we get the lock so we may need to jump back and
306 * alloc a new holder, this can't happen for most events...
307 */
308 if (!list_empty(&new_event->holder.event_list)) {
309alloc_holder:
310 new_holder = fsnotify_alloc_event_holder();
311 if (!new_holder)
312 return -ENOMEM;
313 }
314
315 spin_lock(&old_event->lock);
316 spin_lock(&new_event->lock);
317
318 if (list_empty(&new_event->holder.event_list)) {
319 if (unlikely(new_holder))
320 fsnotify_destroy_event_holder(new_holder);
321 new_holder = &new_event->holder;
322 } else if (unlikely(!new_holder)) {
323 /* between the time we checked above and got the lock the in
324 * event holder was used, go back and get a new one */
325 spin_unlock(&new_event->lock);
326 spin_unlock(&old_event->lock);
327 goto alloc_holder;
328 }
329
330 new_holder->event = new_event;
331 list_replace_init(&old_holder->event_list, &new_holder->event_list);
332
333 spin_unlock(&new_event->lock);
334 spin_unlock(&old_event->lock);
335
336 /* event == holder means we are referenced through the in event holder */
337 if (old_holder != &old_event->holder)
338 fsnotify_destroy_event_holder(old_holder);
339
340 fsnotify_get_event(new_event); /* on the list take reference */
341 fsnotify_put_event(old_event); /* off the list, drop reference */
342
343 return 0;
344}
345
290struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event) 346struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event)
291{ 347{
292 struct fsnotify_event *event; 348 struct fsnotify_event *event;