X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=fs%2Finotify_user.c;h=a336c9709f3cc477ed15236642b743f0a3ca493e;hb=3dfcb701e1ff7aa21d6623e46b6ec3f7d0d306e1;hp=5e009331c01ff5fbe1a453f735e906e54645368f;hpb=0c326331c8b107abc0a160e8899d749150b8f76a;p=linux-2.6-omap-h63xx.git diff --git a/fs/inotify_user.c b/fs/inotify_user.c index 5e009331c01..a336c9709f3 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c @@ -79,6 +79,7 @@ struct inotify_device { atomic_t count; /* reference count */ struct user_struct *user; /* user who opened this dev */ struct inotify_handle *ih; /* inotify handle */ + struct fasync_struct *fa; /* async notification */ 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 */ @@ -247,6 +248,19 @@ inotify_dev_get_event(struct inotify_device *dev) return list_entry(dev->events.next, struct inotify_kernel_event, list); } +/* + * inotify_dev_get_last_event - return the last event in the given dev's queue + * + * Caller must hold dev->ev_mutex. + */ +static inline struct inotify_kernel_event * +inotify_dev_get_last_event(struct inotify_device *dev) +{ + if (list_empty(&dev->events)) + return NULL; + return list_entry(dev->events.prev, struct inotify_kernel_event, list); +} + /* * inotify_dev_queue_event - event handler registered with core inotify, adds * a new event to the given device @@ -273,7 +287,7 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask, put_inotify_watch(w); /* final put */ /* coalescing: drop this event if it is a dupe of the previous */ - last = inotify_dev_get_event(dev); + last = inotify_dev_get_last_event(dev); if (last && last->event.mask == mask && last->event.wd == wd && last->event.cookie == cookie) { const char *lastname = last->name; @@ -302,6 +316,7 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask, dev->queue_size += sizeof(struct inotify_event) + kevent->event.len; list_add_tail(&kevent->list, &dev->events); wake_up_interruptible(&dev->wq); + kill_fasync(&dev->fa, SIGIO, POLL_IN); out: mutex_unlock(&dev->ev_mutex); @@ -490,6 +505,13 @@ static ssize_t inotify_read(struct file *file, char __user *buf, return ret; } +static int inotify_fasync(int fd, struct file *file, int on) +{ + struct inotify_device *dev = file->private_data; + + return fasync_helper(fd, file, on, &dev->fa) >= 0 ? 0 : -EIO; +} + static int inotify_release(struct inode *ignored, struct file *file) { struct inotify_device *dev = file->private_data; @@ -502,6 +524,9 @@ static int inotify_release(struct inode *ignored, struct file *file) inotify_dev_event_dequeue(dev); mutex_unlock(&dev->ev_mutex); + if (file->f_flags & FASYNC) + inotify_fasync(-1, file, 0); + /* free this device: the put matching the get in inotify_init() */ put_inotify_dev(dev); @@ -530,6 +555,7 @@ static long inotify_ioctl(struct file *file, unsigned int cmd, static const struct file_operations inotify_fops = { .poll = inotify_poll, .read = inotify_read, + .fasync = inotify_fasync, .release = inotify_release, .unlocked_ioctl = inotify_ioctl, .compat_ioctl = inotify_ioctl, @@ -577,6 +603,7 @@ asmlinkage long sys_inotify_init(void) goto out_free_dev; } dev->ih = ih; + dev->fa = NULL; filp->f_op = &inotify_fops; filp->f_path.mnt = mntget(inotify_mnt);