X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=fs%2Finotify.c;h=2fd97ef547ffcac2b35a3bcee5a37667b8e51ef4;hb=8191151d0933d65fb6b659ffbd765479f0f200e1;hp=a87926584cd284c9aa1d94230cc2a659dc2d86db;hpb=b680716ed28baf549f777fb125fc23ba975985c5;p=linux-2.6 diff --git a/fs/inotify.c b/fs/inotify.c index a87926584c..2fd97ef547 100644 --- a/fs/inotify.c +++ b/fs/inotify.c @@ -37,6 +37,7 @@ #include static atomic_t inotify_cookie; +static atomic_t inotify_watches; static kmem_cache_t *watch_cachep; static kmem_cache_t *event_cachep; @@ -90,6 +91,7 @@ struct inotify_device { 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 */ + u32 last_wd; /* the last wd allocated */ }; /* @@ -352,7 +354,7 @@ static int inotify_dev_get_wd(struct inotify_device *dev, do { if (unlikely(!idr_pre_get(&dev->idr, GFP_KERNEL))) return -ENOSPC; - ret = idr_get_new(&dev->idr, watch, &watch->wd); + ret = idr_get_new_above(&dev->idr, watch, dev->last_wd+1, &watch->wd); } while (ret == -EAGAIN); return ret; @@ -401,6 +403,7 @@ static struct inotify_watch *create_watch(struct inotify_device *dev, return ERR_PTR(ret); } + dev->last_wd = watch->wd; watch->mask = mask; atomic_set(&watch->count, 0); INIT_LIST_HEAD(&watch->d_list); @@ -420,6 +423,7 @@ static struct inotify_watch *create_watch(struct inotify_device *dev, get_inotify_watch(watch); atomic_inc(&dev->user->inotify_watches); + atomic_inc(&inotify_watches); return watch; } @@ -452,6 +456,7 @@ static void remove_watch_no_event(struct inotify_watch *watch, list_del(&watch->d_list); atomic_dec(&dev->user->inotify_watches); + atomic_dec(&inotify_watches); idr_remove(&dev->idr, watch->wd); put_inotify_watch(watch); } @@ -530,6 +535,9 @@ void inotify_dentry_parent_queue_event(struct dentry *dentry, u32 mask, struct dentry *parent; struct inode *inode; + if (!atomic_read (&inotify_watches)) + return; + spin_lock(&dentry->d_lock); parent = dentry->d_parent; inode = parent->d_inode; @@ -865,23 +873,21 @@ asmlinkage long sys_inotify_init(void) filp = get_empty_filp(); if (!filp) { - put_unused_fd(fd); ret = -ENFILE; - goto out; + goto out_put_fd; } user = get_uid(current->user); - if (unlikely(atomic_read(&user->inotify_devs) >= inotify_max_user_instances)) { ret = -EMFILE; - goto out_err; + goto out_free_uid; } dev = kmalloc(sizeof(struct inotify_device), GFP_KERNEL); if (unlikely(!dev)) { ret = -ENOMEM; - goto out_err; + goto out_free_uid; } filp->f_op = &inotify_fops; @@ -901,6 +907,7 @@ asmlinkage long sys_inotify_init(void) dev->queue_size = 0; dev->max_events = inotify_max_queued_events; dev->user = user; + dev->last_wd = 0; atomic_set(&dev->count, 0); get_inotify_dev(dev); @@ -908,11 +915,11 @@ asmlinkage long sys_inotify_init(void) fd_install(fd, filp); return fd; -out_err: - put_unused_fd (fd); - put_filp (filp); +out_free_uid: free_uid(user); -out: + put_filp(filp); +out_put_fd: + put_unused_fd(fd); return ret; } @@ -923,12 +930,18 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) 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; + /* verify that this is indeed an inotify instance */ + if (unlikely(filp->f_op != &inotify_fops)) { + ret = -EINVAL; + goto fput_and_out; + } + ret = find_inode(path, &nd); if (unlikely(ret)) goto fput_and_out; @@ -969,11 +982,11 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) list_add(&watch->i_list, &inode->inotify_watches); ret = watch->wd; out: - path_release (&nd); up(&dev->sem); up(&inode->inotify_sem); + path_release(&nd); fput_and_out: - fput(filp); + fput_light(filp, fput_needed); return ret; } @@ -981,15 +994,23 @@ 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; + + /* verify that this is indeed an inotify instance */ + if (unlikely(filp->f_op != &inotify_fops)) { + ret = -EINVAL; + goto out; + } + dev = filp->private_data; ret = inotify_ignore(dev, wd); - fput(filp); +out: + fput_light(filp, fput_needed); return ret; } @@ -1013,14 +1034,22 @@ static struct file_system_type inotify_fs_type = { */ static int __init inotify_setup(void) { - register_filesystem(&inotify_fs_type); + int ret; + + ret = register_filesystem(&inotify_fs_type); + if (unlikely(ret)) + panic("inotify: register_filesystem returned %d!\n", ret); + inotify_mnt = kern_mount(&inotify_fs_type); + if (IS_ERR(inotify_mnt)) + panic("inotify: kern_mount ret %ld!\n", PTR_ERR(inotify_mnt)); - inotify_max_queued_events = 8192; - inotify_max_user_instances = 8; + inotify_max_queued_events = 16384; + inotify_max_user_instances = 128; inotify_max_user_watches = 8192; atomic_set(&inotify_cookie, 0); + atomic_set(&inotify_watches, 0); watch_cachep = kmem_cache_create("inotify_watch_cache", sizeof(struct inotify_watch),