diff options
Diffstat (limited to 'fs/inotify_user.c')
-rw-r--r-- | fs/inotify_user.c | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/fs/inotify_user.c b/fs/inotify_user.c index 5e009331c01f..7b94a1e3c015 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c | |||
@@ -41,9 +41,9 @@ static struct kmem_cache *event_cachep __read_mostly; | |||
41 | static struct vfsmount *inotify_mnt __read_mostly; | 41 | static struct vfsmount *inotify_mnt __read_mostly; |
42 | 42 | ||
43 | /* these are configurable via /proc/sys/fs/inotify/ */ | 43 | /* these are configurable via /proc/sys/fs/inotify/ */ |
44 | int inotify_max_user_instances __read_mostly; | 44 | static int inotify_max_user_instances __read_mostly; |
45 | int inotify_max_user_watches __read_mostly; | 45 | static int inotify_max_user_watches __read_mostly; |
46 | int inotify_max_queued_events __read_mostly; | 46 | static int inotify_max_queued_events __read_mostly; |
47 | 47 | ||
48 | /* | 48 | /* |
49 | * Lock ordering: | 49 | * Lock ordering: |
@@ -79,6 +79,7 @@ struct inotify_device { | |||
79 | atomic_t count; /* reference count */ | 79 | atomic_t count; /* reference count */ |
80 | struct user_struct *user; /* user who opened this dev */ | 80 | struct user_struct *user; /* user who opened this dev */ |
81 | struct inotify_handle *ih; /* inotify handle */ | 81 | struct inotify_handle *ih; /* inotify handle */ |
82 | struct fasync_struct *fa; /* async notification */ | ||
82 | unsigned int queue_size; /* size of the queue (bytes) */ | 83 | unsigned int queue_size; /* size of the queue (bytes) */ |
83 | unsigned int event_count; /* number of pending events */ | 84 | unsigned int event_count; /* number of pending events */ |
84 | unsigned int max_events; /* maximum number of events */ | 85 | unsigned int max_events; /* maximum number of events */ |
@@ -248,6 +249,19 @@ inotify_dev_get_event(struct inotify_device *dev) | |||
248 | } | 249 | } |
249 | 250 | ||
250 | /* | 251 | /* |
252 | * inotify_dev_get_last_event - return the last event in the given dev's queue | ||
253 | * | ||
254 | * Caller must hold dev->ev_mutex. | ||
255 | */ | ||
256 | static inline struct inotify_kernel_event * | ||
257 | inotify_dev_get_last_event(struct inotify_device *dev) | ||
258 | { | ||
259 | if (list_empty(&dev->events)) | ||
260 | return NULL; | ||
261 | return list_entry(dev->events.prev, struct inotify_kernel_event, list); | ||
262 | } | ||
263 | |||
264 | /* | ||
251 | * inotify_dev_queue_event - event handler registered with core inotify, adds | 265 | * inotify_dev_queue_event - event handler registered with core inotify, adds |
252 | * a new event to the given device | 266 | * a new event to the given device |
253 | * | 267 | * |
@@ -269,11 +283,11 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask, | |||
269 | /* we can safely put the watch as we don't reference it while | 283 | /* we can safely put the watch as we don't reference it while |
270 | * generating the event | 284 | * generating the event |
271 | */ | 285 | */ |
272 | if (mask & IN_IGNORED || mask & IN_ONESHOT) | 286 | if (mask & IN_IGNORED || w->mask & IN_ONESHOT) |
273 | put_inotify_watch(w); /* final put */ | 287 | put_inotify_watch(w); /* final put */ |
274 | 288 | ||
275 | /* coalescing: drop this event if it is a dupe of the previous */ | 289 | /* coalescing: drop this event if it is a dupe of the previous */ |
276 | last = inotify_dev_get_event(dev); | 290 | last = inotify_dev_get_last_event(dev); |
277 | if (last && last->event.mask == mask && last->event.wd == wd && | 291 | if (last && last->event.mask == mask && last->event.wd == wd && |
278 | last->event.cookie == cookie) { | 292 | last->event.cookie == cookie) { |
279 | const char *lastname = last->name; | 293 | const char *lastname = last->name; |
@@ -302,6 +316,7 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask, | |||
302 | dev->queue_size += sizeof(struct inotify_event) + kevent->event.len; | 316 | dev->queue_size += sizeof(struct inotify_event) + kevent->event.len; |
303 | list_add_tail(&kevent->list, &dev->events); | 317 | list_add_tail(&kevent->list, &dev->events); |
304 | wake_up_interruptible(&dev->wq); | 318 | wake_up_interruptible(&dev->wq); |
319 | kill_fasync(&dev->fa, SIGIO, POLL_IN); | ||
305 | 320 | ||
306 | out: | 321 | out: |
307 | mutex_unlock(&dev->ev_mutex); | 322 | mutex_unlock(&dev->ev_mutex); |
@@ -352,7 +367,7 @@ static int find_inode(const char __user *dirname, struct nameidata *nd, | |||
352 | /* you can only watch an inode if you have read permissions on it */ | 367 | /* you can only watch an inode if you have read permissions on it */ |
353 | error = vfs_permission(nd, MAY_READ); | 368 | error = vfs_permission(nd, MAY_READ); |
354 | if (error) | 369 | if (error) |
355 | path_release(nd); | 370 | path_put(&nd->path); |
356 | return error; | 371 | return error; |
357 | } | 372 | } |
358 | 373 | ||
@@ -490,6 +505,13 @@ static ssize_t inotify_read(struct file *file, char __user *buf, | |||
490 | return ret; | 505 | return ret; |
491 | } | 506 | } |
492 | 507 | ||
508 | static int inotify_fasync(int fd, struct file *file, int on) | ||
509 | { | ||
510 | struct inotify_device *dev = file->private_data; | ||
511 | |||
512 | return fasync_helper(fd, file, on, &dev->fa) >= 0 ? 0 : -EIO; | ||
513 | } | ||
514 | |||
493 | static int inotify_release(struct inode *ignored, struct file *file) | 515 | static int inotify_release(struct inode *ignored, struct file *file) |
494 | { | 516 | { |
495 | struct inotify_device *dev = file->private_data; | 517 | struct inotify_device *dev = file->private_data; |
@@ -502,6 +524,9 @@ static int inotify_release(struct inode *ignored, struct file *file) | |||
502 | inotify_dev_event_dequeue(dev); | 524 | inotify_dev_event_dequeue(dev); |
503 | mutex_unlock(&dev->ev_mutex); | 525 | mutex_unlock(&dev->ev_mutex); |
504 | 526 | ||
527 | if (file->f_flags & FASYNC) | ||
528 | inotify_fasync(-1, file, 0); | ||
529 | |||
505 | /* free this device: the put matching the get in inotify_init() */ | 530 | /* free this device: the put matching the get in inotify_init() */ |
506 | put_inotify_dev(dev); | 531 | put_inotify_dev(dev); |
507 | 532 | ||
@@ -530,6 +555,7 @@ static long inotify_ioctl(struct file *file, unsigned int cmd, | |||
530 | static const struct file_operations inotify_fops = { | 555 | static const struct file_operations inotify_fops = { |
531 | .poll = inotify_poll, | 556 | .poll = inotify_poll, |
532 | .read = inotify_read, | 557 | .read = inotify_read, |
558 | .fasync = inotify_fasync, | ||
533 | .release = inotify_release, | 559 | .release = inotify_release, |
534 | .unlocked_ioctl = inotify_ioctl, | 560 | .unlocked_ioctl = inotify_ioctl, |
535 | .compat_ioctl = inotify_ioctl, | 561 | .compat_ioctl = inotify_ioctl, |
@@ -577,6 +603,7 @@ asmlinkage long sys_inotify_init(void) | |||
577 | goto out_free_dev; | 603 | goto out_free_dev; |
578 | } | 604 | } |
579 | dev->ih = ih; | 605 | dev->ih = ih; |
606 | dev->fa = NULL; | ||
580 | 607 | ||
581 | filp->f_op = &inotify_fops; | 608 | filp->f_op = &inotify_fops; |
582 | filp->f_path.mnt = mntget(inotify_mnt); | 609 | filp->f_path.mnt = mntget(inotify_mnt); |
@@ -640,7 +667,7 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) | |||
640 | goto fput_and_out; | 667 | goto fput_and_out; |
641 | 668 | ||
642 | /* inode held in place by reference to nd; dev by fget on fd */ | 669 | /* inode held in place by reference to nd; dev by fget on fd */ |
643 | inode = nd.dentry->d_inode; | 670 | inode = nd.path.dentry->d_inode; |
644 | dev = filp->private_data; | 671 | dev = filp->private_data; |
645 | 672 | ||
646 | mutex_lock(&dev->up_mutex); | 673 | mutex_lock(&dev->up_mutex); |
@@ -649,7 +676,7 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) | |||
649 | ret = create_watch(dev, inode, mask); | 676 | ret = create_watch(dev, inode, mask); |
650 | mutex_unlock(&dev->up_mutex); | 677 | mutex_unlock(&dev->up_mutex); |
651 | 678 | ||
652 | path_release(&nd); | 679 | path_put(&nd.path); |
653 | fput_and_out: | 680 | fput_and_out: |
654 | fput_light(filp, fput_needed); | 681 | fput_light(filp, fput_needed); |
655 | return ret; | 682 | return ret; |