diff options
-rw-r--r-- | fs/notify/dnotify/dnotify.c | 4 | ||||
-rw-r--r-- | fs/notify/fanotify/fanotify.c | 6 | ||||
-rw-r--r-- | fs/notify/fanotify/fanotify_user.c | 37 | ||||
-rw-r--r-- | fs/notify/fdinfo.c | 4 | ||||
-rw-r--r-- | fs/notify/group.c | 47 | ||||
-rw-r--r-- | fs/notify/inode_mark.c | 14 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_fsnotify.c | 4 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_user.c | 34 | ||||
-rw-r--r-- | fs/notify/mark.c | 91 | ||||
-rw-r--r-- | fs/notify/notification.c | 1 | ||||
-rw-r--r-- | fs/notify/vfsmount_mark.c | 14 | ||||
-rw-r--r-- | include/linux/fsnotify_backend.h | 31 | ||||
-rw-r--r-- | kernel/audit_tree.c | 10 | ||||
-rw-r--r-- | kernel/audit_watch.c | 4 |
14 files changed, 180 insertions, 121 deletions
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c index 3344bdd5506e..08b886f119ce 100644 --- a/fs/notify/dnotify/dnotify.c +++ b/fs/notify/dnotify/dnotify.c | |||
@@ -201,7 +201,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id) | |||
201 | 201 | ||
202 | /* nothing else could have found us thanks to the dnotify_mark_mutex */ | 202 | /* nothing else could have found us thanks to the dnotify_mark_mutex */ |
203 | if (dn_mark->dn == NULL) | 203 | if (dn_mark->dn == NULL) |
204 | fsnotify_destroy_mark(fsn_mark); | 204 | fsnotify_destroy_mark(fsn_mark, dnotify_group); |
205 | 205 | ||
206 | mutex_unlock(&dnotify_mark_mutex); | 206 | mutex_unlock(&dnotify_mark_mutex); |
207 | 207 | ||
@@ -385,7 +385,7 @@ out: | |||
385 | spin_unlock(&fsn_mark->lock); | 385 | spin_unlock(&fsn_mark->lock); |
386 | 386 | ||
387 | if (destroy) | 387 | if (destroy) |
388 | fsnotify_destroy_mark(fsn_mark); | 388 | fsnotify_destroy_mark(fsn_mark, dnotify_group); |
389 | 389 | ||
390 | mutex_unlock(&dnotify_mark_mutex); | 390 | mutex_unlock(&dnotify_mark_mutex); |
391 | fsnotify_put_mark(fsn_mark); | 391 | fsnotify_put_mark(fsn_mark); |
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index a50636025364..0c2f9122b262 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c | |||
@@ -18,6 +18,12 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new) | |||
18 | old->tgid == new->tgid) { | 18 | old->tgid == new->tgid) { |
19 | switch (old->data_type) { | 19 | switch (old->data_type) { |
20 | case (FSNOTIFY_EVENT_PATH): | 20 | case (FSNOTIFY_EVENT_PATH): |
21 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
22 | /* dont merge two permission events */ | ||
23 | if ((old->mask & FAN_ALL_PERM_EVENTS) && | ||
24 | (new->mask & FAN_ALL_PERM_EVENTS)) | ||
25 | return false; | ||
26 | #endif | ||
21 | if ((old->path.mnt == new->path.mnt) && | 27 | if ((old->path.mnt == new->path.mnt) && |
22 | (old->path.dentry == new->path.dentry)) | 28 | (old->path.dentry == new->path.dentry)) |
23 | return true; | 29 | return true; |
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index a5cd9bba022f..9ff4a5ee6e20 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c | |||
@@ -397,8 +397,12 @@ static int fanotify_release(struct inode *ignored, struct file *file) | |||
397 | 397 | ||
398 | wake_up(&group->fanotify_data.access_waitq); | 398 | wake_up(&group->fanotify_data.access_waitq); |
399 | #endif | 399 | #endif |
400 | |||
401 | if (file->f_flags & FASYNC) | ||
402 | fsnotify_fasync(-1, file, 0); | ||
403 | |||
400 | /* matches the fanotify_init->fsnotify_alloc_group */ | 404 | /* matches the fanotify_init->fsnotify_alloc_group */ |
401 | fsnotify_put_group(group); | 405 | fsnotify_destroy_group(group); |
402 | 406 | ||
403 | return 0; | 407 | return 0; |
404 | } | 408 | } |
@@ -493,7 +497,8 @@ out: | |||
493 | 497 | ||
494 | static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, | 498 | static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, |
495 | __u32 mask, | 499 | __u32 mask, |
496 | unsigned int flags) | 500 | unsigned int flags, |
501 | int *destroy) | ||
497 | { | 502 | { |
498 | __u32 oldmask; | 503 | __u32 oldmask; |
499 | 504 | ||
@@ -507,8 +512,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, | |||
507 | } | 512 | } |
508 | spin_unlock(&fsn_mark->lock); | 513 | spin_unlock(&fsn_mark->lock); |
509 | 514 | ||
510 | if (!(oldmask & ~mask)) | 515 | *destroy = !(oldmask & ~mask); |
511 | fsnotify_destroy_mark(fsn_mark); | ||
512 | 516 | ||
513 | return mask & oldmask; | 517 | return mask & oldmask; |
514 | } | 518 | } |
@@ -519,12 +523,17 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group, | |||
519 | { | 523 | { |
520 | struct fsnotify_mark *fsn_mark = NULL; | 524 | struct fsnotify_mark *fsn_mark = NULL; |
521 | __u32 removed; | 525 | __u32 removed; |
526 | int destroy_mark; | ||
522 | 527 | ||
523 | fsn_mark = fsnotify_find_vfsmount_mark(group, mnt); | 528 | fsn_mark = fsnotify_find_vfsmount_mark(group, mnt); |
524 | if (!fsn_mark) | 529 | if (!fsn_mark) |
525 | return -ENOENT; | 530 | return -ENOENT; |
526 | 531 | ||
527 | removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags); | 532 | removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags, |
533 | &destroy_mark); | ||
534 | if (destroy_mark) | ||
535 | fsnotify_destroy_mark(fsn_mark, group); | ||
536 | |||
528 | fsnotify_put_mark(fsn_mark); | 537 | fsnotify_put_mark(fsn_mark); |
529 | if (removed & real_mount(mnt)->mnt_fsnotify_mask) | 538 | if (removed & real_mount(mnt)->mnt_fsnotify_mask) |
530 | fsnotify_recalc_vfsmount_mask(mnt); | 539 | fsnotify_recalc_vfsmount_mask(mnt); |
@@ -538,12 +547,16 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, | |||
538 | { | 547 | { |
539 | struct fsnotify_mark *fsn_mark = NULL; | 548 | struct fsnotify_mark *fsn_mark = NULL; |
540 | __u32 removed; | 549 | __u32 removed; |
550 | int destroy_mark; | ||
541 | 551 | ||
542 | fsn_mark = fsnotify_find_inode_mark(group, inode); | 552 | fsn_mark = fsnotify_find_inode_mark(group, inode); |
543 | if (!fsn_mark) | 553 | if (!fsn_mark) |
544 | return -ENOENT; | 554 | return -ENOENT; |
545 | 555 | ||
546 | removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags); | 556 | removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags, |
557 | &destroy_mark); | ||
558 | if (destroy_mark) | ||
559 | fsnotify_destroy_mark(fsn_mark, group); | ||
547 | /* matches the fsnotify_find_inode_mark() */ | 560 | /* matches the fsnotify_find_inode_mark() */ |
548 | fsnotify_put_mark(fsn_mark); | 561 | fsnotify_put_mark(fsn_mark); |
549 | if (removed & inode->i_fsnotify_mask) | 562 | if (removed & inode->i_fsnotify_mask) |
@@ -710,13 +723,13 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) | |||
710 | break; | 723 | break; |
711 | default: | 724 | default: |
712 | fd = -EINVAL; | 725 | fd = -EINVAL; |
713 | goto out_put_group; | 726 | goto out_destroy_group; |
714 | } | 727 | } |
715 | 728 | ||
716 | if (flags & FAN_UNLIMITED_QUEUE) { | 729 | if (flags & FAN_UNLIMITED_QUEUE) { |
717 | fd = -EPERM; | 730 | fd = -EPERM; |
718 | if (!capable(CAP_SYS_ADMIN)) | 731 | if (!capable(CAP_SYS_ADMIN)) |
719 | goto out_put_group; | 732 | goto out_destroy_group; |
720 | group->max_events = UINT_MAX; | 733 | group->max_events = UINT_MAX; |
721 | } else { | 734 | } else { |
722 | group->max_events = FANOTIFY_DEFAULT_MAX_EVENTS; | 735 | group->max_events = FANOTIFY_DEFAULT_MAX_EVENTS; |
@@ -725,7 +738,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) | |||
725 | if (flags & FAN_UNLIMITED_MARKS) { | 738 | if (flags & FAN_UNLIMITED_MARKS) { |
726 | fd = -EPERM; | 739 | fd = -EPERM; |
727 | if (!capable(CAP_SYS_ADMIN)) | 740 | if (!capable(CAP_SYS_ADMIN)) |
728 | goto out_put_group; | 741 | goto out_destroy_group; |
729 | group->fanotify_data.max_marks = UINT_MAX; | 742 | group->fanotify_data.max_marks = UINT_MAX; |
730 | } else { | 743 | } else { |
731 | group->fanotify_data.max_marks = FANOTIFY_DEFAULT_MAX_MARKS; | 744 | group->fanotify_data.max_marks = FANOTIFY_DEFAULT_MAX_MARKS; |
@@ -733,12 +746,12 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) | |||
733 | 746 | ||
734 | fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags); | 747 | fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags); |
735 | if (fd < 0) | 748 | if (fd < 0) |
736 | goto out_put_group; | 749 | goto out_destroy_group; |
737 | 750 | ||
738 | return fd; | 751 | return fd; |
739 | 752 | ||
740 | out_put_group: | 753 | out_destroy_group: |
741 | fsnotify_put_group(group); | 754 | fsnotify_destroy_group(group); |
742 | return fd; | 755 | return fd; |
743 | } | 756 | } |
744 | 757 | ||
diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c index 514c4b81483d..238a5930cb3c 100644 --- a/fs/notify/fdinfo.c +++ b/fs/notify/fdinfo.c | |||
@@ -27,13 +27,13 @@ static int show_fdinfo(struct seq_file *m, struct file *f, | |||
27 | struct fsnotify_mark *mark; | 27 | struct fsnotify_mark *mark; |
28 | int ret = 0; | 28 | int ret = 0; |
29 | 29 | ||
30 | spin_lock(&group->mark_lock); | 30 | mutex_lock(&group->mark_mutex); |
31 | list_for_each_entry(mark, &group->marks_list, g_list) { | 31 | list_for_each_entry(mark, &group->marks_list, g_list) { |
32 | ret = show(m, mark); | 32 | ret = show(m, mark); |
33 | if (ret) | 33 | if (ret) |
34 | break; | 34 | break; |
35 | } | 35 | } |
36 | spin_unlock(&group->mark_lock); | 36 | mutex_unlock(&group->mark_mutex); |
37 | return ret; | 37 | return ret; |
38 | } | 38 | } |
39 | 39 | ||
diff --git a/fs/notify/group.c b/fs/notify/group.c index 63fc294a4692..bd2625bd88b4 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c | |||
@@ -33,9 +33,6 @@ | |||
33 | */ | 33 | */ |
34 | void fsnotify_final_destroy_group(struct fsnotify_group *group) | 34 | void fsnotify_final_destroy_group(struct fsnotify_group *group) |
35 | { | 35 | { |
36 | /* clear the notification queue of all events */ | ||
37 | fsnotify_flush_notify(group); | ||
38 | |||
39 | if (group->ops->free_group_priv) | 36 | if (group->ops->free_group_priv) |
40 | group->ops->free_group_priv(group); | 37 | group->ops->free_group_priv(group); |
41 | 38 | ||
@@ -43,23 +40,30 @@ void fsnotify_final_destroy_group(struct fsnotify_group *group) | |||
43 | } | 40 | } |
44 | 41 | ||
45 | /* | 42 | /* |
46 | * Trying to get rid of a group. We need to first get rid of any outstanding | 43 | * Trying to get rid of a group. Remove all marks, flush all events and release |
47 | * allocations and then free the group. Remember that fsnotify_clear_marks_by_group | 44 | * the group reference. |
48 | * could miss marks that are being freed by inode and those marks could still | 45 | * Note that another thread calling fsnotify_clear_marks_by_group() may still |
49 | * hold a reference to this group (via group->num_marks) If we get into that | 46 | * hold a ref to the group. |
50 | * situtation, the fsnotify_final_destroy_group will get called when that final | ||
51 | * mark is freed. | ||
52 | */ | 47 | */ |
53 | static void fsnotify_destroy_group(struct fsnotify_group *group) | 48 | void fsnotify_destroy_group(struct fsnotify_group *group) |
54 | { | 49 | { |
55 | /* clear all inode marks for this group */ | 50 | /* clear all inode marks for this group */ |
56 | fsnotify_clear_marks_by_group(group); | 51 | fsnotify_clear_marks_by_group(group); |
57 | 52 | ||
58 | synchronize_srcu(&fsnotify_mark_srcu); | 53 | synchronize_srcu(&fsnotify_mark_srcu); |
59 | 54 | ||
60 | /* past the point of no return, matches the initial value of 1 */ | 55 | /* clear the notification queue of all events */ |
61 | if (atomic_dec_and_test(&group->num_marks)) | 56 | fsnotify_flush_notify(group); |
62 | fsnotify_final_destroy_group(group); | 57 | |
58 | fsnotify_put_group(group); | ||
59 | } | ||
60 | |||
61 | /* | ||
62 | * Get reference to a group. | ||
63 | */ | ||
64 | void fsnotify_get_group(struct fsnotify_group *group) | ||
65 | { | ||
66 | atomic_inc(&group->refcnt); | ||
63 | } | 67 | } |
64 | 68 | ||
65 | /* | 69 | /* |
@@ -68,7 +72,7 @@ static void fsnotify_destroy_group(struct fsnotify_group *group) | |||
68 | void fsnotify_put_group(struct fsnotify_group *group) | 72 | void fsnotify_put_group(struct fsnotify_group *group) |
69 | { | 73 | { |
70 | if (atomic_dec_and_test(&group->refcnt)) | 74 | if (atomic_dec_and_test(&group->refcnt)) |
71 | fsnotify_destroy_group(group); | 75 | fsnotify_final_destroy_group(group); |
72 | } | 76 | } |
73 | 77 | ||
74 | /* | 78 | /* |
@@ -84,21 +88,24 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) | |||
84 | 88 | ||
85 | /* set to 0 when there a no external references to this group */ | 89 | /* set to 0 when there a no external references to this group */ |
86 | atomic_set(&group->refcnt, 1); | 90 | atomic_set(&group->refcnt, 1); |
87 | /* | 91 | atomic_set(&group->num_marks, 0); |
88 | * hits 0 when there are no external references AND no marks for | ||
89 | * this group | ||
90 | */ | ||
91 | atomic_set(&group->num_marks, 1); | ||
92 | 92 | ||
93 | mutex_init(&group->notification_mutex); | 93 | mutex_init(&group->notification_mutex); |
94 | INIT_LIST_HEAD(&group->notification_list); | 94 | INIT_LIST_HEAD(&group->notification_list); |
95 | init_waitqueue_head(&group->notification_waitq); | 95 | init_waitqueue_head(&group->notification_waitq); |
96 | group->max_events = UINT_MAX; | 96 | group->max_events = UINT_MAX; |
97 | 97 | ||
98 | spin_lock_init(&group->mark_lock); | 98 | mutex_init(&group->mark_mutex); |
99 | INIT_LIST_HEAD(&group->marks_list); | 99 | INIT_LIST_HEAD(&group->marks_list); |
100 | 100 | ||
101 | group->ops = ops; | 101 | group->ops = ops; |
102 | 102 | ||
103 | return group; | 103 | return group; |
104 | } | 104 | } |
105 | |||
106 | int fsnotify_fasync(int fd, struct file *file, int on) | ||
107 | { | ||
108 | struct fsnotify_group *group = file->private_data; | ||
109 | |||
110 | return fasync_helper(fd, file, on, &group->fsn_fa) >= 0 ? 0 : -EIO; | ||
111 | } | ||
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index f3035691f528..f31e90fc050d 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c | |||
@@ -63,8 +63,8 @@ void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark) | |||
63 | { | 63 | { |
64 | struct inode *inode = mark->i.inode; | 64 | struct inode *inode = mark->i.inode; |
65 | 65 | ||
66 | BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); | ||
66 | assert_spin_locked(&mark->lock); | 67 | assert_spin_locked(&mark->lock); |
67 | assert_spin_locked(&mark->group->mark_lock); | ||
68 | 68 | ||
69 | spin_lock(&inode->i_lock); | 69 | spin_lock(&inode->i_lock); |
70 | 70 | ||
@@ -99,8 +99,16 @@ void fsnotify_clear_marks_by_inode(struct inode *inode) | |||
99 | spin_unlock(&inode->i_lock); | 99 | spin_unlock(&inode->i_lock); |
100 | 100 | ||
101 | list_for_each_entry_safe(mark, lmark, &free_list, i.free_i_list) { | 101 | list_for_each_entry_safe(mark, lmark, &free_list, i.free_i_list) { |
102 | fsnotify_destroy_mark(mark); | 102 | struct fsnotify_group *group; |
103 | |||
104 | spin_lock(&mark->lock); | ||
105 | fsnotify_get_group(mark->group); | ||
106 | group = mark->group; | ||
107 | spin_unlock(&mark->lock); | ||
108 | |||
109 | fsnotify_destroy_mark(mark, group); | ||
103 | fsnotify_put_mark(mark); | 110 | fsnotify_put_mark(mark); |
111 | fsnotify_put_group(group); | ||
104 | } | 112 | } |
105 | } | 113 | } |
106 | 114 | ||
@@ -192,8 +200,8 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | |||
192 | 200 | ||
193 | mark->flags |= FSNOTIFY_MARK_FLAG_INODE; | 201 | mark->flags |= FSNOTIFY_MARK_FLAG_INODE; |
194 | 202 | ||
203 | BUG_ON(!mutex_is_locked(&group->mark_mutex)); | ||
195 | assert_spin_locked(&mark->lock); | 204 | assert_spin_locked(&mark->lock); |
196 | assert_spin_locked(&group->mark_lock); | ||
197 | 205 | ||
198 | spin_lock(&inode->i_lock); | 206 | spin_lock(&inode->i_lock); |
199 | 207 | ||
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index e3cbd746f64a..871569c7d609 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c | |||
@@ -118,6 +118,7 @@ static int inotify_handle_event(struct fsnotify_group *group, | |||
118 | 118 | ||
119 | fsn_event_priv = &event_priv->fsnotify_event_priv_data; | 119 | fsn_event_priv = &event_priv->fsnotify_event_priv_data; |
120 | 120 | ||
121 | fsnotify_get_group(group); | ||
121 | fsn_event_priv->group = group; | 122 | fsn_event_priv->group = group; |
122 | event_priv->wd = wd; | 123 | event_priv->wd = wd; |
123 | 124 | ||
@@ -131,7 +132,7 @@ static int inotify_handle_event(struct fsnotify_group *group, | |||
131 | } | 132 | } |
132 | 133 | ||
133 | if (inode_mark->mask & IN_ONESHOT) | 134 | if (inode_mark->mask & IN_ONESHOT) |
134 | fsnotify_destroy_mark(inode_mark); | 135 | fsnotify_destroy_mark(inode_mark, group); |
135 | 136 | ||
136 | return ret; | 137 | return ret; |
137 | } | 138 | } |
@@ -210,6 +211,7 @@ void inotify_free_event_priv(struct fsnotify_event_private_data *fsn_event_priv) | |||
210 | event_priv = container_of(fsn_event_priv, struct inotify_event_private_data, | 211 | event_priv = container_of(fsn_event_priv, struct inotify_event_private_data, |
211 | fsnotify_event_priv_data); | 212 | fsnotify_event_priv_data); |
212 | 213 | ||
214 | fsnotify_put_group(fsn_event_priv->group); | ||
213 | kmem_cache_free(event_priv_cachep, event_priv); | 215 | kmem_cache_free(event_priv_cachep, event_priv); |
214 | } | 216 | } |
215 | 217 | ||
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 36cb013c7c13..228a2c2ad8d7 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -265,7 +265,7 @@ static ssize_t inotify_read(struct file *file, char __user *buf, | |||
265 | ret = -EAGAIN; | 265 | ret = -EAGAIN; |
266 | if (file->f_flags & O_NONBLOCK) | 266 | if (file->f_flags & O_NONBLOCK) |
267 | break; | 267 | break; |
268 | ret = -EINTR; | 268 | ret = -ERESTARTSYS; |
269 | if (signal_pending(current)) | 269 | if (signal_pending(current)) |
270 | break; | 270 | break; |
271 | 271 | ||
@@ -281,23 +281,17 @@ static ssize_t inotify_read(struct file *file, char __user *buf, | |||
281 | return ret; | 281 | return ret; |
282 | } | 282 | } |
283 | 283 | ||
284 | static int inotify_fasync(int fd, struct file *file, int on) | ||
285 | { | ||
286 | struct fsnotify_group *group = file->private_data; | ||
287 | |||
288 | return fasync_helper(fd, file, on, &group->inotify_data.fa) >= 0 ? 0 : -EIO; | ||
289 | } | ||
290 | |||
291 | static int inotify_release(struct inode *ignored, struct file *file) | 284 | static int inotify_release(struct inode *ignored, struct file *file) |
292 | { | 285 | { |
293 | struct fsnotify_group *group = file->private_data; | 286 | struct fsnotify_group *group = file->private_data; |
294 | 287 | ||
295 | pr_debug("%s: group=%p\n", __func__, group); | 288 | pr_debug("%s: group=%p\n", __func__, group); |
296 | 289 | ||
297 | fsnotify_clear_marks_by_group(group); | 290 | if (file->f_flags & FASYNC) |
291 | fsnotify_fasync(-1, file, 0); | ||
298 | 292 | ||
299 | /* free this group, matching get was inotify_init->fsnotify_obtain_group */ | 293 | /* free this group, matching get was inotify_init->fsnotify_obtain_group */ |
300 | fsnotify_put_group(group); | 294 | fsnotify_destroy_group(group); |
301 | 295 | ||
302 | return 0; | 296 | return 0; |
303 | } | 297 | } |
@@ -339,7 +333,7 @@ static const struct file_operations inotify_fops = { | |||
339 | .show_fdinfo = inotify_show_fdinfo, | 333 | .show_fdinfo = inotify_show_fdinfo, |
340 | .poll = inotify_poll, | 334 | .poll = inotify_poll, |
341 | .read = inotify_read, | 335 | .read = inotify_read, |
342 | .fasync = inotify_fasync, | 336 | .fasync = fsnotify_fasync, |
343 | .release = inotify_release, | 337 | .release = inotify_release, |
344 | .unlocked_ioctl = inotify_ioctl, | 338 | .unlocked_ioctl = inotify_ioctl, |
345 | .compat_ioctl = inotify_ioctl, | 339 | .compat_ioctl = inotify_ioctl, |
@@ -521,13 +515,13 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark, | |||
521 | struct fsnotify_event_private_data *fsn_event_priv; | 515 | struct fsnotify_event_private_data *fsn_event_priv; |
522 | int ret; | 516 | int ret; |
523 | 517 | ||
518 | i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark); | ||
519 | |||
524 | ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL, | 520 | ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL, |
525 | FSNOTIFY_EVENT_NONE, NULL, 0, | 521 | FSNOTIFY_EVENT_NONE, NULL, 0, |
526 | GFP_NOFS); | 522 | GFP_NOFS); |
527 | if (!ignored_event) | 523 | if (!ignored_event) |
528 | return; | 524 | goto skip_send_ignore; |
529 | |||
530 | i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark); | ||
531 | 525 | ||
532 | event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS); | 526 | event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS); |
533 | if (unlikely(!event_priv)) | 527 | if (unlikely(!event_priv)) |
@@ -535,6 +529,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark, | |||
535 | 529 | ||
536 | fsn_event_priv = &event_priv->fsnotify_event_priv_data; | 530 | fsn_event_priv = &event_priv->fsnotify_event_priv_data; |
537 | 531 | ||
532 | fsnotify_get_group(group); | ||
538 | fsn_event_priv->group = group; | 533 | fsn_event_priv->group = group; |
539 | event_priv->wd = i_mark->wd; | 534 | event_priv->wd = i_mark->wd; |
540 | 535 | ||
@@ -548,9 +543,9 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark, | |||
548 | } | 543 | } |
549 | 544 | ||
550 | skip_send_ignore: | 545 | skip_send_ignore: |
551 | |||
552 | /* matches the reference taken when the event was created */ | 546 | /* matches the reference taken when the event was created */ |
553 | fsnotify_put_event(ignored_event); | 547 | if (ignored_event) |
548 | fsnotify_put_event(ignored_event); | ||
554 | 549 | ||
555 | /* remove this mark from the idr */ | 550 | /* remove this mark from the idr */ |
556 | inotify_remove_from_idr(group, i_mark); | 551 | inotify_remove_from_idr(group, i_mark); |
@@ -709,12 +704,11 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events) | |||
709 | spin_lock_init(&group->inotify_data.idr_lock); | 704 | spin_lock_init(&group->inotify_data.idr_lock); |
710 | idr_init(&group->inotify_data.idr); | 705 | idr_init(&group->inotify_data.idr); |
711 | group->inotify_data.last_wd = 0; | 706 | group->inotify_data.last_wd = 0; |
712 | group->inotify_data.fa = NULL; | ||
713 | group->inotify_data.user = get_current_user(); | 707 | group->inotify_data.user = get_current_user(); |
714 | 708 | ||
715 | if (atomic_inc_return(&group->inotify_data.user->inotify_devs) > | 709 | if (atomic_inc_return(&group->inotify_data.user->inotify_devs) > |
716 | inotify_max_user_instances) { | 710 | inotify_max_user_instances) { |
717 | fsnotify_put_group(group); | 711 | fsnotify_destroy_group(group); |
718 | return ERR_PTR(-EMFILE); | 712 | return ERR_PTR(-EMFILE); |
719 | } | 713 | } |
720 | 714 | ||
@@ -743,7 +737,7 @@ SYSCALL_DEFINE1(inotify_init1, int, flags) | |||
743 | ret = anon_inode_getfd("inotify", &inotify_fops, group, | 737 | ret = anon_inode_getfd("inotify", &inotify_fops, group, |
744 | O_RDONLY | flags); | 738 | O_RDONLY | flags); |
745 | if (ret < 0) | 739 | if (ret < 0) |
746 | fsnotify_put_group(group); | 740 | fsnotify_destroy_group(group); |
747 | 741 | ||
748 | return ret; | 742 | return ret; |
749 | } | 743 | } |
@@ -819,7 +813,7 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd) | |||
819 | 813 | ||
820 | ret = 0; | 814 | ret = 0; |
821 | 815 | ||
822 | fsnotify_destroy_mark(&i_mark->fsn_mark); | 816 | fsnotify_destroy_mark(&i_mark->fsn_mark, group); |
823 | 817 | ||
824 | /* match ref taken by inotify_idr_find */ | 818 | /* match ref taken by inotify_idr_find */ |
825 | fsnotify_put_mark(&i_mark->fsn_mark); | 819 | fsnotify_put_mark(&i_mark->fsn_mark); |
diff --git a/fs/notify/mark.c b/fs/notify/mark.c index f104d565b682..fc6b49bf7360 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c | |||
@@ -109,8 +109,11 @@ void fsnotify_get_mark(struct fsnotify_mark *mark) | |||
109 | 109 | ||
110 | void fsnotify_put_mark(struct fsnotify_mark *mark) | 110 | void fsnotify_put_mark(struct fsnotify_mark *mark) |
111 | { | 111 | { |
112 | if (atomic_dec_and_test(&mark->refcnt)) | 112 | if (atomic_dec_and_test(&mark->refcnt)) { |
113 | if (mark->group) | ||
114 | fsnotify_put_group(mark->group); | ||
113 | mark->free_mark(mark); | 115 | mark->free_mark(mark); |
116 | } | ||
114 | } | 117 | } |
115 | 118 | ||
116 | /* | 119 | /* |
@@ -118,14 +121,14 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) | |||
118 | * The caller had better be holding a reference to this mark so we don't actually | 121 | * The caller had better be holding a reference to this mark so we don't actually |
119 | * do the final put under the mark->lock | 122 | * do the final put under the mark->lock |
120 | */ | 123 | */ |
121 | void fsnotify_destroy_mark(struct fsnotify_mark *mark) | 124 | void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, |
125 | struct fsnotify_group *group) | ||
122 | { | 126 | { |
123 | struct fsnotify_group *group; | ||
124 | struct inode *inode = NULL; | 127 | struct inode *inode = NULL; |
125 | 128 | ||
126 | spin_lock(&mark->lock); | 129 | BUG_ON(!mutex_is_locked(&group->mark_mutex)); |
127 | 130 | ||
128 | group = mark->group; | 131 | spin_lock(&mark->lock); |
129 | 132 | ||
130 | /* something else already called this function on this mark */ | 133 | /* something else already called this function on this mark */ |
131 | if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { | 134 | if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { |
@@ -135,8 +138,6 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) | |||
135 | 138 | ||
136 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; | 139 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; |
137 | 140 | ||
138 | spin_lock(&group->mark_lock); | ||
139 | |||
140 | if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { | 141 | if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { |
141 | inode = mark->i.inode; | 142 | inode = mark->i.inode; |
142 | fsnotify_destroy_inode_mark(mark); | 143 | fsnotify_destroy_inode_mark(mark); |
@@ -147,13 +148,22 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) | |||
147 | 148 | ||
148 | list_del_init(&mark->g_list); | 149 | list_del_init(&mark->g_list); |
149 | 150 | ||
150 | spin_unlock(&group->mark_lock); | ||
151 | spin_unlock(&mark->lock); | 151 | spin_unlock(&mark->lock); |
152 | 152 | ||
153 | if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) | ||
154 | iput(inode); | ||
155 | /* release lock temporarily */ | ||
156 | mutex_unlock(&group->mark_mutex); | ||
157 | |||
153 | spin_lock(&destroy_lock); | 158 | spin_lock(&destroy_lock); |
154 | list_add(&mark->destroy_list, &destroy_list); | 159 | list_add(&mark->destroy_list, &destroy_list); |
155 | spin_unlock(&destroy_lock); | 160 | spin_unlock(&destroy_lock); |
156 | wake_up(&destroy_waitq); | 161 | wake_up(&destroy_waitq); |
162 | /* | ||
163 | * We don't necessarily have a ref on mark from caller so the above destroy | ||
164 | * may have actually freed it, unless this group provides a 'freeing_mark' | ||
165 | * function which must be holding a reference. | ||
166 | */ | ||
157 | 167 | ||
158 | /* | 168 | /* |
159 | * Some groups like to know that marks are being freed. This is a | 169 | * Some groups like to know that marks are being freed. This is a |
@@ -175,21 +185,17 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) | |||
175 | * is just a lazy update (and could be a perf win...) | 185 | * is just a lazy update (and could be a perf win...) |
176 | */ | 186 | */ |
177 | 187 | ||
178 | if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) | 188 | atomic_dec(&group->num_marks); |
179 | iput(inode); | ||
180 | 189 | ||
181 | /* | 190 | mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); |
182 | * We don't necessarily have a ref on mark from caller so the above iput | 191 | } |
183 | * may have already destroyed it. Don't touch from now on. | ||
184 | */ | ||
185 | 192 | ||
186 | /* | 193 | void fsnotify_destroy_mark(struct fsnotify_mark *mark, |
187 | * it's possible that this group tried to destroy itself, but this | 194 | struct fsnotify_group *group) |
188 | * this mark was simultaneously being freed by inode. If that's the | 195 | { |
189 | * case, we finish freeing the group here. | 196 | mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); |
190 | */ | 197 | fsnotify_destroy_mark_locked(mark, group); |
191 | if (unlikely(atomic_dec_and_test(&group->num_marks))) | 198 | mutex_unlock(&group->mark_mutex); |
192 | fsnotify_final_destroy_group(group); | ||
193 | } | 199 | } |
194 | 200 | ||
195 | void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) | 201 | void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) |
@@ -214,26 +220,26 @@ void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mas | |||
214 | * These marks may be used for the fsnotify backend to determine which | 220 | * These marks may be used for the fsnotify backend to determine which |
215 | * event types should be delivered to which group. | 221 | * event types should be delivered to which group. |
216 | */ | 222 | */ |
217 | int fsnotify_add_mark(struct fsnotify_mark *mark, | 223 | int fsnotify_add_mark_locked(struct fsnotify_mark *mark, |
218 | struct fsnotify_group *group, struct inode *inode, | 224 | struct fsnotify_group *group, struct inode *inode, |
219 | struct vfsmount *mnt, int allow_dups) | 225 | struct vfsmount *mnt, int allow_dups) |
220 | { | 226 | { |
221 | int ret = 0; | 227 | int ret = 0; |
222 | 228 | ||
223 | BUG_ON(inode && mnt); | 229 | BUG_ON(inode && mnt); |
224 | BUG_ON(!inode && !mnt); | 230 | BUG_ON(!inode && !mnt); |
231 | BUG_ON(!mutex_is_locked(&group->mark_mutex)); | ||
225 | 232 | ||
226 | /* | 233 | /* |
227 | * LOCKING ORDER!!!! | 234 | * LOCKING ORDER!!!! |
235 | * group->mark_mutex | ||
228 | * mark->lock | 236 | * mark->lock |
229 | * group->mark_lock | ||
230 | * inode->i_lock | 237 | * inode->i_lock |
231 | */ | 238 | */ |
232 | spin_lock(&mark->lock); | 239 | spin_lock(&mark->lock); |
233 | spin_lock(&group->mark_lock); | ||
234 | |||
235 | mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; | 240 | mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; |
236 | 241 | ||
242 | fsnotify_get_group(group); | ||
237 | mark->group = group; | 243 | mark->group = group; |
238 | list_add(&mark->g_list, &group->marks_list); | 244 | list_add(&mark->g_list, &group->marks_list); |
239 | atomic_inc(&group->num_marks); | 245 | atomic_inc(&group->num_marks); |
@@ -251,11 +257,8 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, | |||
251 | BUG(); | 257 | BUG(); |
252 | } | 258 | } |
253 | 259 | ||
254 | spin_unlock(&group->mark_lock); | ||
255 | |||
256 | /* this will pin the object if appropriate */ | 260 | /* this will pin the object if appropriate */ |
257 | fsnotify_set_mark_mask_locked(mark, mark->mask); | 261 | fsnotify_set_mark_mask_locked(mark, mark->mask); |
258 | |||
259 | spin_unlock(&mark->lock); | 262 | spin_unlock(&mark->lock); |
260 | 263 | ||
261 | if (inode) | 264 | if (inode) |
@@ -265,10 +268,10 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, | |||
265 | err: | 268 | err: |
266 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; | 269 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; |
267 | list_del_init(&mark->g_list); | 270 | list_del_init(&mark->g_list); |
271 | fsnotify_put_group(group); | ||
268 | mark->group = NULL; | 272 | mark->group = NULL; |
269 | atomic_dec(&group->num_marks); | 273 | atomic_dec(&group->num_marks); |
270 | 274 | ||
271 | spin_unlock(&group->mark_lock); | ||
272 | spin_unlock(&mark->lock); | 275 | spin_unlock(&mark->lock); |
273 | 276 | ||
274 | spin_lock(&destroy_lock); | 277 | spin_lock(&destroy_lock); |
@@ -279,6 +282,16 @@ err: | |||
279 | return ret; | 282 | return ret; |
280 | } | 283 | } |
281 | 284 | ||
285 | int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, | ||
286 | struct inode *inode, struct vfsmount *mnt, int allow_dups) | ||
287 | { | ||
288 | int ret; | ||
289 | mutex_lock(&group->mark_mutex); | ||
290 | ret = fsnotify_add_mark_locked(mark, group, inode, mnt, allow_dups); | ||
291 | mutex_unlock(&group->mark_mutex); | ||
292 | return ret; | ||
293 | } | ||
294 | |||
282 | /* | 295 | /* |
283 | * clear any marks in a group in which mark->flags & flags is true | 296 | * clear any marks in a group in which mark->flags & flags is true |
284 | */ | 297 | */ |
@@ -286,22 +299,16 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, | |||
286 | unsigned int flags) | 299 | unsigned int flags) |
287 | { | 300 | { |
288 | struct fsnotify_mark *lmark, *mark; | 301 | struct fsnotify_mark *lmark, *mark; |
289 | LIST_HEAD(free_list); | ||
290 | 302 | ||
291 | spin_lock(&group->mark_lock); | 303 | mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); |
292 | list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { | 304 | list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { |
293 | if (mark->flags & flags) { | 305 | if (mark->flags & flags) { |
294 | list_add(&mark->free_g_list, &free_list); | ||
295 | list_del_init(&mark->g_list); | ||
296 | fsnotify_get_mark(mark); | 306 | fsnotify_get_mark(mark); |
307 | fsnotify_destroy_mark_locked(mark, group); | ||
308 | fsnotify_put_mark(mark); | ||
297 | } | 309 | } |
298 | } | 310 | } |
299 | spin_unlock(&group->mark_lock); | 311 | mutex_unlock(&group->mark_mutex); |
300 | |||
301 | list_for_each_entry_safe(mark, lmark, &free_list, free_g_list) { | ||
302 | fsnotify_destroy_mark(mark); | ||
303 | fsnotify_put_mark(mark); | ||
304 | } | ||
305 | } | 312 | } |
306 | 313 | ||
307 | /* | 314 | /* |
@@ -317,6 +324,8 @@ void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *ol | |||
317 | assert_spin_locked(&old->lock); | 324 | assert_spin_locked(&old->lock); |
318 | new->i.inode = old->i.inode; | 325 | new->i.inode = old->i.inode; |
319 | new->m.mnt = old->m.mnt; | 326 | new->m.mnt = old->m.mnt; |
327 | if (old->group) | ||
328 | fsnotify_get_group(old->group); | ||
320 | new->group = old->group; | 329 | new->group = old->group; |
321 | new->mask = old->mask; | 330 | new->mask = old->mask; |
322 | new->free_mark = old->free_mark; | 331 | new->free_mark = old->free_mark; |
diff --git a/fs/notify/notification.c b/fs/notify/notification.c index 48cb994e4922..7b51b05f160c 100644 --- a/fs/notify/notification.c +++ b/fs/notify/notification.c | |||
@@ -225,6 +225,7 @@ alloc_holder: | |||
225 | mutex_unlock(&group->notification_mutex); | 225 | mutex_unlock(&group->notification_mutex); |
226 | 226 | ||
227 | wake_up(&group->notification_waitq); | 227 | wake_up(&group->notification_waitq); |
228 | kill_fasync(&group->fsn_fa, SIGIO, POLL_IN); | ||
228 | return return_event; | 229 | return return_event; |
229 | } | 230 | } |
230 | 231 | ||
diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c index b7b4b0e8554f..4df58b8ea64a 100644 --- a/fs/notify/vfsmount_mark.c +++ b/fs/notify/vfsmount_mark.c | |||
@@ -46,8 +46,16 @@ void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) | |||
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 | list_for_each_entry_safe(mark, lmark, &free_list, m.free_m_list) { |
49 | fsnotify_destroy_mark(mark); | 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); | ||
50 | fsnotify_put_mark(mark); | 57 | fsnotify_put_mark(mark); |
58 | fsnotify_put_group(group); | ||
51 | } | 59 | } |
52 | } | 60 | } |
53 | 61 | ||
@@ -88,8 +96,8 @@ void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark) | |||
88 | { | 96 | { |
89 | struct vfsmount *mnt = mark->m.mnt; | 97 | struct vfsmount *mnt = mark->m.mnt; |
90 | 98 | ||
99 | BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); | ||
91 | assert_spin_locked(&mark->lock); | 100 | assert_spin_locked(&mark->lock); |
92 | assert_spin_locked(&mark->group->mark_lock); | ||
93 | 101 | ||
94 | spin_lock(&mnt->mnt_root->d_lock); | 102 | spin_lock(&mnt->mnt_root->d_lock); |
95 | 103 | ||
@@ -151,8 +159,8 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | |||
151 | 159 | ||
152 | mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; | 160 | mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; |
153 | 161 | ||
162 | BUG_ON(!mutex_is_locked(&group->mark_mutex)); | ||
154 | assert_spin_locked(&mark->lock); | 163 | assert_spin_locked(&mark->lock); |
155 | assert_spin_locked(&group->mark_lock); | ||
156 | 164 | ||
157 | spin_lock(&mnt->mnt_root->d_lock); | 165 | spin_lock(&mnt->mnt_root->d_lock); |
158 | 166 | ||
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 63d966d5c2ea..d5b0910d4961 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h | |||
@@ -88,9 +88,10 @@ struct fsnotify_event_private_data; | |||
88 | * if the group is interested in this event. | 88 | * if the group is interested in this event. |
89 | * handle_event - main call for a group to handle an fs event | 89 | * handle_event - main call for a group to handle an fs event |
90 | * free_group_priv - called when a group refcnt hits 0 to clean up the private union | 90 | * free_group_priv - called when a group refcnt hits 0 to clean up the private union |
91 | * freeing-mark - this means that a mark has been flagged to die when everything | 91 | * freeing_mark - called when a mark is being destroyed for some reason. The group |
92 | * finishes using it. The function is supplied with what must be a | 92 | * MUST be holding a reference on each mark and that reference must be |
93 | * valid group and inode to use to clean up. | 93 | * dropped in this function. inotify uses this function to send |
94 | * userspace messages that marks have been removed. | ||
94 | */ | 95 | */ |
95 | struct fsnotify_ops { | 96 | struct fsnotify_ops { |
96 | bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode, | 97 | bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode, |
@@ -141,12 +142,14 @@ struct fsnotify_group { | |||
141 | unsigned int priority; | 142 | unsigned int priority; |
142 | 143 | ||
143 | /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */ | 144 | /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */ |
144 | spinlock_t mark_lock; /* protect marks_list */ | 145 | struct mutex mark_mutex; /* protect marks_list */ |
145 | atomic_t num_marks; /* 1 for each mark and 1 for not being | 146 | atomic_t num_marks; /* 1 for each mark and 1 for not being |
146 | * past the point of no return when freeing | 147 | * past the point of no return when freeing |
147 | * a group */ | 148 | * a group */ |
148 | struct list_head marks_list; /* all inode marks for this group */ | 149 | struct list_head marks_list; /* all inode marks for this group */ |
149 | 150 | ||
151 | struct fasync_struct *fsn_fa; /* async notification */ | ||
152 | |||
150 | /* groups can define private fields here or use the void *private */ | 153 | /* groups can define private fields here or use the void *private */ |
151 | union { | 154 | union { |
152 | void *private; | 155 | void *private; |
@@ -155,7 +158,6 @@ struct fsnotify_group { | |||
155 | spinlock_t idr_lock; | 158 | spinlock_t idr_lock; |
156 | struct idr idr; | 159 | struct idr idr; |
157 | u32 last_wd; | 160 | u32 last_wd; |
158 | struct fasync_struct *fa; /* async notification */ | ||
159 | struct user_struct *user; | 161 | struct user_struct *user; |
160 | } inotify_data; | 162 | } inotify_data; |
161 | #endif | 163 | #endif |
@@ -287,7 +289,6 @@ struct fsnotify_mark { | |||
287 | struct fsnotify_inode_mark i; | 289 | struct fsnotify_inode_mark i; |
288 | struct fsnotify_vfsmount_mark m; | 290 | struct fsnotify_vfsmount_mark m; |
289 | }; | 291 | }; |
290 | struct list_head free_g_list; /* tmp list used when freeing this mark */ | ||
291 | __u32 ignored_mask; /* events types to ignore */ | 292 | __u32 ignored_mask; /* events types to ignore */ |
292 | #define FSNOTIFY_MARK_FLAG_INODE 0x01 | 293 | #define FSNOTIFY_MARK_FLAG_INODE 0x01 |
293 | #define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02 | 294 | #define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02 |
@@ -360,11 +361,16 @@ static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode | |||
360 | 361 | ||
361 | /* called from fsnotify listeners, such as fanotify or dnotify */ | 362 | /* called from fsnotify listeners, such as fanotify or dnotify */ |
362 | 363 | ||
363 | /* get a reference to an existing or create a new group */ | 364 | /* create a new group */ |
364 | extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops); | 365 | extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops); |
366 | /* get reference to a group */ | ||
367 | extern void fsnotify_get_group(struct fsnotify_group *group); | ||
365 | /* drop reference on a group from fsnotify_alloc_group */ | 368 | /* drop reference on a group from fsnotify_alloc_group */ |
366 | extern void fsnotify_put_group(struct fsnotify_group *group); | 369 | extern void fsnotify_put_group(struct fsnotify_group *group); |
367 | 370 | /* destroy group */ | |
371 | extern void fsnotify_destroy_group(struct fsnotify_group *group); | ||
372 | /* fasync handler function */ | ||
373 | extern int fsnotify_fasync(int fd, struct file *file, int on); | ||
368 | /* take a reference to an event */ | 374 | /* take a reference to an event */ |
369 | extern void fsnotify_get_event(struct fsnotify_event *event); | 375 | extern void fsnotify_get_event(struct fsnotify_event *event); |
370 | extern void fsnotify_put_event(struct fsnotify_event *event); | 376 | extern void fsnotify_put_event(struct fsnotify_event *event); |
@@ -405,8 +411,13 @@ extern void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask | |||
405 | /* attach the mark to both the group and the inode */ | 411 | /* attach the mark to both the group and the inode */ |
406 | extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, | 412 | extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, |
407 | struct inode *inode, struct vfsmount *mnt, int allow_dups); | 413 | struct inode *inode, struct vfsmount *mnt, int allow_dups); |
408 | /* given a mark, flag it to be freed when all references are dropped */ | 414 | extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct fsnotify_group *group, |
409 | extern void fsnotify_destroy_mark(struct fsnotify_mark *mark); | 415 | struct inode *inode, struct vfsmount *mnt, int allow_dups); |
416 | /* given a group and a mark, flag mark to be freed when all references are dropped */ | ||
417 | extern void fsnotify_destroy_mark(struct fsnotify_mark *mark, | ||
418 | struct fsnotify_group *group); | ||
419 | extern void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, | ||
420 | struct fsnotify_group *group); | ||
410 | /* run all the marks in a group, and clear all of the vfsmount marks */ | 421 | /* run all the marks in a group, and clear all of the vfsmount marks */ |
411 | extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group); | 422 | extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group); |
412 | /* run all the marks in a group, and clear all of the inode marks */ | 423 | /* run all the marks in a group, and clear all of the inode marks */ |
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index ed206fd88cca..e81175ef25f8 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c | |||
@@ -249,7 +249,7 @@ static void untag_chunk(struct node *p) | |||
249 | list_del_rcu(&chunk->hash); | 249 | list_del_rcu(&chunk->hash); |
250 | spin_unlock(&hash_lock); | 250 | spin_unlock(&hash_lock); |
251 | spin_unlock(&entry->lock); | 251 | spin_unlock(&entry->lock); |
252 | fsnotify_destroy_mark(entry); | 252 | fsnotify_destroy_mark(entry, audit_tree_group); |
253 | goto out; | 253 | goto out; |
254 | } | 254 | } |
255 | 255 | ||
@@ -291,7 +291,7 @@ static void untag_chunk(struct node *p) | |||
291 | owner->root = new; | 291 | owner->root = new; |
292 | spin_unlock(&hash_lock); | 292 | spin_unlock(&hash_lock); |
293 | spin_unlock(&entry->lock); | 293 | spin_unlock(&entry->lock); |
294 | fsnotify_destroy_mark(entry); | 294 | fsnotify_destroy_mark(entry, audit_tree_group); |
295 | fsnotify_put_mark(&new->mark); /* drop initial reference */ | 295 | fsnotify_put_mark(&new->mark); /* drop initial reference */ |
296 | goto out; | 296 | goto out; |
297 | 297 | ||
@@ -331,7 +331,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree) | |||
331 | spin_unlock(&hash_lock); | 331 | spin_unlock(&hash_lock); |
332 | chunk->dead = 1; | 332 | chunk->dead = 1; |
333 | spin_unlock(&entry->lock); | 333 | spin_unlock(&entry->lock); |
334 | fsnotify_destroy_mark(entry); | 334 | fsnotify_destroy_mark(entry, audit_tree_group); |
335 | fsnotify_put_mark(entry); | 335 | fsnotify_put_mark(entry); |
336 | return 0; | 336 | return 0; |
337 | } | 337 | } |
@@ -412,7 +412,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) | |||
412 | spin_unlock(&chunk_entry->lock); | 412 | spin_unlock(&chunk_entry->lock); |
413 | spin_unlock(&old_entry->lock); | 413 | spin_unlock(&old_entry->lock); |
414 | 414 | ||
415 | fsnotify_destroy_mark(chunk_entry); | 415 | fsnotify_destroy_mark(chunk_entry, audit_tree_group); |
416 | 416 | ||
417 | fsnotify_put_mark(chunk_entry); | 417 | fsnotify_put_mark(chunk_entry); |
418 | fsnotify_put_mark(old_entry); | 418 | fsnotify_put_mark(old_entry); |
@@ -443,7 +443,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) | |||
443 | spin_unlock(&hash_lock); | 443 | spin_unlock(&hash_lock); |
444 | spin_unlock(&chunk_entry->lock); | 444 | spin_unlock(&chunk_entry->lock); |
445 | spin_unlock(&old_entry->lock); | 445 | spin_unlock(&old_entry->lock); |
446 | fsnotify_destroy_mark(old_entry); | 446 | fsnotify_destroy_mark(old_entry, audit_tree_group); |
447 | fsnotify_put_mark(chunk_entry); /* drop initial reference */ | 447 | fsnotify_put_mark(chunk_entry); /* drop initial reference */ |
448 | fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */ | 448 | fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */ |
449 | return 0; | 449 | return 0; |
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index 9a9ae6e3d290..4a599f699adc 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c | |||
@@ -350,7 +350,7 @@ static void audit_remove_parent_watches(struct audit_parent *parent) | |||
350 | } | 350 | } |
351 | mutex_unlock(&audit_filter_mutex); | 351 | mutex_unlock(&audit_filter_mutex); |
352 | 352 | ||
353 | fsnotify_destroy_mark(&parent->mark); | 353 | fsnotify_destroy_mark(&parent->mark, audit_watch_group); |
354 | } | 354 | } |
355 | 355 | ||
356 | /* Get path information necessary for adding watches. */ | 356 | /* Get path information necessary for adding watches. */ |
@@ -457,7 +457,7 @@ void audit_remove_watch_rule(struct audit_krule *krule) | |||
457 | 457 | ||
458 | if (list_empty(&parent->watches)) { | 458 | if (list_empty(&parent->watches)) { |
459 | audit_get_parent(parent); | 459 | audit_get_parent(parent); |
460 | fsnotify_destroy_mark(&parent->mark); | 460 | fsnotify_destroy_mark(&parent->mark, audit_watch_group); |
461 | audit_put_parent(parent); | 461 | audit_put_parent(parent); |
462 | } | 462 | } |
463 | } | 463 | } |