summaryrefslogtreecommitdiffstats
path: root/fs/inotify.c
diff options
context:
space:
mode:
authorJohn McCutchan <ttb@tentacle.dhs.org>2005-08-01 11:00:45 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-08-01 09:16:53 -0700
commitb9c55d29e9fced1eb1b4c252b2efd4b55a0c3c7f (patch)
tree3fc1fe1e0f40d673d9675a3db5b84ca00b81eaea /fs/inotify.c
parent7544953685859875b5ac0260b6b1856066c092d6 (diff)
downloadlinux-stable-b9c55d29e9fced1eb1b4c252b2efd4b55a0c3c7f.tar.gz
linux-stable-b9c55d29e9fced1eb1b4c252b2efd4b55a0c3c7f.tar.bz2
linux-stable-b9c55d29e9fced1eb1b4c252b2efd4b55a0c3c7f.zip
[PATCH] inotify: fix race between the kernel and user space
When you rm a watch, an IN_IGNORED event is sent down the event queue with the watch descriptor that you just rm'd. If you then add a watch you could get the ignored watch's wd and if you haven't read the entire event queue, user space will think that it's newly created watch was just ignored. To avoid this problem we just use idr_get_new_above instead of idr_get_new. Signed-off-by: John McCutchan <ttb@tentacle.dhs.org> Signed-off-by: Robert Love <rml@novell.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/inotify.c')
-rw-r--r--fs/inotify.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/fs/inotify.c b/fs/inotify.c
index a8a714e48140..27ebcac5e07f 100644
--- a/fs/inotify.c
+++ b/fs/inotify.c
@@ -90,6 +90,7 @@ struct inotify_device {
unsigned int queue_size; /* size of the queue (bytes) */
unsigned int event_count; /* number of pending events */
unsigned int max_events; /* maximum number of events */
+ u32 last_wd; /* the last wd allocated */
};
/*
@@ -352,7 +353,7 @@ static int inotify_dev_get_wd(struct inotify_device *dev,
do {
if (unlikely(!idr_pre_get(&dev->idr, GFP_KERNEL)))
return -ENOSPC;
- ret = idr_get_new(&dev->idr, watch, &watch->wd);
+ ret = idr_get_new_above(&dev->idr, watch, dev->last_wd, &watch->wd);
} while (ret == -EAGAIN);
return ret;
@@ -401,6 +402,7 @@ static struct inotify_watch *create_watch(struct inotify_device *dev,
return ERR_PTR(ret);
}
+ dev->last_wd = ret;
watch->mask = mask;
atomic_set(&watch->count, 0);
INIT_LIST_HEAD(&watch->d_list);
@@ -899,6 +901,7 @@ asmlinkage long sys_inotify_init(void)
dev->queue_size = 0;
dev->max_events = inotify_max_queued_events;
dev->user = user;
+ dev->last_wd = 0;
atomic_set(&dev->count, 0);
get_inotify_dev(dev);