]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/notify/inode_mark.c
fsnotify: rename mark_entry to just mark
[net-next-2.6.git] / fs / notify / inode_mark.c
index 0399bcbe09c83f02bdf1627b1dcfc6b12c316d5f..27c1b43ad739eb307f9a4e327a7624f2f96ec79a 100644 (file)
  * There are 3 spinlocks involved with fsnotify inode marks and they MUST
  * be taken in order as follows:
  *
- * entry->lock
+ * mark->lock
  * group->mark_lock
  * inode->i_lock
  *
- * entry->lock protects 2 things, entry->group and entry->inode.  You must hold
+ * mark->lock protects 2 things, mark->group and mark->inode.  You must hold
  * that lock to dereference either of these things (they could be NULL even with
  * the lock)
  *
- * group->mark_lock protects the mark_entries list anchored inside a given group
- * and each entry is hooked via the g_list.  It also sorta protects the
+ * group->mark_lock protects the marks_list anchored inside a given group
+ * and each mark is hooked via the g_list.  It also sorta protects the
  * free_g_list, which when used is anchored by a private list on the stack of the
  * task which held the group->mark_lock.
  *
- * inode->i_lock protects the i_fsnotify_mark_entries list anchored inside a
- * given inode and each entry is hooked via the i_list. (and sorta the
+ * inode->i_lock protects the i_fsnotify_marks list anchored inside a
+ * given inode and each mark is hooked via the i_list. (and sorta the
  * free_i_list)
  *
  *
  * - The inode is unlinked for the last time.  (fsnotify_inode_remove)
  * - The inode is being evicted from cache. (fsnotify_inode_delete)
  * - The fs the inode is on is unmounted.  (fsnotify_inode_delete/fsnotify_unmount_inodes)
- * - Something explicitly requests that it be removed.  (fsnotify_destroy_mark_by_entry)
+ * - Something explicitly requests that it be removed.  (fsnotify_destroy_mark)
  * - The fsnotify_group associated with the mark is going away and all such marks
  *   need to be cleaned up. (fsnotify_clear_marks_by_group)
  *
  * Worst case we are given an inode and need to clean up all the marks on that
- * inode.  We take i_lock and walk the i_fsnotify_mark_entries safely.  For each
+ * inode.  We take i_lock and walk the i_fsnotify_marks safely.  For each
  * mark on the list we take a reference (so the mark can't disappear under us).
  * We remove that mark form the inode's list of marks and we add this mark to a
  * private list anchored on the stack using i_free_list;  At this point we no
 #include <linux/fsnotify_backend.h>
 #include "fsnotify.h"
 
-void fsnotify_get_mark(struct fsnotify_mark_entry *entry)
+void fsnotify_get_mark(struct fsnotify_mark *mark)
 {
-       atomic_inc(&entry->refcnt);
+       atomic_inc(&mark->refcnt);
 }
 
-void fsnotify_put_mark(struct fsnotify_mark_entry *entry)
+void fsnotify_put_mark(struct fsnotify_mark *mark)
 {
-       if (atomic_dec_and_test(&entry->refcnt))
-               entry->free_mark(entry);
+       if (atomic_dec_and_test(&mark->refcnt))
+               mark->free_mark(mark);
 }
 
 /*
@@ -111,14 +111,14 @@ void fsnotify_put_mark(struct fsnotify_mark_entry *entry)
  */
 static void fsnotify_recalc_inode_mask_locked(struct inode *inode)
 {
-       struct fsnotify_mark_entry *entry;
+       struct fsnotify_mark *mark;
        struct hlist_node *pos;
        __u32 new_mask = 0;
 
        assert_spin_locked(&inode->i_lock);
 
-       hlist_for_each_entry(entry, pos, &inode->i_fsnotify_mark_entries, i_list)
-               new_mask |= entry->mask;
+       hlist_for_each_entry(mark, pos, &inode->i_fsnotify_marks, i.i_list)
+               new_mask |= mark->mask;
        inode->i_fsnotify_mask = new_mask;
 }
 
@@ -138,43 +138,43 @@ void fsnotify_recalc_inode_mask(struct inode *inode)
 /*
  * Any time a mark is getting freed we end up here.
  * The caller had better be holding a reference to this mark so we don't actually
- * do the final put under the entry->lock
+ * do the final put under the mark->lock
  */
-void fsnotify_destroy_mark_by_entry(struct fsnotify_mark_entry *entry)
+void fsnotify_destroy_mark(struct fsnotify_mark *mark)
 {
        struct fsnotify_group *group;
        struct inode *inode;
 
-       spin_lock(&entry->lock);
+       spin_lock(&mark->lock);
 
-       group = entry->group;
-       inode = entry->inode;
+       group = mark->group;
+       inode = mark->i.inode;
 
        BUG_ON(group && !inode);
        BUG_ON(!group && inode);
 
        /* if !group something else already marked this to die */
        if (!group) {
-               spin_unlock(&entry->lock);
+               spin_unlock(&mark->lock);
                return;
        }
 
        /* 1 from caller and 1 for being on i_list/g_list */
-       BUG_ON(atomic_read(&entry->refcnt) < 2);
+       BUG_ON(atomic_read(&mark->refcnt) < 2);
 
        spin_lock(&group->mark_lock);
        spin_lock(&inode->i_lock);
 
-       hlist_del_init(&entry->i_list);
-       entry->inode = NULL;
+       hlist_del_init(&mark->i.i_list);
+       mark->i.inode = NULL;
 
-       list_del_init(&entry->g_list);
-       entry->group = NULL;
+       list_del_init(&mark->g_list);
+       mark->group = NULL;
 
-       fsnotify_put_mark(entry); /* for i_list and g_list */
+       fsnotify_put_mark(mark); /* for i_list and g_list */
 
        /*
-        * this mark is now off the inode->i_fsnotify_mark_entries list and we
+        * this mark is now off the inode->i_fsnotify_marks list and we
         * hold the inode->i_lock, so this is the perfect time to update the
         * inode->i_fsnotify_mask
         */
@@ -182,21 +182,21 @@ void fsnotify_destroy_mark_by_entry(struct fsnotify_mark_entry *entry)
 
        spin_unlock(&inode->i_lock);
        spin_unlock(&group->mark_lock);
-       spin_unlock(&entry->lock);
+       spin_unlock(&mark->lock);
 
        /*
         * Some groups like to know that marks are being freed.  This is a
-        * callback to the group function to let it know that this entry
+        * callback to the group function to let it know that this mark
         * is being freed.
         */
        if (group->ops->freeing_mark)
-               group->ops->freeing_mark(entry, group);
+               group->ops->freeing_mark(mark, group);
 
        /*
         * __fsnotify_update_child_dentry_flags(inode);
         *
         * I really want to call that, but we can't, we have no idea if the inode
-        * still exists the second we drop the entry->lock.
+        * still exists the second we drop the mark->lock.
         *
         * The next time an event arrive to this inode from one of it's children
         * __fsnotify_parent will see that the inode doesn't care about it's
@@ -221,20 +221,20 @@ void fsnotify_destroy_mark_by_entry(struct fsnotify_mark_entry *entry)
  */
 void fsnotify_clear_marks_by_group(struct fsnotify_group *group)
 {
-       struct fsnotify_mark_entry *lentry, *entry;
+       struct fsnotify_mark *lmark, *mark;
        LIST_HEAD(free_list);
 
        spin_lock(&group->mark_lock);
-       list_for_each_entry_safe(entry, lentry, &group->mark_entries, g_list) {
-               list_add(&entry->free_g_list, &free_list);
-               list_del_init(&entry->g_list);
-               fsnotify_get_mark(entry);
+       list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
+               list_add(&mark->free_g_list, &free_list);
+               list_del_init(&mark->g_list);
+               fsnotify_get_mark(mark);
        }
        spin_unlock(&group->mark_lock);
 
-       list_for_each_entry_safe(entry, lentry, &free_list, free_g_list) {
-               fsnotify_destroy_mark_by_entry(entry);
-               fsnotify_put_mark(entry);
+       list_for_each_entry_safe(mark, lmark, &free_list, free_g_list) {
+               fsnotify_destroy_mark(mark);
+               fsnotify_put_mark(mark);
        }
 }
 
@@ -243,21 +243,21 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group)
  */
 void fsnotify_clear_marks_by_inode(struct inode *inode)
 {
-       struct fsnotify_mark_entry *entry, *lentry;
+       struct fsnotify_mark *mark, *lmark;
        struct hlist_node *pos, *n;
        LIST_HEAD(free_list);
 
        spin_lock(&inode->i_lock);
-       hlist_for_each_entry_safe(entry, pos, n, &inode->i_fsnotify_mark_entries, i_list) {
-               list_add(&entry->free_i_list, &free_list);
-               hlist_del_init(&entry->i_list);
-               fsnotify_get_mark(entry);
+       hlist_for_each_entry_safe(mark, pos, n, &inode->i_fsnotify_marks, i.i_list) {
+               list_add(&mark->i.free_i_list, &free_list);
+               hlist_del_init(&mark->i.i_list);
+               fsnotify_get_mark(mark);
        }
        spin_unlock(&inode->i_lock);
 
-       list_for_each_entry_safe(entry, lentry, &free_list, free_i_list) {
-               fsnotify_destroy_mark_by_entry(entry);
-               fsnotify_put_mark(entry);
+       list_for_each_entry_safe(mark, lmark, &free_list, i.free_i_list) {
+               fsnotify_destroy_mark(mark);
+               fsnotify_put_mark(mark);
        }
 }
 
@@ -265,73 +265,99 @@ void fsnotify_clear_marks_by_inode(struct inode *inode)
  * given a group and inode, find the mark associated with that combination.
  * if found take a reference to that mark and return it, else return NULL
  */
-struct fsnotify_mark_entry *fsnotify_find_mark_entry(struct fsnotify_group *group,
-                                                    struct inode *inode)
+struct fsnotify_mark *fsnotify_find_mark(struct fsnotify_group *group,
+                                        struct inode *inode)
 {
-       struct fsnotify_mark_entry *entry;
+       struct fsnotify_mark *mark;
        struct hlist_node *pos;
 
        assert_spin_locked(&inode->i_lock);
 
-       hlist_for_each_entry(entry, pos, &inode->i_fsnotify_mark_entries, i_list) {
-               if (entry->group == group) {
-                       fsnotify_get_mark(entry);
-                       return entry;
+       hlist_for_each_entry(mark, pos, &inode->i_fsnotify_marks, i.i_list) {
+               if (mark->group == group) {
+                       fsnotify_get_mark(mark);
+                       return mark;
                }
        }
        return NULL;
 }
 
+void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old)
+{
+       assert_spin_locked(&old->lock);
+       new->i.inode = old->i.inode;
+       new->group = old->group;
+       new->mask = old->mask;
+       new->free_mark = old->free_mark;
+}
+
 /*
  * Nothing fancy, just initialize lists and locks and counters.
  */
-void fsnotify_init_mark(struct fsnotify_mark_entry *entry,
-                       void (*free_mark)(struct fsnotify_mark_entry *entry))
-
+void fsnotify_init_mark(struct fsnotify_mark *mark,
+                       void (*free_mark)(struct fsnotify_mark *mark))
 {
-       spin_lock_init(&entry->lock);
-       atomic_set(&entry->refcnt, 1);
-       INIT_HLIST_NODE(&entry->i_list);
-       entry->group = NULL;
-       entry->mask = 0;
-       entry->inode = NULL;
-       entry->free_mark = free_mark;
+       spin_lock_init(&mark->lock);
+       atomic_set(&mark->refcnt, 1);
+       INIT_HLIST_NODE(&mark->i.i_list);
+       mark->group = NULL;
+       mark->mask = 0;
+       mark->i.inode = NULL;
+       mark->free_mark = free_mark;
 }
 
 /*
- * Attach an initialized mark entry to a given group and inode.
+ * Attach an initialized mark mark to a given group and inode.
  * These marks may be used for the fsnotify backend to determine which
  * event types should be delivered to which group and for which inodes.
  */
-int fsnotify_add_mark(struct fsnotify_mark_entry *entry,
-                     struct fsnotify_group *group, struct inode *inode)
+int fsnotify_add_mark(struct fsnotify_mark *mark,
+                     struct fsnotify_group *group, struct inode *inode,
+                     int allow_dups)
 {
-       struct fsnotify_mark_entry *lentry;
+       struct fsnotify_mark *lmark = NULL;
        int ret = 0;
 
        inode = igrab(inode);
        if (unlikely(!inode))
                return -EINVAL;
 
+       mark->flags = FSNOTIFY_MARK_FLAG_INODE;
+
+       /*
+        * if this group isn't being testing for inode type events we need
+        * to start testing
+        */
+       if (unlikely(list_empty(&group->inode_group_list)))
+               fsnotify_add_inode_group(group);
+       /*
+        * XXX This is where we could also do the fsnotify_add_vfsmount_group
+        * if we are setting and vfsmount mark....
+
+       if (unlikely(list_empty(&group->vfsmount_group_list)))
+               fsnotify_add_vfsmount_group(group);
+        */
+
        /*
         * LOCKING ORDER!!!!
-        * entry->lock
+        * mark->lock
         * group->mark_lock
         * inode->i_lock
         */
-       spin_lock(&entry->lock);
+       spin_lock(&mark->lock);
        spin_lock(&group->mark_lock);
        spin_lock(&inode->i_lock);
 
-       lentry = fsnotify_find_mark_entry(group, inode);
-       if (!lentry) {
-               entry->group = group;
-               entry->inode = inode;
+       if (!allow_dups)
+               lmark = fsnotify_find_mark(group, inode);
+       if (!lmark) {
+               mark->group = group;
+               mark->i.inode = inode;
 
-               hlist_add_head(&entry->i_list, &inode->i_fsnotify_mark_entries);
-               list_add(&entry->g_list, &group->mark_entries);
+               hlist_add_head(&mark->i.i_list, &inode->i_fsnotify_marks);
+               list_add(&mark->g_list, &group->marks_list);
 
-               fsnotify_get_mark(entry); /* for i_list and g_list */
+               fsnotify_get_mark(mark); /* for i_list and g_list */
 
                atomic_inc(&group->num_marks);
 
@@ -340,12 +366,12 @@ int fsnotify_add_mark(struct fsnotify_mark_entry *entry,
 
        spin_unlock(&inode->i_lock);
        spin_unlock(&group->mark_lock);
-       spin_unlock(&entry->lock);
+       spin_unlock(&mark->lock);
 
-       if (lentry) {
+       if (lmark) {
                ret = -EEXIST;
                iput(inode);
-               fsnotify_put_mark(lentry);
+               fsnotify_put_mark(lmark);
        } else {
                __fsnotify_update_child_dentry_flags(inode);
        }