aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/mark.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/notify/mark.c')
-rw-r--r--fs/notify/mark.c50
1 files changed, 22 insertions, 28 deletions
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index fc6b49bf7360..923fe4a5f503 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -20,28 +20,29 @@
20 * fsnotify inode mark locking/lifetime/and refcnting 20 * fsnotify inode mark locking/lifetime/and refcnting
21 * 21 *
22 * REFCNT: 22 * REFCNT:
23 * The mark->refcnt tells how many "things" in the kernel currently are 23 * The group->recnt and mark->refcnt tell how many "things" in the kernel
24 * referencing this object. The object typically will live inside the kernel 24 * currently are referencing the objects. Both kind of objects typically will
25 * with a refcnt of 2, one for each list it is on (i_list, g_list). Any task 25 * live inside the kernel with a refcnt of 2, one for its creation and one for
26 * which can find this object holding the appropriete locks, can take a reference 26 * the reference a group and a mark hold to each other.
27 * and the object itself is guaranteed to survive until the reference is dropped. 27 * If you are holding the appropriate locks, you can take a reference and the
28 * object itself is guaranteed to survive until the reference is dropped.
28 * 29 *
29 * LOCKING: 30 * LOCKING:
30 * There are 3 spinlocks involved with fsnotify inode marks and they MUST 31 * There are 3 locks involved with fsnotify inode marks and they MUST be taken
31 * be taken in order as follows: 32 * in order as follows:
32 * 33 *
34 * group->mark_mutex
33 * mark->lock 35 * mark->lock
34 * group->mark_lock
35 * inode->i_lock 36 * inode->i_lock
36 * 37 *
37 * mark->lock protects 2 things, mark->group and mark->inode. You must hold 38 * group->mark_mutex protects the marks_list anchored inside a given group and
38 * that lock to dereference either of these things (they could be NULL even with 39 * each mark is hooked via the g_list. It also protects the groups private
39 * the lock) 40 * data (i.e group limits).
40 * 41
41 * group->mark_lock protects the marks_list anchored inside a given group 42 * mark->lock protects the marks attributes like its masks and flags.
42 * and each mark is hooked via the g_list. It also sorta protects the 43 * Furthermore it protects the access to a reference of the group that the mark
43 * free_g_list, which when used is anchored by a private list on the stack of the 44 * is assigned to as well as the access to a reference of the inode/vfsmount
44 * task which held the group->mark_lock. 45 * that is being watched by the mark.
45 * 46 *
46 * inode->i_lock protects the i_fsnotify_marks list anchored inside a 47 * inode->i_lock protects the i_fsnotify_marks list anchored inside a
47 * given inode and each mark is hooked via the i_list. (and sorta the 48 * given inode and each mark is hooked via the i_list. (and sorta the
@@ -64,18 +65,11 @@
64 * inode. We take i_lock and walk the i_fsnotify_marks safely. For each 65 * inode. We take i_lock and walk the i_fsnotify_marks safely. For each
65 * mark on the list we take a reference (so the mark can't disappear under us). 66 * mark on the list we take a reference (so the mark can't disappear under us).
66 * We remove that mark form the inode's list of marks and we add this mark to a 67 * We remove that mark form the inode's list of marks and we add this mark to a
67 * private list anchored on the stack using i_free_list; At this point we no 68 * private list anchored on the stack using i_free_list; we walk i_free_list
68 * longer fear anything finding the mark using the inode's list of marks. 69 * and before we destroy the mark we make sure that we dont race with a
69 * 70 * concurrent destroy_group by getting a ref to the marks group and taking the
70 * We can safely and locklessly run the private list on the stack of everything 71 * groups mutex.
71 * we just unattached from the original inode. For each mark on the private list 72
72 * we grab the mark-> and can thus dereference mark->group and mark->inode. If
73 * we see the group and inode are not NULL we take those locks. Now holding all
74 * 3 locks we can completely remove the mark from other tasks finding it in the
75 * future. Remember, 10 things might already be referencing this mark, but they
76 * better be holding a ref. We drop our reference we took before we unhooked it
77 * from the inode. When the ref hits 0 we can free the mark.
78 *
79 * Very similarly for freeing by group, except we use free_g_list. 73 * Very similarly for freeing by group, except we use free_g_list.
80 * 74 *
81 * This has the very interesting property of being able to run concurrently with 75 * This has the very interesting property of being able to run concurrently with