diff options
Diffstat (limited to 'fs/notify/mark.c')
-rw-r--r-- | fs/notify/mark.c | 52 |
1 files changed, 29 insertions, 23 deletions
diff --git a/fs/notify/mark.c b/fs/notify/mark.c index e9191b416434..61f4c5fa34c7 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c | |||
@@ -119,9 +119,9 @@ static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) | |||
119 | if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) | 119 | if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) |
120 | new_mask |= mark->mask; | 120 | new_mask |= mark->mask; |
121 | } | 121 | } |
122 | if (conn->flags & FSNOTIFY_OBJ_TYPE_INODE) | 122 | if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) |
123 | conn->inode->i_fsnotify_mask = new_mask; | 123 | conn->inode->i_fsnotify_mask = new_mask; |
124 | else if (conn->flags & FSNOTIFY_OBJ_TYPE_VFSMOUNT) | 124 | else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) |
125 | real_mount(conn->mnt)->mnt_fsnotify_mask = new_mask; | 125 | real_mount(conn->mnt)->mnt_fsnotify_mask = new_mask; |
126 | } | 126 | } |
127 | 127 | ||
@@ -139,7 +139,7 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) | |||
139 | spin_lock(&conn->lock); | 139 | spin_lock(&conn->lock); |
140 | __fsnotify_recalc_mask(conn); | 140 | __fsnotify_recalc_mask(conn); |
141 | spin_unlock(&conn->lock); | 141 | spin_unlock(&conn->lock); |
142 | if (conn->flags & FSNOTIFY_OBJ_TYPE_INODE) | 142 | if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) |
143 | __fsnotify_update_child_dentry_flags(conn->inode); | 143 | __fsnotify_update_child_dentry_flags(conn->inode); |
144 | } | 144 | } |
145 | 145 | ||
@@ -166,18 +166,18 @@ static struct inode *fsnotify_detach_connector_from_object( | |||
166 | { | 166 | { |
167 | struct inode *inode = NULL; | 167 | struct inode *inode = NULL; |
168 | 168 | ||
169 | if (conn->flags & FSNOTIFY_OBJ_TYPE_INODE) { | 169 | if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) { |
170 | inode = conn->inode; | 170 | inode = conn->inode; |
171 | rcu_assign_pointer(inode->i_fsnotify_marks, NULL); | 171 | rcu_assign_pointer(inode->i_fsnotify_marks, NULL); |
172 | inode->i_fsnotify_mask = 0; | 172 | inode->i_fsnotify_mask = 0; |
173 | conn->inode = NULL; | 173 | conn->inode = NULL; |
174 | conn->flags &= ~FSNOTIFY_OBJ_TYPE_INODE; | 174 | conn->type = FSNOTIFY_OBJ_TYPE_DETACHED; |
175 | } else if (conn->flags & FSNOTIFY_OBJ_TYPE_VFSMOUNT) { | 175 | } else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) { |
176 | rcu_assign_pointer(real_mount(conn->mnt)->mnt_fsnotify_marks, | 176 | rcu_assign_pointer(real_mount(conn->mnt)->mnt_fsnotify_marks, |
177 | NULL); | 177 | NULL); |
178 | real_mount(conn->mnt)->mnt_fsnotify_mask = 0; | 178 | real_mount(conn->mnt)->mnt_fsnotify_mask = 0; |
179 | conn->mnt = NULL; | 179 | conn->mnt = NULL; |
180 | conn->flags &= ~FSNOTIFY_OBJ_TYPE_VFSMOUNT; | 180 | conn->type = FSNOTIFY_OBJ_TYPE_DETACHED; |
181 | } | 181 | } |
182 | 182 | ||
183 | return inode; | 183 | return inode; |
@@ -294,12 +294,12 @@ static void fsnotify_put_mark_wake(struct fsnotify_mark *mark) | |||
294 | 294 | ||
295 | bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info) | 295 | bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info) |
296 | { | 296 | { |
297 | /* This can fail if mark is being removed */ | 297 | int type; |
298 | if (!fsnotify_get_mark_safe(iter_info->inode_mark)) | 298 | |
299 | return false; | 299 | fsnotify_foreach_obj_type(type) { |
300 | if (!fsnotify_get_mark_safe(iter_info->vfsmount_mark)) { | 300 | /* This can fail if mark is being removed */ |
301 | fsnotify_put_mark_wake(iter_info->inode_mark); | 301 | if (!fsnotify_get_mark_safe(iter_info->marks[type])) |
302 | return false; | 302 | goto fail; |
303 | } | 303 | } |
304 | 304 | ||
305 | /* | 305 | /* |
@@ -310,13 +310,20 @@ bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info) | |||
310 | srcu_read_unlock(&fsnotify_mark_srcu, iter_info->srcu_idx); | 310 | srcu_read_unlock(&fsnotify_mark_srcu, iter_info->srcu_idx); |
311 | 311 | ||
312 | return true; | 312 | return true; |
313 | |||
314 | fail: | ||
315 | for (type--; type >= 0; type--) | ||
316 | fsnotify_put_mark_wake(iter_info->marks[type]); | ||
317 | return false; | ||
313 | } | 318 | } |
314 | 319 | ||
315 | void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info) | 320 | void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info) |
316 | { | 321 | { |
322 | int type; | ||
323 | |||
317 | iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); | 324 | iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); |
318 | fsnotify_put_mark_wake(iter_info->inode_mark); | 325 | fsnotify_foreach_obj_type(type) |
319 | fsnotify_put_mark_wake(iter_info->vfsmount_mark); | 326 | fsnotify_put_mark_wake(iter_info->marks[type]); |
320 | } | 327 | } |
321 | 328 | ||
322 | /* | 329 | /* |
@@ -442,10 +449,10 @@ static int fsnotify_attach_connector_to_object( | |||
442 | spin_lock_init(&conn->lock); | 449 | spin_lock_init(&conn->lock); |
443 | INIT_HLIST_HEAD(&conn->list); | 450 | INIT_HLIST_HEAD(&conn->list); |
444 | if (inode) { | 451 | if (inode) { |
445 | conn->flags = FSNOTIFY_OBJ_TYPE_INODE; | 452 | conn->type = FSNOTIFY_OBJ_TYPE_INODE; |
446 | conn->inode = igrab(inode); | 453 | conn->inode = igrab(inode); |
447 | } else { | 454 | } else { |
448 | conn->flags = FSNOTIFY_OBJ_TYPE_VFSMOUNT; | 455 | conn->type = FSNOTIFY_OBJ_TYPE_VFSMOUNT; |
449 | conn->mnt = mnt; | 456 | conn->mnt = mnt; |
450 | } | 457 | } |
451 | /* | 458 | /* |
@@ -479,8 +486,7 @@ static struct fsnotify_mark_connector *fsnotify_grab_connector( | |||
479 | if (!conn) | 486 | if (!conn) |
480 | goto out; | 487 | goto out; |
481 | spin_lock(&conn->lock); | 488 | spin_lock(&conn->lock); |
482 | if (!(conn->flags & (FSNOTIFY_OBJ_TYPE_INODE | | 489 | if (conn->type == FSNOTIFY_OBJ_TYPE_DETACHED) { |
483 | FSNOTIFY_OBJ_TYPE_VFSMOUNT))) { | ||
484 | spin_unlock(&conn->lock); | 490 | spin_unlock(&conn->lock); |
485 | srcu_read_unlock(&fsnotify_mark_srcu, idx); | 491 | srcu_read_unlock(&fsnotify_mark_srcu, idx); |
486 | return NULL; | 492 | return NULL; |
@@ -646,16 +652,16 @@ struct fsnotify_mark *fsnotify_find_mark( | |||
646 | return NULL; | 652 | return NULL; |
647 | } | 653 | } |
648 | 654 | ||
649 | /* Clear any marks in a group with given type */ | 655 | /* Clear any marks in a group with given type mask */ |
650 | void fsnotify_clear_marks_by_group(struct fsnotify_group *group, | 656 | void fsnotify_clear_marks_by_group(struct fsnotify_group *group, |
651 | unsigned int type) | 657 | unsigned int type_mask) |
652 | { | 658 | { |
653 | struct fsnotify_mark *lmark, *mark; | 659 | struct fsnotify_mark *lmark, *mark; |
654 | LIST_HEAD(to_free); | 660 | LIST_HEAD(to_free); |
655 | struct list_head *head = &to_free; | 661 | struct list_head *head = &to_free; |
656 | 662 | ||
657 | /* Skip selection step if we want to clear all marks. */ | 663 | /* Skip selection step if we want to clear all marks. */ |
658 | if (type == FSNOTIFY_OBJ_ALL_TYPES) { | 664 | if (type_mask == FSNOTIFY_OBJ_ALL_TYPES_MASK) { |
659 | head = &group->marks_list; | 665 | head = &group->marks_list; |
660 | goto clear; | 666 | goto clear; |
661 | } | 667 | } |
@@ -670,7 +676,7 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group, | |||
670 | */ | 676 | */ |
671 | mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); | 677 | mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); |
672 | list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { | 678 | list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { |
673 | if (mark->connector->flags & type) | 679 | if ((1U << mark->connector->type) & type_mask) |
674 | list_move(&mark->g_list, &to_free); | 680 | list_move(&mark->g_list, &to_free); |
675 | } | 681 | } |
676 | mutex_unlock(&group->mark_mutex); | 682 | mutex_unlock(&group->mark_mutex); |