X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;ds=sidebyside;f=fs%2Finotify.c;h=7457501b95656087cfe27339b94d3bace7585782;hb=99f9f3d49cbc7d944476f6fde53a77ec789ab2aa;hp=a1bedf3975ca74077c7edc30aad0ac918841868a;hpb=2d9048e201bfb67ba21f05e647b1286b8a4a5667;p=mv-sheeva.git diff --git a/fs/inotify.c b/fs/inotify.c index a1bedf3975c..7457501b956 100644 --- a/fs/inotify.c +++ b/fs/inotify.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -207,7 +208,7 @@ static struct inotify_watch *inode_find_handle(struct inode *inode, } /* - * remove_watch_no_event - remove_watch() without the IN_IGNORED event. + * remove_watch_no_event - remove watch without the IN_IGNORED event. * * Callers must hold both inode->inotify_mutex and ih->mutex. */ @@ -223,17 +224,22 @@ static void remove_watch_no_event(struct inotify_watch *watch, idr_remove(&ih->idr, watch->wd); } -/* - * remove_watch - Remove a watch from both the handle and the inode. Sends - * the IN_IGNORED event signifying that the inode is no longer watched. +/** + * inotify_remove_watch_locked - Remove a watch from both the handle and the + * inode. Sends the IN_IGNORED event signifying that the inode is no longer + * watched. May be invoked from a caller's event handler. + * @ih: inotify handle associated with watch + * @watch: watch to remove * * Callers must hold both inode->inotify_mutex and ih->mutex. */ -static void remove_watch(struct inotify_watch *watch, struct inotify_handle *ih) +void inotify_remove_watch_locked(struct inotify_handle *ih, + struct inotify_watch *watch) { remove_watch_no_event(watch, ih); - ih->in_ops->handle_event(watch, watch->wd, IN_IGNORED, 0, NULL); + ih->in_ops->handle_event(watch, watch->wd, IN_IGNORED, 0, NULL, NULL); } +EXPORT_SYMBOL_GPL(inotify_remove_watch_locked); /* Kernel API for producing events */ @@ -275,9 +281,10 @@ void inotify_d_move(struct dentry *entry) * @mask: event mask describing this event * @cookie: cookie for synchronization, or zero * @name: filename, if any + * @n_inode: inode associated with name */ void inotify_inode_queue_event(struct inode *inode, u32 mask, u32 cookie, - const char *name) + const char *name, struct inode *n_inode) { struct inotify_watch *watch, *next; @@ -292,7 +299,8 @@ void inotify_inode_queue_event(struct inode *inode, u32 mask, u32 cookie, mutex_lock(&ih->mutex); if (watch_mask & IN_ONESHOT) remove_watch_no_event(watch, ih); - ih->in_ops->handle_event(watch, watch->wd, mask, cookie, name); + ih->in_ops->handle_event(watch, watch->wd, mask, cookie, + name, n_inode); mutex_unlock(&ih->mutex); } } @@ -323,7 +331,8 @@ void inotify_dentry_parent_queue_event(struct dentry *dentry, u32 mask, if (inotify_inode_watched(inode)) { dget(parent); spin_unlock(&dentry->d_lock); - inotify_inode_queue_event(inode, mask, cookie, name); + inotify_inode_queue_event(inode, mask, cookie, name, + dentry->d_inode); dput(parent); } else spin_unlock(&dentry->d_lock); @@ -375,7 +384,7 @@ void inotify_unmount_inodes(struct list_head *list) need_iput_tmp = need_iput; need_iput = NULL; - /* In case the remove_watch() drops a reference. */ + /* In case inotify_remove_watch_locked() drops a reference. */ if (inode != need_iput_tmp) __iget(inode); else @@ -407,8 +416,8 @@ void inotify_unmount_inodes(struct list_head *list) struct inotify_handle *ih= watch->ih; mutex_lock(&ih->mutex); ih->in_ops->handle_event(watch, watch->wd, IN_UNMOUNT, 0, - NULL); - remove_watch(watch, ih); + NULL, NULL); + inotify_remove_watch_locked(ih, watch); mutex_unlock(&ih->mutex); } mutex_unlock(&inode->inotify_mutex); @@ -431,7 +440,7 @@ void inotify_inode_is_dead(struct inode *inode) list_for_each_entry_safe(watch, next, &inode->inotify_watches, i_list) { struct inotify_handle *ih = watch->ih; mutex_lock(&ih->mutex); - remove_watch(watch, ih); + inotify_remove_watch_locked(ih, watch); mutex_unlock(&ih->mutex); } mutex_unlock(&inode->inotify_mutex); @@ -464,6 +473,19 @@ struct inotify_handle *inotify_init(const struct inotify_operations *ops) } EXPORT_SYMBOL_GPL(inotify_init); +/** + * inotify_init_watch - initialize an inotify watch + * @watch: watch to initialize + */ +void inotify_init_watch(struct inotify_watch *watch) +{ + INIT_LIST_HEAD(&watch->h_list); + INIT_LIST_HEAD(&watch->i_list); + atomic_set(&watch->count, 0); + get_inotify_watch(watch); /* initial get */ +} +EXPORT_SYMBOL_GPL(inotify_init_watch); + /** * inotify_destroy - clean up and destroy an inotify instance * @ih: inotify handle @@ -487,7 +509,7 @@ void inotify_destroy(struct inotify_handle *ih) mutex_unlock(&ih->mutex); break; } - watch = list_entry(watches->next, struct inotify_watch, h_list); + watch = list_first_entry(watches, struct inotify_watch, h_list); get_inotify_watch(watch); mutex_unlock(&ih->mutex); @@ -511,6 +533,37 @@ void inotify_destroy(struct inotify_handle *ih) } EXPORT_SYMBOL_GPL(inotify_destroy); +/** + * inotify_find_watch - find an existing watch for an (ih,inode) pair + * @ih: inotify handle + * @inode: inode to watch + * @watchp: pointer to existing inotify_watch + * + * Caller must pin given inode (via nameidata). + */ +s32 inotify_find_watch(struct inotify_handle *ih, struct inode *inode, + struct inotify_watch **watchp) +{ + struct inotify_watch *old; + int ret = -ENOENT; + + mutex_lock(&inode->inotify_mutex); + mutex_lock(&ih->mutex); + + old = inode_find_handle(inode, ih); + if (unlikely(old)) { + get_inotify_watch(old); /* caller must put watch */ + *watchp = old; + ret = old->wd; + } + + mutex_unlock(&ih->mutex); + mutex_unlock(&inode->inotify_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(inotify_find_watch); + /** * inotify_find_update_watch - find and update the mask of an existing watch * @ih: inotify handle @@ -590,10 +643,6 @@ s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch, goto out; ret = watch->wd; - atomic_set(&watch->count, 0); - INIT_LIST_HEAD(&watch->h_list); - INIT_LIST_HEAD(&watch->i_list); - /* save a reference to handle and bump the count to make it official */ get_inotify_handle(ih); watch->ih = ih; @@ -604,8 +653,6 @@ s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch, */ watch->inode = igrab(inode); - get_inotify_watch(watch); /* initial get */ - if (!inotify_inode_watched(inode)) set_dentry_child_flags(inode, 1); @@ -646,7 +693,7 @@ int inotify_rm_wd(struct inotify_handle *ih, u32 wd) /* make sure that we did not race */ if (likely(idr_find(&ih->idr, wd) == watch)) - remove_watch(watch, ih); + inotify_remove_watch_locked(ih, watch); mutex_unlock(&ih->mutex); mutex_unlock(&inode->inotify_mutex); @@ -656,6 +703,20 @@ int inotify_rm_wd(struct inotify_handle *ih, u32 wd) } EXPORT_SYMBOL_GPL(inotify_rm_wd); +/** + * inotify_rm_watch - remove a watch from an inotify instance + * @ih: inotify handle + * @watch: watch to remove + * + * Can sleep. + */ +int inotify_rm_watch(struct inotify_handle *ih, + struct inotify_watch *watch) +{ + return inotify_rm_wd(ih, watch->wd); +} +EXPORT_SYMBOL_GPL(inotify_rm_watch); + /* * inotify_setup - core initialization function */