[PATCH] inotify: use fget_light
[linux-2.6.git] / fs / inotify.c
index e423bfe..807209f 100644 (file)
@@ -29,8 +29,6 @@
 #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/poll.h>
-#include <linux/device.h>
-#include <linux/miscdevice.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/writeback.h>
@@ -45,8 +43,8 @@ static kmem_cache_t *event_cachep;
 
 static struct vfsmount *inotify_mnt;
 
-/* These are configurable via /proc/sys/inotify */
-int inotify_max_user_devices;
+/* these are configurable via /proc/sys/fs/inotify/ */
+int inotify_max_user_instances;
 int inotify_max_user_watches;
 int inotify_max_queued_events;
 
@@ -64,8 +62,8 @@ int inotify_max_queued_events;
  * Lifetimes of the three main data structures--inotify_device, inode, and
  * inotify_watch--are managed by reference count.
  *
- * inotify_device: Lifetime is from open until release.  Additional references
- * can bump the count via get_inotify_dev() and drop the count via
+ * inotify_device: Lifetime is from inotify_init() until release.  Additional
+ * references can bump the count via get_inotify_dev() and drop the count via
  * put_inotify_dev().
  *
  * inotify_watch: Lifetime is from create_watch() to destory_watch().
@@ -77,7 +75,7 @@ int inotify_max_queued_events;
  */
 
 /*
- * struct inotify_device - represents an open instance of an inotify device
+ * struct inotify_device - represents an inotify instance
  *
  * This structure is protected by the semaphore 'sem'.
  */
@@ -125,6 +123,47 @@ struct inotify_watch {
        u32                     mask;   /* event mask for this watch */
 };
 
+#ifdef CONFIG_SYSCTL
+
+#include <linux/sysctl.h>
+
+static int zero;
+
+ctl_table inotify_table[] = {
+       {
+               .ctl_name       = INOTIFY_MAX_USER_INSTANCES,
+               .procname       = "max_user_instances",
+               .data           = &inotify_max_user_instances,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &zero,
+       },
+       {
+               .ctl_name       = INOTIFY_MAX_USER_WATCHES,
+               .procname       = "max_user_watches",
+               .data           = &inotify_max_user_watches,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &zero, 
+       },
+       {
+               .ctl_name       = INOTIFY_MAX_QUEUED_EVENTS,
+               .procname       = "max_queued_events",
+               .data           = &inotify_max_queued_events,
+               .maxlen         = sizeof(int),
+               .mode           = 0644, 
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec, 
+               .extra1         = &zero
+       },
+       { .ctl_name = 0 }
+};
+#endif /* CONFIG_SYSCTL */
+
 static inline void get_inotify_dev(struct inotify_device *dev)
 {
        atomic_inc(&dev->count);
@@ -332,7 +371,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 = permission(nd->dentry->d_inode, MAY_READ, NULL);
        if (error) 
-               path_release (nd);
+               path_release(nd);
        return error;
 }
 
@@ -348,7 +387,8 @@ static struct inotify_watch *create_watch(struct inotify_device *dev,
        struct inotify_watch *watch;
        int ret;
 
-       if (atomic_read(&dev->user->inotify_watches) >= inotify_max_user_watches)
+       if (atomic_read(&dev->user->inotify_watches) >=
+                       inotify_max_user_watches)
                return ERR_PTR(-ENOSPC);
 
        watch = kmem_cache_alloc(watch_cachep, GFP_KERNEL);
@@ -744,15 +784,14 @@ static int inotify_release(struct inode *ignored, struct file *file)
                inotify_dev_event_dequeue(dev);
        up(&dev->sem);
 
-       /* free this device: the put matching the get in inotify_open() */
+       /* free this device: the put matching the get in inotify_init() */
        put_inotify_dev(dev);
 
        return 0;
 }
 
 /*
- * inotify_ignore - handle the INOTIFY_IGNORE ioctl, asking that a given wd be
- * removed from the device.
+ * inotify_ignore - remove a given wd from this inotify instance.
  *
  * Can sleep.
  */
@@ -817,15 +856,12 @@ asmlinkage long sys_inotify_init(void)
 {
        struct inotify_device *dev;
        struct user_struct *user;
-       int ret = -ENOTTY;
-       int fd;
-       struct file *filp;
+       struct file *filp;      
+       int fd, ret;
 
        fd = get_unused_fd();
-       if (fd < 0) {
-               ret = fd;
-               goto out;
-       }
+       if (fd < 0)
+               return fd;
 
        filp = get_empty_filp();
        if (!filp) {
@@ -833,16 +869,11 @@ asmlinkage long sys_inotify_init(void)
                ret = -ENFILE;
                goto out;
        }
-       filp->f_op = &inotify_fops;
-       filp->f_vfsmnt = mntget(inotify_mnt);
-       filp->f_dentry = dget(inotify_mnt->mnt_root);
-       filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
-       filp->f_mode = FMODE_READ;
-       filp->f_flags = O_RDONLY;
 
        user = get_uid(current->user);
 
-       if (unlikely(atomic_read(&user->inotify_devs) >= inotify_max_user_devices)) {
+       if (unlikely(atomic_read(&user->inotify_devs) >=
+                       inotify_max_user_instances)) {
                ret = -EMFILE;
                goto out_err;
        }
@@ -853,6 +884,14 @@ asmlinkage long sys_inotify_init(void)
                goto out_err;
        }
 
+       filp->f_op = &inotify_fops;
+       filp->f_vfsmnt = mntget(inotify_mnt);
+       filp->f_dentry = dget(inotify_mnt->mnt_root);
+       filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
+       filp->f_mode = FMODE_READ;
+       filp->f_flags = O_RDONLY;
+       filp->private_data = dev;
+
        idr_init(&dev->idr);
        INIT_LIST_HEAD(&dev->events);
        INIT_LIST_HEAD(&dev->watches);
@@ -866,9 +905,8 @@ asmlinkage long sys_inotify_init(void)
 
        get_inotify_dev(dev);
        atomic_inc(&user->inotify_devs);
+       fd_install(fd, filp);
 
-       filp->private_data = dev;
-       fd_install (fd, filp);
        return fd;
 out_err:
        put_unused_fd (fd);
@@ -878,34 +916,33 @@ out:
        return ret;
 }
 
-asmlinkage long sys_inotify_add_watch(int fd, const char *path, u32 mask)
+asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
 {
        struct inotify_watch *watch, *old;
        struct inode *inode;
        struct inotify_device *dev;
        struct nameidata nd;
        struct file *filp;
-       int ret;
+       int ret, fput_needed;
 
-       filp = fget(fd);
-       if (!filp)
+       filp = fget_light(fd, &fput_needed);
+       if (unlikely(!filp))
                return -EBADF;
 
-       dev = filp->private_data;
-
-       ret = find_inode ((const char __user*)path, &nd);
-       if (ret)
+       ret = find_inode(path, &nd);
+       if (unlikely(ret))
                goto fput_and_out;
 
-       /* Held in place by reference in nd */
+       /* inode held in place by reference to nd; dev by fget on fd */
        inode = nd.dentry->d_inode;
+       dev = filp->private_data;
 
        down(&inode->inotify_sem);
        down(&dev->sem);
 
        /* don't let user-space set invalid bits: we don't want flags set */
        mask &= IN_ALL_EVENTS;
-       if (!mask) {
+       if (unlikely(!mask)) {
                ret = -EINVAL;
                goto out;
        }
@@ -936,7 +973,7 @@ out:
        up(&dev->sem);
        up(&inode->inotify_sem);
 fput_and_out:
-       fput(filp);
+       fput_light(filp, fput_needed);
        return ret;
 }
 
@@ -944,14 +981,15 @@ asmlinkage long sys_inotify_rm_watch(int fd, u32 wd)
 {
        struct file *filp;
        struct inotify_device *dev;
-       int ret;
+       int ret, fput_needed;
 
-       filp = fget(fd);
-       if (!filp)
+       filp = fget_light(fd, &fput_needed);
+       if (unlikely(!filp))
                return -EBADF;
        dev = filp->private_data;
-       ret = inotify_ignore (dev, wd);
-       fput(filp);
+       ret = inotify_ignore(dev, wd);
+       fput_light(filp, fput_needed);
+
        return ret;
 }
 
@@ -969,17 +1007,17 @@ static struct file_system_type inotify_fs_type = {
 };
 
 /*
- * inotify_init - Our initialization function.  Note that we cannnot return
+ * inotify_setup - Our initialization function.  Note that we cannnot return
  * error because we have compiled-in VFS hooks.  So an (unlikely) failure here
  * must result in panic().
  */
-static int __init inotify_init(void)
+static int __init inotify_setup(void)
 {
        register_filesystem(&inotify_fs_type);
        inotify_mnt = kern_mount(&inotify_fs_type);
 
        inotify_max_queued_events = 8192;
-       inotify_max_user_devices = 128;
+       inotify_max_user_instances = 8;
        inotify_max_user_watches = 8192;
 
        atomic_set(&inotify_cookie, 0);
@@ -991,9 +1029,7 @@ static int __init inotify_init(void)
                                         sizeof(struct inotify_kernel_event),
                                         0, SLAB_PANIC, NULL, NULL);
 
-       printk(KERN_INFO "inotify syscall\n");
-
        return 0;
 }
 
-module_init(inotify_init);
+module_init(inotify_setup);