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.c97
1 files changed, 90 insertions, 7 deletions
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index 34c38fabf514..92e48c70f0f0 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);
@@ -150,7 +161,7 @@ void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark,
150 mutex_unlock(&group->mark_mutex); 161 mutex_unlock(&group->mark_mutex);
151 162
152 spin_lock(&destroy_lock); 163 spin_lock(&destroy_lock);
153 list_add(&mark->destroy_list, &destroy_list); 164 list_add(&mark->g_list, &destroy_list);
154 spin_unlock(&destroy_lock); 165 spin_unlock(&destroy_lock);
155 wake_up(&destroy_waitq); 166 wake_up(&destroy_waitq);
156 /* 167 /*
@@ -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
@@ -305,7 +370,7 @@ err:
305 spin_unlock(&mark->lock); 370 spin_unlock(&mark->lock);
306 371
307 spin_lock(&destroy_lock); 372 spin_lock(&destroy_lock);
308 list_add(&mark->destroy_list, &destroy_list); 373 list_add(&mark->g_list, &destroy_list);
309 spin_unlock(&destroy_lock); 374 spin_unlock(&destroy_lock);
310 wake_up(&destroy_waitq); 375 wake_up(&destroy_waitq);
311 376
@@ -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;
@@ -386,8 +469,8 @@ static int fsnotify_mark_destroy(void *ignored)
386 469
387 synchronize_srcu(&fsnotify_mark_srcu); 470 synchronize_srcu(&fsnotify_mark_srcu);
388 471
389 list_for_each_entry_safe(mark, next, &private_destroy_list, destroy_list) { 472 list_for_each_entry_safe(mark, next, &private_destroy_list, g_list) {
390 list_del_init(&mark->destroy_list); 473 list_del_init(&mark->g_list);
391 fsnotify_put_mark(mark); 474 fsnotify_put_mark(mark);
392 } 475 }
393 476