[PATCH] inotify: use fget_light
[linux-2.6.git] / fs / inotify.c
index fb48031..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>
@@ -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'.
  */
@@ -373,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;
 }
 
@@ -389,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);
@@ -785,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.
  */
@@ -858,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) {
@@ -874,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_instances)) {
+       if (unlikely(atomic_read(&user->inotify_devs) >=
+                       inotify_max_user_instances)) {
                ret = -EMFILE;
                goto out_err;
        }
@@ -894,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);
@@ -907,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);
@@ -919,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;
        }
@@ -977,7 +973,7 @@ out:
        up(&dev->sem);
        up(&inode->inotify_sem);
 fput_and_out:
-       fput(filp);
+       fput_light(filp, fput_needed);
        return ret;
 }
 
@@ -985,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;
 }
 
@@ -1010,11 +1007,11 @@ 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);
@@ -1032,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);