aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2014-12-12 19:58:36 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-13 15:42:53 -0500
commit0809ab69a2782afac8c4d7f3d35cd123050aab9a (patch)
tree373ed29c67e9ffd46a53d04e6fc68f4d96b6ba2d
parent820c12d5d6c0890bc93dd63893924a13041fdc35 (diff)
fsnotify: unify inode and mount marks handling
There's a lot of common code in inode and mount marks handling. Factor it out to a common helper function. Signed-off-by: Jan Kara <jack@suse.cz> Cc: Eric Paris <eparis@redhat.com> Cc: Heinrich Schuchardt <xypron.glpk@gmx.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/notify/dnotify/dnotify.c4
-rw-r--r--fs/notify/fdinfo.c6
-rw-r--r--fs/notify/fsnotify.c4
-rw-r--r--fs/notify/fsnotify.h12
-rw-r--r--fs/notify/inode_mark.c113
-rw-r--r--fs/notify/inotify/inotify_fsnotify.c2
-rw-r--r--fs/notify/inotify/inotify_user.c10
-rw-r--r--fs/notify/mark.c89
-rw-r--r--fs/notify/vfsmount_mark.c109
-rw-r--r--include/linux/fsnotify_backend.h24
-rw-r--r--kernel/audit_tree.c16
11 files changed, 160 insertions, 229 deletions
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index caaaf9dfe353..44523f4a6084 100644
--- a/fs/notify/dnotify/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -69,8 +69,8 @@ static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark)
69 if (old_mask == new_mask) 69 if (old_mask == new_mask)
70 return; 70 return;
71 71
72 if (fsn_mark->i.inode) 72 if (fsn_mark->inode)
73 fsnotify_recalc_inode_mask(fsn_mark->i.inode); 73 fsnotify_recalc_inode_mask(fsn_mark->inode);
74} 74}
75 75
76/* 76/*
diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c
index 6ffd220eb14d..58b7cdb63da9 100644
--- a/fs/notify/fdinfo.c
+++ b/fs/notify/fdinfo.c
@@ -80,7 +80,7 @@ static void inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
80 return; 80 return;
81 81
82 inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark); 82 inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark);
83 inode = igrab(mark->i.inode); 83 inode = igrab(mark->inode);
84 if (inode) { 84 if (inode) {
85 seq_printf(m, "inotify wd:%x ino:%lx sdev:%x mask:%x ignored_mask:%x ", 85 seq_printf(m, "inotify wd:%x ino:%lx sdev:%x mask:%x ignored_mask:%x ",
86 inode_mark->wd, inode->i_ino, inode->i_sb->s_dev, 86 inode_mark->wd, inode->i_ino, inode->i_sb->s_dev,
@@ -112,7 +112,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
112 mflags |= FAN_MARK_IGNORED_SURV_MODIFY; 112 mflags |= FAN_MARK_IGNORED_SURV_MODIFY;
113 113
114 if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { 114 if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) {
115 inode = igrab(mark->i.inode); 115 inode = igrab(mark->inode);
116 if (!inode) 116 if (!inode)
117 return; 117 return;
118 seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ", 118 seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ",
@@ -122,7 +122,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
122 seq_putc(m, '\n'); 122 seq_putc(m, '\n');
123 iput(inode); 123 iput(inode);
124 } else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) { 124 } else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) {
125 struct mount *mnt = real_mount(mark->m.mnt); 125 struct mount *mnt = real_mount(mark->mnt);
126 126
127 seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n", 127 seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n",
128 mnt->mnt_id, mflags, mark->mask, mark->ignored_mask); 128 mnt->mnt_id, mflags, mark->mask, mark->ignored_mask);
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 41e39102743a..dd3fb0b17be7 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -242,13 +242,13 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
242 242
243 if (inode_node) { 243 if (inode_node) {
244 inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu), 244 inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu),
245 struct fsnotify_mark, i.i_list); 245 struct fsnotify_mark, obj_list);
246 inode_group = inode_mark->group; 246 inode_group = inode_mark->group;
247 } 247 }
248 248
249 if (vfsmount_node) { 249 if (vfsmount_node) {
250 vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu), 250 vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu),
251 struct fsnotify_mark, m.m_list); 251 struct fsnotify_mark, obj_list);
252 vfsmount_group = vfsmount_mark->group; 252 vfsmount_group = vfsmount_mark->group;
253 } 253 }
254 254
diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h
index 3b68b0ae0a97..13a00be516d2 100644
--- a/fs/notify/fsnotify.h
+++ b/fs/notify/fsnotify.h
@@ -12,12 +12,19 @@ extern void fsnotify_flush_notify(struct fsnotify_group *group);
12/* protects reads of inode and vfsmount marks list */ 12/* protects reads of inode and vfsmount marks list */
13extern struct srcu_struct fsnotify_mark_srcu; 13extern struct srcu_struct fsnotify_mark_srcu;
14 14
15/* Calculate mask of events for a list of marks */
16extern u32 fsnotify_recalc_mask(struct hlist_head *head);
17
15/* compare two groups for sorting of marks lists */ 18/* compare two groups for sorting of marks lists */
16extern int fsnotify_compare_groups(struct fsnotify_group *a, 19extern int fsnotify_compare_groups(struct fsnotify_group *a,
17 struct fsnotify_group *b); 20 struct fsnotify_group *b);
18 21
19extern void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *fsn_mark, 22extern void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *fsn_mark,
20 __u32 mask); 23 __u32 mask);
24/* Add mark to a proper place in mark list */
25extern int fsnotify_add_mark_list(struct hlist_head *head,
26 struct fsnotify_mark *mark,
27 int allow_dups);
21/* add a mark to an inode */ 28/* add a mark to an inode */
22extern int fsnotify_add_inode_mark(struct fsnotify_mark *mark, 29extern int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
23 struct fsnotify_group *group, struct inode *inode, 30 struct fsnotify_group *group, struct inode *inode,
@@ -31,6 +38,11 @@ extern int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
31extern void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark); 38extern void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark);
32/* inode specific destruction of a mark */ 39/* inode specific destruction of a mark */
33extern void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark); 40extern void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark);
41/* Destroy all marks in the given list */
42extern void fsnotify_destroy_marks(struct list_head *to_free);
43/* Find mark belonging to given group in the list of marks */
44extern struct fsnotify_mark *fsnotify_find_mark(struct hlist_head *head,
45 struct fsnotify_group *group);
34/* run the list of all marks associated with inode and flag them to be freed */ 46/* run the list of all marks associated with inode and flag them to be freed */
35extern void fsnotify_clear_marks_by_inode(struct inode *inode); 47extern void fsnotify_clear_marks_by_inode(struct inode *inode);
36/* run the list of all marks associated with vfsmount and flag them to be freed */ 48/* run the list of all marks associated with vfsmount and flag them to be freed */
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c
index dfbf5447eea4..3daf513ee99e 100644
--- a/fs/notify/inode_mark.c
+++ b/fs/notify/inode_mark.c
@@ -31,28 +31,13 @@
31#include "../internal.h" 31#include "../internal.h"
32 32
33/* 33/*
34 * Recalculate the mask of events relevant to a given inode locked.
35 */
36static void fsnotify_recalc_inode_mask_locked(struct inode *inode)
37{
38 struct fsnotify_mark *mark;
39 __u32 new_mask = 0;
40
41 assert_spin_locked(&inode->i_lock);
42
43 hlist_for_each_entry(mark, &inode->i_fsnotify_marks, i.i_list)
44 new_mask |= mark->mask;
45 inode->i_fsnotify_mask = new_mask;
46}
47
48/*
49 * Recalculate the inode->i_fsnotify_mask, or the mask of all FS_* event types 34 * Recalculate the inode->i_fsnotify_mask, or the mask of all FS_* event types
50 * any notifier is interested in hearing for this inode. 35 * any notifier is interested in hearing for this inode.
51 */ 36 */
52void fsnotify_recalc_inode_mask(struct inode *inode) 37void fsnotify_recalc_inode_mask(struct inode *inode)
53{ 38{
54 spin_lock(&inode->i_lock); 39 spin_lock(&inode->i_lock);
55 fsnotify_recalc_inode_mask_locked(inode); 40 inode->i_fsnotify_mask = fsnotify_recalc_mask(&inode->i_fsnotify_marks);
56 spin_unlock(&inode->i_lock); 41 spin_unlock(&inode->i_lock);
57 42
58 __fsnotify_update_child_dentry_flags(inode); 43 __fsnotify_update_child_dentry_flags(inode);
@@ -60,23 +45,22 @@ void fsnotify_recalc_inode_mask(struct inode *inode)
60 45
61void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark) 46void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark)
62{ 47{
63 struct inode *inode = mark->i.inode; 48 struct inode *inode = mark->inode;
64 49
65 BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); 50 BUG_ON(!mutex_is_locked(&mark->group->mark_mutex));
66 assert_spin_locked(&mark->lock); 51 assert_spin_locked(&mark->lock);
67 52
68 spin_lock(&inode->i_lock); 53 spin_lock(&inode->i_lock);
69 54
70 hlist_del_init_rcu(&mark->i.i_list); 55 hlist_del_init_rcu(&mark->obj_list);
71 mark->i.inode = NULL; 56 mark->inode = NULL;
72 57
73 /* 58 /*
74 * this mark is now off the inode->i_fsnotify_marks list and we 59 * this mark is now off the inode->i_fsnotify_marks list and we
75 * hold the inode->i_lock, so this is the perfect time to update the 60 * hold the inode->i_lock, so this is the perfect time to update the
76 * inode->i_fsnotify_mask 61 * inode->i_fsnotify_mask
77 */ 62 */
78 fsnotify_recalc_inode_mask_locked(inode); 63 inode->i_fsnotify_mask = fsnotify_recalc_mask(&inode->i_fsnotify_marks);
79
80 spin_unlock(&inode->i_lock); 64 spin_unlock(&inode->i_lock);
81} 65}
82 66
@@ -85,30 +69,19 @@ void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark)
85 */ 69 */
86void fsnotify_clear_marks_by_inode(struct inode *inode) 70void fsnotify_clear_marks_by_inode(struct inode *inode)
87{ 71{
88 struct fsnotify_mark *mark, *lmark; 72 struct fsnotify_mark *mark;
89 struct hlist_node *n; 73 struct hlist_node *n;
90 LIST_HEAD(free_list); 74 LIST_HEAD(free_list);
91 75
92 spin_lock(&inode->i_lock); 76 spin_lock(&inode->i_lock);
93 hlist_for_each_entry_safe(mark, n, &inode->i_fsnotify_marks, i.i_list) { 77 hlist_for_each_entry_safe(mark, n, &inode->i_fsnotify_marks, obj_list) {
94 list_add(&mark->i.free_i_list, &free_list); 78 list_add(&mark->free_list, &free_list);
95 hlist_del_init_rcu(&mark->i.i_list); 79 hlist_del_init_rcu(&mark->obj_list);
96 fsnotify_get_mark(mark); 80 fsnotify_get_mark(mark);
97 } 81 }
98 spin_unlock(&inode->i_lock); 82 spin_unlock(&inode->i_lock);
99 83
100 list_for_each_entry_safe(mark, lmark, &free_list, i.free_i_list) { 84 fsnotify_destroy_marks(&free_list);
101 struct fsnotify_group *group;
102
103 spin_lock(&mark->lock);
104 fsnotify_get_group(mark->group);
105 group = mark->group;
106 spin_unlock(&mark->lock);
107
108 fsnotify_destroy_mark(mark, group);
109 fsnotify_put_mark(mark);
110 fsnotify_put_group(group);
111 }
112} 85}
113 86
114/* 87/*
@@ -123,34 +96,13 @@ void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group)
123 * given a group and inode, find the mark associated with that combination. 96 * given a group and inode, find the mark associated with that combination.
124 * if found take a reference to that mark and return it, else return NULL 97 * if found take a reference to that mark and return it, else return NULL
125 */ 98 */
126static struct fsnotify_mark *fsnotify_find_inode_mark_locked(
127 struct fsnotify_group *group,
128 struct inode *inode)
129{
130 struct fsnotify_mark *mark;
131
132 assert_spin_locked(&inode->i_lock);
133
134 hlist_for_each_entry(mark, &inode->i_fsnotify_marks, i.i_list) {
135 if (mark->group == group) {
136 fsnotify_get_mark(mark);
137 return mark;
138 }
139 }
140 return NULL;
141}
142
143/*
144 * given a group and inode, find the mark associated with that combination.
145 * if found take a reference to that mark and return it, else return NULL
146 */
147struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group, 99struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group,
148 struct inode *inode) 100 struct inode *inode)
149{ 101{
150 struct fsnotify_mark *mark; 102 struct fsnotify_mark *mark;
151 103
152 spin_lock(&inode->i_lock); 104 spin_lock(&inode->i_lock);
153 mark = fsnotify_find_inode_mark_locked(group, inode); 105 mark = fsnotify_find_mark(&inode->i_fsnotify_marks, group);
154 spin_unlock(&inode->i_lock); 106 spin_unlock(&inode->i_lock);
155 107
156 return mark; 108 return mark;
@@ -168,10 +120,10 @@ void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *mark,
168 assert_spin_locked(&mark->lock); 120 assert_spin_locked(&mark->lock);
169 121
170 if (mask && 122 if (mask &&
171 mark->i.inode && 123 mark->inode &&
172 !(mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) { 124 !(mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) {
173 mark->flags |= FSNOTIFY_MARK_FLAG_OBJECT_PINNED; 125 mark->flags |= FSNOTIFY_MARK_FLAG_OBJECT_PINNED;
174 inode = igrab(mark->i.inode); 126 inode = igrab(mark->inode);
175 /* 127 /*
176 * we shouldn't be able to get here if the inode wasn't 128 * we shouldn't be able to get here if the inode wasn't
177 * already safely held in memory. But bug in case it 129 * already safely held in memory. But bug in case it
@@ -192,9 +144,7 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
192 struct fsnotify_group *group, struct inode *inode, 144 struct fsnotify_group *group, struct inode *inode,
193 int allow_dups) 145 int allow_dups)
194{ 146{
195 struct fsnotify_mark *lmark, *last = NULL; 147 int ret;
196 int ret = 0;
197 int cmp;
198 148
199 mark->flags |= FSNOTIFY_MARK_FLAG_INODE; 149 mark->flags |= FSNOTIFY_MARK_FLAG_INODE;
200 150
@@ -202,37 +152,10 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
202 assert_spin_locked(&mark->lock); 152 assert_spin_locked(&mark->lock);
203 153
204 spin_lock(&inode->i_lock); 154 spin_lock(&inode->i_lock);
205 155 mark->inode = inode;
206 mark->i.inode = inode; 156 ret = fsnotify_add_mark_list(&inode->i_fsnotify_marks, mark,
207 157 allow_dups);
208 /* is mark the first mark? */ 158 inode->i_fsnotify_mask = fsnotify_recalc_mask(&inode->i_fsnotify_marks);
209 if (hlist_empty(&inode->i_fsnotify_marks)) {
210 hlist_add_head_rcu(&mark->i.i_list, &inode->i_fsnotify_marks);
211 goto out;
212 }
213
214 /* should mark be in the middle of the current list? */
215 hlist_for_each_entry(lmark, &inode->i_fsnotify_marks, i.i_list) {
216 last = lmark;
217
218 if ((lmark->group == group) && !allow_dups) {
219 ret = -EEXIST;
220 goto out;
221 }
222
223 cmp = fsnotify_compare_groups(lmark->group, mark->group);
224 if (cmp < 0)
225 continue;
226
227 hlist_add_before_rcu(&mark->i.i_list, &lmark->i.i_list);
228 goto out;
229 }
230
231 BUG_ON(last == NULL);
232 /* mark should be the last entry. last is the current last entry */
233 hlist_add_behind_rcu(&mark->i.i_list, &last->i.i_list);
234out:
235 fsnotify_recalc_inode_mask_locked(inode);
236 spin_unlock(&inode->i_lock); 159 spin_unlock(&inode->i_lock);
237 160
238 return ret; 161 return ret;
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index 7d888d77d59a..2cd900c2c737 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -156,7 +156,7 @@ static int idr_callback(int id, void *p, void *data)
156 */ 156 */
157 if (fsn_mark) 157 if (fsn_mark)
158 printk(KERN_WARNING "fsn_mark->group=%p inode=%p wd=%d\n", 158 printk(KERN_WARNING "fsn_mark->group=%p inode=%p wd=%d\n",
159 fsn_mark->group, fsn_mark->i.inode, i_mark->wd); 159 fsn_mark->group, fsn_mark->inode, i_mark->wd);
160 return 0; 160 return 0;
161} 161}
162 162
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 283aa312d745..450648697433 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -433,7 +433,7 @@ static void inotify_remove_from_idr(struct fsnotify_group *group,
433 if (wd == -1) { 433 if (wd == -1) {
434 WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p" 434 WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p"
435 " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd, 435 " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd,
436 i_mark->fsn_mark.group, i_mark->fsn_mark.i.inode); 436 i_mark->fsn_mark.group, i_mark->fsn_mark.inode);
437 goto out; 437 goto out;
438 } 438 }
439 439
@@ -442,7 +442,7 @@ static void inotify_remove_from_idr(struct fsnotify_group *group,
442 if (unlikely(!found_i_mark)) { 442 if (unlikely(!found_i_mark)) {
443 WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p" 443 WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p"
444 " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd, 444 " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd,
445 i_mark->fsn_mark.group, i_mark->fsn_mark.i.inode); 445 i_mark->fsn_mark.group, i_mark->fsn_mark.inode);
446 goto out; 446 goto out;
447 } 447 }
448 448
@@ -456,9 +456,9 @@ static void inotify_remove_from_idr(struct fsnotify_group *group,
456 "mark->inode=%p found_i_mark=%p found_i_mark->wd=%d " 456 "mark->inode=%p found_i_mark=%p found_i_mark->wd=%d "
457 "found_i_mark->group=%p found_i_mark->inode=%p\n", 457 "found_i_mark->group=%p found_i_mark->inode=%p\n",
458 __func__, i_mark, i_mark->wd, i_mark->fsn_mark.group, 458 __func__, i_mark, i_mark->wd, i_mark->fsn_mark.group,
459 i_mark->fsn_mark.i.inode, found_i_mark, found_i_mark->wd, 459 i_mark->fsn_mark.inode, found_i_mark, found_i_mark->wd,
460 found_i_mark->fsn_mark.group, 460 found_i_mark->fsn_mark.group,
461 found_i_mark->fsn_mark.i.inode); 461 found_i_mark->fsn_mark.inode);
462 goto out; 462 goto out;
463 } 463 }
464 464
@@ -470,7 +470,7 @@ static void inotify_remove_from_idr(struct fsnotify_group *group,
470 if (unlikely(atomic_read(&i_mark->fsn_mark.refcnt) < 3)) { 470 if (unlikely(atomic_read(&i_mark->fsn_mark.refcnt) < 3)) {
471 printk(KERN_ERR "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p" 471 printk(KERN_ERR "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p"
472 " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd, 472 " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd,
473 i_mark->fsn_mark.group, i_mark->fsn_mark.i.inode); 473 i_mark->fsn_mark.group, i_mark->fsn_mark.inode);
474 /* we can't really recover with bad ref cnting.. */ 474 /* we can't really recover with bad ref cnting.. */
475 BUG(); 475 BUG();
476 } 476 }
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index 34c38fabf514..3942d5c9eb8d 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -110,6 +110,17 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
110 } 110 }
111} 111}
112 112
113/* Calculate mask of events for a list of marks */
114u32 fsnotify_recalc_mask(struct hlist_head *head)
115{
116 u32 new_mask = 0;
117 struct fsnotify_mark *mark;
118
119 hlist_for_each_entry(mark, head, obj_list)
120 new_mask |= mark->mask;
121 return new_mask;
122}
123
113/* 124/*
114 * Any time a mark is getting freed we end up here. 125 * Any time a mark is getting freed we end up here.
115 * The caller had better be holding a reference to this mark so we don't actually 126 * The caller had better be holding a reference to this mark so we don't actually
@@ -133,7 +144,7 @@ void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark,
133 mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; 144 mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
134 145
135 if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { 146 if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) {
136 inode = mark->i.inode; 147 inode = mark->inode;
137 fsnotify_destroy_inode_mark(mark); 148 fsnotify_destroy_inode_mark(mark);
138 } else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) 149 } else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT)
139 fsnotify_destroy_vfsmount_mark(mark); 150 fsnotify_destroy_vfsmount_mark(mark);
@@ -192,6 +203,27 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark,
192 mutex_unlock(&group->mark_mutex); 203 mutex_unlock(&group->mark_mutex);
193} 204}
194 205
206/*
207 * Destroy all marks in the given list. The marks must be already detached from
208 * the original inode / vfsmount.
209 */
210void fsnotify_destroy_marks(struct list_head *to_free)
211{
212 struct fsnotify_mark *mark, *lmark;
213 struct fsnotify_group *group;
214
215 list_for_each_entry_safe(mark, lmark, to_free, free_list) {
216 spin_lock(&mark->lock);
217 fsnotify_get_group(mark->group);
218 group = mark->group;
219 spin_unlock(&mark->lock);
220
221 fsnotify_destroy_mark(mark, group);
222 fsnotify_put_mark(mark);
223 fsnotify_put_group(group);
224 }
225}
226
195void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) 227void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask)
196{ 228{
197 assert_spin_locked(&mark->lock); 229 assert_spin_locked(&mark->lock);
@@ -245,6 +277,39 @@ int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b)
245 return -1; 277 return -1;
246} 278}
247 279
280/* Add mark into proper place in given list of marks */
281int fsnotify_add_mark_list(struct hlist_head *head, struct fsnotify_mark *mark,
282 int allow_dups)
283{
284 struct fsnotify_mark *lmark, *last = NULL;
285 int cmp;
286
287 /* is mark the first mark? */
288 if (hlist_empty(head)) {
289 hlist_add_head_rcu(&mark->obj_list, head);
290 return 0;
291 }
292
293 /* should mark be in the middle of the current list? */
294 hlist_for_each_entry(lmark, head, obj_list) {
295 last = lmark;
296
297 if ((lmark->group == mark->group) && !allow_dups)
298 return -EEXIST;
299
300 cmp = fsnotify_compare_groups(lmark->group, mark->group);
301 if (cmp >= 0) {
302 hlist_add_before_rcu(&mark->obj_list, &lmark->obj_list);
303 return 0;
304 }
305 }
306
307 BUG_ON(last == NULL);
308 /* mark should be the last entry. last is the current last entry */
309 hlist_add_behind_rcu(&mark->obj_list, &last->obj_list);
310 return 0;
311}
312
248/* 313/*
249 * Attach an initialized mark to a given group and fs object. 314 * Attach an initialized mark to a given group and fs object.
250 * These marks may be used for the fsnotify backend to determine which 315 * These marks may be used for the fsnotify backend to determine which
@@ -323,6 +388,24 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group,
323} 388}
324 389
325/* 390/*
391 * Given a list of marks, find the mark associated with given group. If found
392 * take a reference to that mark and return it, else return NULL.
393 */
394struct fsnotify_mark *fsnotify_find_mark(struct hlist_head *head,
395 struct fsnotify_group *group)
396{
397 struct fsnotify_mark *mark;
398
399 hlist_for_each_entry(mark, head, obj_list) {
400 if (mark->group == group) {
401 fsnotify_get_mark(mark);
402 return mark;
403 }
404 }
405 return NULL;
406}
407
408/*
326 * clear any marks in a group in which mark->flags & flags is true 409 * clear any marks in a group in which mark->flags & flags is true
327 */ 410 */
328void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, 411void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group,
@@ -352,8 +435,8 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group)
352void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old) 435void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old)
353{ 436{
354 assert_spin_locked(&old->lock); 437 assert_spin_locked(&old->lock);
355 new->i.inode = old->i.inode; 438 new->inode = old->inode;
356 new->m.mnt = old->m.mnt; 439 new->mnt = old->mnt;
357 if (old->group) 440 if (old->group)
358 fsnotify_get_group(old->group); 441 fsnotify_get_group(old->group);
359 new->group = old->group; 442 new->group = old->group;
diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c
index faefa72a11eb..326b148e623c 100644
--- a/fs/notify/vfsmount_mark.c
+++ b/fs/notify/vfsmount_mark.c
@@ -32,31 +32,20 @@
32 32
33void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) 33void fsnotify_clear_marks_by_mount(struct vfsmount *mnt)
34{ 34{
35 struct fsnotify_mark *mark, *lmark; 35 struct fsnotify_mark *mark;
36 struct hlist_node *n; 36 struct hlist_node *n;
37 struct mount *m = real_mount(mnt); 37 struct mount *m = real_mount(mnt);
38 LIST_HEAD(free_list); 38 LIST_HEAD(free_list);
39 39
40 spin_lock(&mnt->mnt_root->d_lock); 40 spin_lock(&mnt->mnt_root->d_lock);
41 hlist_for_each_entry_safe(mark, n, &m->mnt_fsnotify_marks, m.m_list) { 41 hlist_for_each_entry_safe(mark, n, &m->mnt_fsnotify_marks, obj_list) {
42 list_add(&mark->m.free_m_list, &free_list); 42 list_add(&mark->free_list, &free_list);
43 hlist_del_init_rcu(&mark->m.m_list); 43 hlist_del_init_rcu(&mark->obj_list);
44 fsnotify_get_mark(mark); 44 fsnotify_get_mark(mark);
45 } 45 }
46 spin_unlock(&mnt->mnt_root->d_lock); 46 spin_unlock(&mnt->mnt_root->d_lock);
47 47
48 list_for_each_entry_safe(mark, lmark, &free_list, m.free_m_list) { 48 fsnotify_destroy_marks(&free_list);
49 struct fsnotify_group *group;
50
51 spin_lock(&mark->lock);
52 fsnotify_get_group(mark->group);
53 group = mark->group;
54 spin_unlock(&mark->lock);
55
56 fsnotify_destroy_mark(mark, group);
57 fsnotify_put_mark(mark);
58 fsnotify_put_group(group);
59 }
60} 49}
61 50
62void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) 51void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group)
@@ -65,66 +54,35 @@ void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group)
65} 54}
66 55
67/* 56/*
68 * Recalculate the mask of events relevant to a given vfsmount locked.
69 */
70static void fsnotify_recalc_vfsmount_mask_locked(struct vfsmount *mnt)
71{
72 struct mount *m = real_mount(mnt);
73 struct fsnotify_mark *mark;
74 __u32 new_mask = 0;
75
76 assert_spin_locked(&mnt->mnt_root->d_lock);
77
78 hlist_for_each_entry(mark, &m->mnt_fsnotify_marks, m.m_list)
79 new_mask |= mark->mask;
80 m->mnt_fsnotify_mask = new_mask;
81}
82
83/*
84 * Recalculate the mnt->mnt_fsnotify_mask, or the mask of all FS_* event types 57 * Recalculate the mnt->mnt_fsnotify_mask, or the mask of all FS_* event types
85 * any notifier is interested in hearing for this mount point 58 * any notifier is interested in hearing for this mount point
86 */ 59 */
87void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt) 60void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt)
88{ 61{
62 struct mount *m = real_mount(mnt);
63
89 spin_lock(&mnt->mnt_root->d_lock); 64 spin_lock(&mnt->mnt_root->d_lock);
90 fsnotify_recalc_vfsmount_mask_locked(mnt); 65 m->mnt_fsnotify_mask = fsnotify_recalc_mask(&m->mnt_fsnotify_marks);
91 spin_unlock(&mnt->mnt_root->d_lock); 66 spin_unlock(&mnt->mnt_root->d_lock);
92} 67}
93 68
94void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark) 69void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark)
95{ 70{
96 struct vfsmount *mnt = mark->m.mnt; 71 struct vfsmount *mnt = mark->mnt;
72 struct mount *m = real_mount(mnt);
97 73
98 BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); 74 BUG_ON(!mutex_is_locked(&mark->group->mark_mutex));
99 assert_spin_locked(&mark->lock); 75 assert_spin_locked(&mark->lock);
100 76
101 spin_lock(&mnt->mnt_root->d_lock); 77 spin_lock(&mnt->mnt_root->d_lock);
102 78
103 hlist_del_init_rcu(&mark->m.m_list); 79 hlist_del_init_rcu(&mark->obj_list);
104 mark->m.mnt = NULL; 80 mark->mnt = NULL;
105
106 fsnotify_recalc_vfsmount_mask_locked(mnt);
107 81
82 m->mnt_fsnotify_mask = fsnotify_recalc_mask(&m->mnt_fsnotify_marks);
108 spin_unlock(&mnt->mnt_root->d_lock); 83 spin_unlock(&mnt->mnt_root->d_lock);
109} 84}
110 85
111static struct fsnotify_mark *fsnotify_find_vfsmount_mark_locked(struct fsnotify_group *group,
112 struct vfsmount *mnt)
113{
114 struct mount *m = real_mount(mnt);
115 struct fsnotify_mark *mark;
116
117 assert_spin_locked(&mnt->mnt_root->d_lock);
118
119 hlist_for_each_entry(mark, &m->mnt_fsnotify_marks, m.m_list) {
120 if (mark->group == group) {
121 fsnotify_get_mark(mark);
122 return mark;
123 }
124 }
125 return NULL;
126}
127
128/* 86/*
129 * given a group and vfsmount, find the mark associated with that combination. 87 * given a group and vfsmount, find the mark associated with that combination.
130 * if found take a reference to that mark and return it, else return NULL 88 * if found take a reference to that mark and return it, else return NULL
@@ -132,10 +90,11 @@ static struct fsnotify_mark *fsnotify_find_vfsmount_mark_locked(struct fsnotify_
132struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, 90struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group,
133 struct vfsmount *mnt) 91 struct vfsmount *mnt)
134{ 92{
93 struct mount *m = real_mount(mnt);
135 struct fsnotify_mark *mark; 94 struct fsnotify_mark *mark;
136 95
137 spin_lock(&mnt->mnt_root->d_lock); 96 spin_lock(&mnt->mnt_root->d_lock);
138 mark = fsnotify_find_vfsmount_mark_locked(group, mnt); 97 mark = fsnotify_find_mark(&m->mnt_fsnotify_marks, group);
139 spin_unlock(&mnt->mnt_root->d_lock); 98 spin_unlock(&mnt->mnt_root->d_lock);
140 99
141 return mark; 100 return mark;
@@ -151,9 +110,7 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
151 int allow_dups) 110 int allow_dups)
152{ 111{
153 struct mount *m = real_mount(mnt); 112 struct mount *m = real_mount(mnt);
154 struct fsnotify_mark *lmark, *last = NULL; 113 int ret;
155 int ret = 0;
156 int cmp;
157 114
158 mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; 115 mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT;
159 116
@@ -161,37 +118,9 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
161 assert_spin_locked(&mark->lock); 118 assert_spin_locked(&mark->lock);
162 119
163 spin_lock(&mnt->mnt_root->d_lock); 120 spin_lock(&mnt->mnt_root->d_lock);
164 121 mark->mnt = mnt;
165 mark->m.mnt = mnt; 122 ret = fsnotify_add_mark_list(&m->mnt_fsnotify_marks, mark, allow_dups);
166 123 m->mnt_fsnotify_mask = fsnotify_recalc_mask(&m->mnt_fsnotify_marks);
167 /* is mark the first mark? */
168 if (hlist_empty(&m->mnt_fsnotify_marks)) {
169 hlist_add_head_rcu(&mark->m.m_list, &m->mnt_fsnotify_marks);
170 goto out;
171 }
172
173 /* should mark be in the middle of the current list? */
174 hlist_for_each_entry(lmark, &m->mnt_fsnotify_marks, m.m_list) {
175 last = lmark;
176
177 if ((lmark->group == group) && !allow_dups) {
178 ret = -EEXIST;
179 goto out;
180 }
181
182 cmp = fsnotify_compare_groups(lmark->group, mark->group);
183 if (cmp < 0)
184 continue;
185
186 hlist_add_before_rcu(&mark->m.m_list, &lmark->m.m_list);
187 goto out;
188 }
189
190 BUG_ON(last == NULL);
191 /* mark should be the last entry. last is the current last entry */
192 hlist_add_behind_rcu(&mark->m.m_list, &last->m.m_list);
193out:
194 fsnotify_recalc_vfsmount_mask_locked(mnt);
195 spin_unlock(&mnt->mnt_root->d_lock); 124 spin_unlock(&mnt->mnt_root->d_lock);
196 125
197 return ret; 126 return ret;
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index ca060d7c4fa6..442847a02b8f 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -197,24 +197,6 @@ struct fsnotify_group {
197#define FSNOTIFY_EVENT_INODE 2 197#define FSNOTIFY_EVENT_INODE 2
198 198
199/* 199/*
200 * Inode specific fields in an fsnotify_mark
201 */
202struct fsnotify_inode_mark {
203 struct inode *inode; /* inode this mark is associated with */
204 struct hlist_node i_list; /* list of marks by inode->i_fsnotify_marks */
205 struct list_head free_i_list; /* tmp list used when freeing this mark */
206};
207
208/*
209 * Mount point specific fields in an fsnotify_mark
210 */
211struct fsnotify_vfsmount_mark {
212 struct vfsmount *mnt; /* vfsmount this mark is associated with */
213 struct hlist_node m_list; /* list of marks by inode->i_fsnotify_marks */
214 struct list_head free_m_list; /* tmp list used when freeing this mark */
215};
216
217/*
218 * a mark is simply an object attached to an in core inode which allows an 200 * a mark is simply an object attached to an in core inode which allows an
219 * fsnotify listener to indicate they are either no longer interested in events 201 * fsnotify listener to indicate they are either no longer interested in events
220 * of a type matching mask or only interested in those events. 202 * of a type matching mask or only interested in those events.
@@ -232,9 +214,11 @@ struct fsnotify_mark {
232 struct fsnotify_group *group; /* group this mark is for */ 214 struct fsnotify_group *group; /* group this mark is for */
233 struct list_head g_list; /* list of marks by group->i_fsnotify_marks */ 215 struct list_head g_list; /* list of marks by group->i_fsnotify_marks */
234 spinlock_t lock; /* protect group and inode */ 216 spinlock_t lock; /* protect group and inode */
217 struct hlist_node obj_list; /* list of marks for inode / vfsmount */
218 struct list_head free_list; /* tmp list used when freeing this mark */
235 union { 219 union {
236 struct fsnotify_inode_mark i; 220 struct inode *inode; /* inode this mark is associated with */
237 struct fsnotify_vfsmount_mark m; 221 struct vfsmount *mnt; /* vfsmount this mark is associated with */
238 }; 222 };
239 __u32 ignored_mask; /* events types to ignore */ 223 __u32 ignored_mask; /* events types to ignore */
240#define FSNOTIFY_MARK_FLAG_INODE 0x01 224#define FSNOTIFY_MARK_FLAG_INODE 0x01
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 80f29e015570..2e0c97427b33 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -174,9 +174,9 @@ static void insert_hash(struct audit_chunk *chunk)
174 struct fsnotify_mark *entry = &chunk->mark; 174 struct fsnotify_mark *entry = &chunk->mark;
175 struct list_head *list; 175 struct list_head *list;
176 176
177 if (!entry->i.inode) 177 if (!entry->inode)
178 return; 178 return;
179 list = chunk_hash(entry->i.inode); 179 list = chunk_hash(entry->inode);
180 list_add_rcu(&chunk->hash, list); 180 list_add_rcu(&chunk->hash, list);
181} 181}
182 182
@@ -188,7 +188,7 @@ struct audit_chunk *audit_tree_lookup(const struct inode *inode)
188 188
189 list_for_each_entry_rcu(p, list, hash) { 189 list_for_each_entry_rcu(p, list, hash) {
190 /* mark.inode may have gone NULL, but who cares? */ 190 /* mark.inode may have gone NULL, but who cares? */
191 if (p->mark.i.inode == inode) { 191 if (p->mark.inode == inode) {
192 atomic_long_inc(&p->refs); 192 atomic_long_inc(&p->refs);
193 return p; 193 return p;
194 } 194 }
@@ -231,7 +231,7 @@ static void untag_chunk(struct node *p)
231 new = alloc_chunk(size); 231 new = alloc_chunk(size);
232 232
233 spin_lock(&entry->lock); 233 spin_lock(&entry->lock);
234 if (chunk->dead || !entry->i.inode) { 234 if (chunk->dead || !entry->inode) {
235 spin_unlock(&entry->lock); 235 spin_unlock(&entry->lock);
236 if (new) 236 if (new)
237 free_chunk(new); 237 free_chunk(new);
@@ -258,7 +258,7 @@ static void untag_chunk(struct node *p)
258 goto Fallback; 258 goto Fallback;
259 259
260 fsnotify_duplicate_mark(&new->mark, entry); 260 fsnotify_duplicate_mark(&new->mark, entry);
261 if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, NULL, 1)) { 261 if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.inode, NULL, 1)) {
262 fsnotify_put_mark(&new->mark); 262 fsnotify_put_mark(&new->mark);
263 goto Fallback; 263 goto Fallback;
264 } 264 }
@@ -386,7 +386,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
386 chunk_entry = &chunk->mark; 386 chunk_entry = &chunk->mark;
387 387
388 spin_lock(&old_entry->lock); 388 spin_lock(&old_entry->lock);
389 if (!old_entry->i.inode) { 389 if (!old_entry->inode) {
390 /* old_entry is being shot, lets just lie */ 390 /* old_entry is being shot, lets just lie */
391 spin_unlock(&old_entry->lock); 391 spin_unlock(&old_entry->lock);
392 fsnotify_put_mark(old_entry); 392 fsnotify_put_mark(old_entry);
@@ -395,7 +395,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
395 } 395 }
396 396
397 fsnotify_duplicate_mark(chunk_entry, old_entry); 397 fsnotify_duplicate_mark(chunk_entry, old_entry);
398 if (fsnotify_add_mark(chunk_entry, chunk_entry->group, chunk_entry->i.inode, NULL, 1)) { 398 if (fsnotify_add_mark(chunk_entry, chunk_entry->group, chunk_entry->inode, NULL, 1)) {
399 spin_unlock(&old_entry->lock); 399 spin_unlock(&old_entry->lock);
400 fsnotify_put_mark(chunk_entry); 400 fsnotify_put_mark(chunk_entry);
401 fsnotify_put_mark(old_entry); 401 fsnotify_put_mark(old_entry);
@@ -611,7 +611,7 @@ void audit_trim_trees(void)
611 list_for_each_entry(node, &tree->chunks, list) { 611 list_for_each_entry(node, &tree->chunks, list) {
612 struct audit_chunk *chunk = find_chunk(node); 612 struct audit_chunk *chunk = find_chunk(node);
613 /* this could be NULL if the watch is dying else where... */ 613 /* this could be NULL if the watch is dying else where... */
614 struct inode *inode = chunk->mark.i.inode; 614 struct inode *inode = chunk->mark.inode;
615 node->index |= 1U<<31; 615 node->index |= 1U<<31;
616 if (iterate_mounts(compare_root, inode, root_mnt)) 616 if (iterate_mounts(compare_root, inode, root_mnt))
617 node->index &= ~(1U<<31); 617 node->index &= ~(1U<<31);