summaryrefslogtreecommitdiffstats
path: root/fs/notify
diff options
context:
space:
mode:
authorEric Paris2009-12-18 03:24:25 +0100
committerEric Paris2010-07-28 15:58:55 +0200
commit9dced01a0939f3e952eca8c21427ceec1f473dcf (patch)
tree10eab41808fd16d7db9b6737bccf30fb53eb4faa /fs/notify
parentfanotify: merge notification events with different masks (diff)
downloadkernel-qcow2-linux-9dced01a0939f3e952eca8c21427ceec1f473dcf.tar.gz
kernel-qcow2-linux-9dced01a0939f3e952eca8c21427ceec1f473dcf.tar.xz
kernel-qcow2-linux-9dced01a0939f3e952eca8c21427ceec1f473dcf.zip
fanotify: do not clone on merge unless needed
Currently if 2 events are going to be merged on the notication queue with different masks the second event will be cloned and will replace the first event. However if this notification queue is the only place referencing the event in question there is no reason not to just update the event in place. We can tell this if the event->refcnt == 1. Since we hold a reference for each queue this event is on we know that when refcnt == 1 this is the only queue. The other concern is that it might be about to be added to a new queue, but this can't be the case since fsnotify holds a reference on the event until it is finished adding it to queues. Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to 'fs/notify')
-rw-r--r--fs/notify/fanotify/fanotify.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 8e574d6f6a80..5b0b6b485a9c 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -46,6 +46,16 @@ static int fanotify_merge(struct list_head *list, struct fsnotify_event *event)
if (test_event->mask == event->mask)
goto out;
+ /*
+ * if the refcnt == 1 this is the only queue
+ * for this event and so we can update the mask
+ * in place.
+ */
+ if (atomic_read(&test_event->refcnt) == 1) {
+ test_event->mask |= event->mask;
+ goto out;
+ }
+
/* can't allocate memory, merge was no possible */
new_event = fsnotify_clone_event(test_event);
if (unlikely(!new_event)) {