X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Finotify.c;h=2fecb7af4a77d6316171f0e25a40fd9027a71647;hb=eeac8047fcf4c659eb15f2e27a0ef4aeba64157f;hp=27ebcac5e07ff8f67afe7594d25aa5d384814951;hpb=b9c55d29e9fced1eb1b4c252b2efd4b55a0c3c7f;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/inotify.c b/fs/inotify.c index 27ebcac..2fecb7a 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; @@ -175,6 +176,7 @@ static inline void put_inotify_dev(struct inotify_device *dev) if (atomic_dec_and_test(&dev->count)) { atomic_dec(&dev->user->inotify_devs); free_uid(dev->user); + idr_destroy(&dev->idr); kfree(dev); } } @@ -353,7 +355,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_above(&dev->idr, watch, dev->last_wd, &watch->wd); + ret = idr_get_new_above(&dev->idr, watch, dev->last_wd+1, &watch->wd); } while (ret == -EAGAIN); return ret; @@ -362,15 +364,16 @@ static int inotify_dev_get_wd(struct inotify_device *dev, /* * find_inode - resolve a user-given path to a specific inode and return a nd */ -static int find_inode(const char __user *dirname, struct nameidata *nd) +static int find_inode(const char __user *dirname, struct nameidata *nd, + unsigned flags) { int error; - error = __user_walk(dirname, LOOKUP_FOLLOW, nd); + error = __user_walk(dirname, flags, nd); if (error) return error; /* you can only watch an inode if you have read permissions on it */ - error = permission(nd->dentry->d_inode, MAY_READ, NULL); + error = vfs_permission(nd, MAY_READ); if (error) path_release(nd); return error; @@ -402,7 +405,7 @@ static struct inotify_watch *create_watch(struct inotify_device *dev, return ERR_PTR(ret); } - dev->last_wd = ret; + dev->last_wd = watch->wd; watch->mask = mask; atomic_set(&watch->count, 0); INIT_LIST_HEAD(&watch->d_list); @@ -422,6 +425,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; } @@ -454,6 +458,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); } @@ -532,6 +537,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; @@ -925,6 +933,8 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) struct nameidata nd; struct file *filp; int ret, fput_needed; + int mask_add = 0; + unsigned flags = 0; filp = fget_light(fd, &fput_needed); if (unlikely(!filp)) @@ -936,7 +946,12 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) goto fput_and_out; } - ret = find_inode(path, &nd); + if (!(mask & IN_DONT_FOLLOW)) + flags |= LOOKUP_FOLLOW; + if (mask & IN_ONLYDIR) + flags |= LOOKUP_DIRECTORY; + + ret = find_inode(path, &nd, flags); if (unlikely(ret)) goto fput_and_out; @@ -947,6 +962,9 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) down(&inode->inotify_sem); down(&dev->sem); + if (mask & IN_MASK_ADD) + mask_add = 1; + /* don't let user-space set invalid bits: we don't want flags set */ mask &= IN_ALL_EVENTS; if (unlikely(!mask)) { @@ -960,7 +978,10 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) */ old = inode_find_dev(inode, dev); if (unlikely(old)) { - old->mask = mask; + if (mask_add) + old->mask |= mask; + else + old->mask = mask; ret = old->wd; goto out; } @@ -1043,6 +1064,7 @@ static int __init inotify_setup(void) 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),