#include <linux/idr.h>
#include <linux/slab.h>
#include <linux/fs.h>
+#include <linux/sched.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/writeback.h>
}
/*
- * 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.
*/
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, NULL);
}
+EXPORT_SYMBOL_GPL(inotify_remove_watch_locked);
/* Kernel API for producing events */
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
mutex_lock(&ih->mutex);
ih->in_ops->handle_event(watch, watch->wd, IN_UNMOUNT, 0,
NULL, NULL);
- remove_watch(watch, ih);
+ inotify_remove_watch_locked(ih, watch);
mutex_unlock(&ih->mutex);
}
mutex_unlock(&inode->inotify_mutex);
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);
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);
EXPORT_SYMBOL_GPL(inotify_add_watch);
/**
+ * inotify_clone_watch - put the watch next to existing one
+ * @old: already installed watch
+ * @new: new watch
+ *
+ * Caller must hold the inotify_mutex of inode we are dealing with;
+ * it is expected to remove the old watch before unlocking the inode.
+ */
+s32 inotify_clone_watch(struct inotify_watch *old, struct inotify_watch *new)
+{
+ struct inotify_handle *ih = old->ih;
+ int ret = 0;
+
+ new->mask = old->mask;
+ new->ih = ih;
+
+ mutex_lock(&ih->mutex);
+
+ /* Initialize a new watch */
+ ret = inotify_handle_get_wd(ih, new);
+ if (unlikely(ret))
+ goto out;
+ ret = new->wd;
+
+ get_inotify_handle(ih);
+
+ new->inode = igrab(old->inode);
+
+ list_add(&new->h_list, &ih->watches);
+ list_add(&new->i_list, &old->inode->inotify_watches);
+out:
+ mutex_unlock(&ih->mutex);
+ return ret;
+}
+
+void inotify_evict_watch(struct inotify_watch *watch)
+{
+ get_inotify_watch(watch);
+ mutex_lock(&watch->ih->mutex);
+ inotify_remove_watch_locked(watch->ih, watch);
+ mutex_unlock(&watch->ih->mutex);
+}
+
+/**
* inotify_rm_wd - remove a watch from an inotify instance
* @ih: inotify handle
* @wd: watch descriptor to remove
/* 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);