X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=fs%2Finotify_user.c;h=6676c06bb7c16935b3a7fbc4615836f1dfb256fb;hb=e098675635479e9267cf2b12fb969c463cf506ab;hp=c509a817068f86d97eba002c4a64e4cf93bb43ef;hpb=1c17d18e3775485bf1e0ce79575eb637a94494a2;p=linux-2.6 diff --git a/fs/inotify_user.c b/fs/inotify_user.c index c509a81706..6676c06bb7 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c @@ -41,9 +41,9 @@ static struct kmem_cache *event_cachep __read_mostly; static struct vfsmount *inotify_mnt __read_mostly; /* these are configurable via /proc/sys/fs/inotify/ */ -int inotify_max_user_instances __read_mostly; -int inotify_max_user_watches __read_mostly; -int inotify_max_queued_events __read_mostly; +static int inotify_max_user_instances __read_mostly; +static int inotify_max_user_watches __read_mostly; +static int inotify_max_queued_events __read_mostly; /* * Lock ordering: @@ -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 */ @@ -282,7 +283,7 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask, /* we can safely put the watch as we don't reference it while * generating the event */ - if (mask & IN_IGNORED || mask & IN_ONESHOT) + if (mask & IN_IGNORED || w->mask & IN_ONESHOT) put_inotify_watch(w); /* final put */ /* coalescing: drop this event if it is a dupe of the previous */ @@ -315,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); @@ -365,7 +367,7 @@ static int find_inode(const char __user *dirname, struct nameidata *nd, /* you can only watch an inode if you have read permissions on it */ error = vfs_permission(nd, MAY_READ); if (error) - path_release(nd); + path_put(&nd->path); return error; } @@ -503,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; @@ -515,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); @@ -543,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, @@ -585,11 +598,12 @@ asmlinkage long sys_inotify_init(void) } ih = inotify_init(&inotify_user_ops); - if (unlikely(IS_ERR(ih))) { + if (IS_ERR(ih)) { ret = PTR_ERR(ih); goto out_free_dev; } dev->ih = ih; + dev->fa = NULL; filp->f_op = &inotify_fops; filp->f_path.mnt = mntget(inotify_mnt); @@ -653,7 +667,7 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) goto fput_and_out; /* inode held in place by reference to nd; dev by fget on fd */ - inode = nd.dentry->d_inode; + inode = nd.path.dentry->d_inode; dev = filp->private_data; mutex_lock(&dev->up_mutex); @@ -662,7 +676,7 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) ret = create_watch(dev, inode, mask); mutex_unlock(&dev->up_mutex); - path_release(&nd); + path_put(&nd.path); fput_and_out: fput_light(filp, fput_needed); return ret;