diff options
Diffstat (limited to 'fs/notify/mark.c')
| -rw-r--r-- | fs/notify/mark.c | 97 |
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 */ | ||
| 114 | u32 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 | */ | ||
| 210 | void 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 | |||
| 195 | void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) | 227 | void 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 */ | ||
| 281 | int 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 | */ | ||
| 394 | struct 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 | */ |
| 328 | void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, | 411 | void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, |
| @@ -352,8 +435,8 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group) | |||
| 352 | void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old) | 435 | void 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 | ||
