diff options
Diffstat (limited to 'fs/notify')
-rw-r--r-- | fs/notify/dnotify/dnotify.c | 2 | ||||
-rw-r--r-- | fs/notify/fanotify/fanotify.c | 8 | ||||
-rw-r--r-- | fs/notify/fanotify/fanotify_user.c | 13 | ||||
-rw-r--r-- | fs/notify/fsnotify.c | 2 | ||||
-rw-r--r-- | fs/notify/group.c | 8 | ||||
-rw-r--r-- | fs/notify/inotify/inotify.h | 2 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_fsnotify.c | 3 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_user.c | 14 | ||||
-rw-r--r-- | fs/notify/notification.c | 20 |
9 files changed, 58 insertions, 14 deletions
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c index 0b9ff4395e6a..abc8cbcfe90e 100644 --- a/fs/notify/dnotify/dnotify.c +++ b/fs/notify/dnotify/dnotify.c | |||
@@ -86,7 +86,7 @@ static int dnotify_handle_event(struct fsnotify_group *group, | |||
86 | struct fsnotify_mark *inode_mark, | 86 | struct fsnotify_mark *inode_mark, |
87 | struct fsnotify_mark *vfsmount_mark, | 87 | struct fsnotify_mark *vfsmount_mark, |
88 | u32 mask, void *data, int data_type, | 88 | u32 mask, void *data, int data_type, |
89 | const unsigned char *file_name) | 89 | const unsigned char *file_name, u32 cookie) |
90 | { | 90 | { |
91 | struct dnotify_mark *dn_mark; | 91 | struct dnotify_mark *dn_mark; |
92 | struct dnotify_struct *dn; | 92 | struct dnotify_struct *dn; |
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 0e792f5e3147..dc638f786d5c 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c | |||
@@ -147,7 +147,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, | |||
147 | struct fsnotify_mark *inode_mark, | 147 | struct fsnotify_mark *inode_mark, |
148 | struct fsnotify_mark *fanotify_mark, | 148 | struct fsnotify_mark *fanotify_mark, |
149 | u32 mask, void *data, int data_type, | 149 | u32 mask, void *data, int data_type, |
150 | const unsigned char *file_name) | 150 | const unsigned char *file_name, u32 cookie) |
151 | { | 151 | { |
152 | int ret = 0; | 152 | int ret = 0; |
153 | struct fanotify_event_info *event; | 153 | struct fanotify_event_info *event; |
@@ -192,10 +192,12 @@ static int fanotify_handle_event(struct fsnotify_group *group, | |||
192 | 192 | ||
193 | ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge); | 193 | ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge); |
194 | if (ret) { | 194 | if (ret) { |
195 | BUG_ON(mask & FAN_ALL_PERM_EVENTS); | 195 | /* Permission events shouldn't be merged */ |
196 | BUG_ON(ret == 1 && mask & FAN_ALL_PERM_EVENTS); | ||
196 | /* Our event wasn't used in the end. Free it. */ | 197 | /* Our event wasn't used in the end. Free it. */ |
197 | fsnotify_destroy_event(group, fsn_event); | 198 | fsnotify_destroy_event(group, fsn_event); |
198 | ret = 0; | 199 | |
200 | return 0; | ||
199 | } | 201 | } |
200 | 202 | ||
201 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | 203 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS |
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index b6175fa11bf8..287a22c04149 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c | |||
@@ -698,6 +698,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) | |||
698 | struct fsnotify_group *group; | 698 | struct fsnotify_group *group; |
699 | int f_flags, fd; | 699 | int f_flags, fd; |
700 | struct user_struct *user; | 700 | struct user_struct *user; |
701 | struct fanotify_event_info *oevent; | ||
701 | 702 | ||
702 | pr_debug("%s: flags=%d event_f_flags=%d\n", | 703 | pr_debug("%s: flags=%d event_f_flags=%d\n", |
703 | __func__, flags, event_f_flags); | 704 | __func__, flags, event_f_flags); |
@@ -730,8 +731,20 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) | |||
730 | group->fanotify_data.user = user; | 731 | group->fanotify_data.user = user; |
731 | atomic_inc(&user->fanotify_listeners); | 732 | atomic_inc(&user->fanotify_listeners); |
732 | 733 | ||
734 | oevent = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL); | ||
735 | if (unlikely(!oevent)) { | ||
736 | fd = -ENOMEM; | ||
737 | goto out_destroy_group; | ||
738 | } | ||
739 | group->overflow_event = &oevent->fse; | ||
740 | fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW); | ||
741 | oevent->tgid = get_pid(task_tgid(current)); | ||
742 | oevent->path.mnt = NULL; | ||
743 | oevent->path.dentry = NULL; | ||
744 | |||
733 | group->fanotify_data.f_flags = event_f_flags; | 745 | group->fanotify_data.f_flags = event_f_flags; |
734 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | 746 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS |
747 | oevent->response = 0; | ||
735 | mutex_init(&group->fanotify_data.access_mutex); | 748 | mutex_init(&group->fanotify_data.access_mutex); |
736 | init_waitqueue_head(&group->fanotify_data.access_waitq); | 749 | init_waitqueue_head(&group->fanotify_data.access_waitq); |
737 | INIT_LIST_HEAD(&group->fanotify_data.access_list); | 750 | INIT_LIST_HEAD(&group->fanotify_data.access_list); |
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 1d4e1ea2f37c..9d3e9c50066a 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c | |||
@@ -179,7 +179,7 @@ static int send_to_group(struct inode *to_tell, | |||
179 | 179 | ||
180 | return group->ops->handle_event(group, to_tell, inode_mark, | 180 | return group->ops->handle_event(group, to_tell, inode_mark, |
181 | vfsmount_mark, mask, data, data_is, | 181 | vfsmount_mark, mask, data, data_is, |
182 | file_name); | 182 | file_name, cookie); |
183 | } | 183 | } |
184 | 184 | ||
185 | /* | 185 | /* |
diff --git a/fs/notify/group.c b/fs/notify/group.c index ee674fe2cec7..ad1995980456 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c | |||
@@ -55,6 +55,13 @@ void fsnotify_destroy_group(struct fsnotify_group *group) | |||
55 | /* clear the notification queue of all events */ | 55 | /* clear the notification queue of all events */ |
56 | fsnotify_flush_notify(group); | 56 | fsnotify_flush_notify(group); |
57 | 57 | ||
58 | /* | ||
59 | * Destroy overflow event (we cannot use fsnotify_destroy_event() as | ||
60 | * that deliberately ignores overflow events. | ||
61 | */ | ||
62 | if (group->overflow_event) | ||
63 | group->ops->free_event(group->overflow_event); | ||
64 | |||
58 | fsnotify_put_group(group); | 65 | fsnotify_put_group(group); |
59 | } | 66 | } |
60 | 67 | ||
@@ -99,7 +106,6 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) | |||
99 | INIT_LIST_HEAD(&group->marks_list); | 106 | INIT_LIST_HEAD(&group->marks_list); |
100 | 107 | ||
101 | group->ops = ops; | 108 | group->ops = ops; |
102 | fsnotify_init_event(&group->overflow_event, NULL, FS_Q_OVERFLOW); | ||
103 | 109 | ||
104 | return group; | 110 | return group; |
105 | } | 111 | } |
diff --git a/fs/notify/inotify/inotify.h b/fs/notify/inotify/inotify.h index 485eef3f4407..ed855ef6f077 100644 --- a/fs/notify/inotify/inotify.h +++ b/fs/notify/inotify/inotify.h | |||
@@ -27,6 +27,6 @@ extern int inotify_handle_event(struct fsnotify_group *group, | |||
27 | struct fsnotify_mark *inode_mark, | 27 | struct fsnotify_mark *inode_mark, |
28 | struct fsnotify_mark *vfsmount_mark, | 28 | struct fsnotify_mark *vfsmount_mark, |
29 | u32 mask, void *data, int data_type, | 29 | u32 mask, void *data, int data_type, |
30 | const unsigned char *file_name); | 30 | const unsigned char *file_name, u32 cookie); |
31 | 31 | ||
32 | extern const struct fsnotify_ops inotify_fsnotify_ops; | 32 | extern const struct fsnotify_ops inotify_fsnotify_ops; |
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index d5ee56348bb8..43ab1e1a07a2 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c | |||
@@ -67,7 +67,7 @@ int inotify_handle_event(struct fsnotify_group *group, | |||
67 | struct fsnotify_mark *inode_mark, | 67 | struct fsnotify_mark *inode_mark, |
68 | struct fsnotify_mark *vfsmount_mark, | 68 | struct fsnotify_mark *vfsmount_mark, |
69 | u32 mask, void *data, int data_type, | 69 | u32 mask, void *data, int data_type, |
70 | const unsigned char *file_name) | 70 | const unsigned char *file_name, u32 cookie) |
71 | { | 71 | { |
72 | struct inotify_inode_mark *i_mark; | 72 | struct inotify_inode_mark *i_mark; |
73 | struct inotify_event_info *event; | 73 | struct inotify_event_info *event; |
@@ -103,6 +103,7 @@ int inotify_handle_event(struct fsnotify_group *group, | |||
103 | fsn_event = &event->fse; | 103 | fsn_event = &event->fse; |
104 | fsnotify_init_event(fsn_event, inode, mask); | 104 | fsnotify_init_event(fsn_event, inode, mask); |
105 | event->wd = i_mark->wd; | 105 | event->wd = i_mark->wd; |
106 | event->sync_cookie = cookie; | ||
106 | event->name_len = len; | 107 | event->name_len = len; |
107 | if (len) | 108 | if (len) |
108 | strcpy(event->name, file_name); | 109 | strcpy(event->name, file_name); |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 497395c8274b..78a2ca3966c3 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -495,7 +495,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark, | |||
495 | 495 | ||
496 | /* Queue ignore event for the watch */ | 496 | /* Queue ignore event for the watch */ |
497 | inotify_handle_event(group, NULL, fsn_mark, NULL, FS_IN_IGNORED, | 497 | inotify_handle_event(group, NULL, fsn_mark, NULL, FS_IN_IGNORED, |
498 | NULL, FSNOTIFY_EVENT_NONE, NULL); | 498 | NULL, FSNOTIFY_EVENT_NONE, NULL, 0); |
499 | 499 | ||
500 | i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark); | 500 | i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark); |
501 | /* remove this mark from the idr */ | 501 | /* remove this mark from the idr */ |
@@ -633,11 +633,23 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod | |||
633 | static struct fsnotify_group *inotify_new_group(unsigned int max_events) | 633 | static struct fsnotify_group *inotify_new_group(unsigned int max_events) |
634 | { | 634 | { |
635 | struct fsnotify_group *group; | 635 | struct fsnotify_group *group; |
636 | struct inotify_event_info *oevent; | ||
636 | 637 | ||
637 | group = fsnotify_alloc_group(&inotify_fsnotify_ops); | 638 | group = fsnotify_alloc_group(&inotify_fsnotify_ops); |
638 | if (IS_ERR(group)) | 639 | if (IS_ERR(group)) |
639 | return group; | 640 | return group; |
640 | 641 | ||
642 | oevent = kmalloc(sizeof(struct inotify_event_info), GFP_KERNEL); | ||
643 | if (unlikely(!oevent)) { | ||
644 | fsnotify_destroy_group(group); | ||
645 | return ERR_PTR(-ENOMEM); | ||
646 | } | ||
647 | group->overflow_event = &oevent->fse; | ||
648 | fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW); | ||
649 | oevent->wd = -1; | ||
650 | oevent->sync_cookie = 0; | ||
651 | oevent->name_len = 0; | ||
652 | |||
641 | group->max_events = max_events; | 653 | group->max_events = max_events; |
642 | 654 | ||
643 | spin_lock_init(&group->inotify_data.idr_lock); | 655 | spin_lock_init(&group->inotify_data.idr_lock); |
diff --git a/fs/notify/notification.c b/fs/notify/notification.c index 18b3c4427dca..1e58402171a5 100644 --- a/fs/notify/notification.c +++ b/fs/notify/notification.c | |||
@@ -80,7 +80,8 @@ void fsnotify_destroy_event(struct fsnotify_group *group, | |||
80 | /* | 80 | /* |
81 | * Add an event to the group notification queue. The group can later pull this | 81 | * Add an event to the group notification queue. The group can later pull this |
82 | * event off the queue to deal with. The function returns 0 if the event was | 82 | * event off the queue to deal with. The function returns 0 if the event was |
83 | * added to the queue, 1 if the event was merged with some other queued event. | 83 | * added to the queue, 1 if the event was merged with some other queued event, |
84 | * 2 if the queue of events has overflown. | ||
84 | */ | 85 | */ |
85 | int fsnotify_add_notify_event(struct fsnotify_group *group, | 86 | int fsnotify_add_notify_event(struct fsnotify_group *group, |
86 | struct fsnotify_event *event, | 87 | struct fsnotify_event *event, |
@@ -95,10 +96,14 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, | |||
95 | mutex_lock(&group->notification_mutex); | 96 | mutex_lock(&group->notification_mutex); |
96 | 97 | ||
97 | if (group->q_len >= group->max_events) { | 98 | if (group->q_len >= group->max_events) { |
99 | ret = 2; | ||
98 | /* Queue overflow event only if it isn't already queued */ | 100 | /* Queue overflow event only if it isn't already queued */ |
99 | if (list_empty(&group->overflow_event.list)) | 101 | if (!list_empty(&group->overflow_event->list)) { |
100 | event = &group->overflow_event; | 102 | mutex_unlock(&group->notification_mutex); |
101 | ret = 1; | 103 | return ret; |
104 | } | ||
105 | event = group->overflow_event; | ||
106 | goto queue; | ||
102 | } | 107 | } |
103 | 108 | ||
104 | if (!list_empty(list) && merge) { | 109 | if (!list_empty(list) && merge) { |
@@ -109,6 +114,7 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, | |||
109 | } | 114 | } |
110 | } | 115 | } |
111 | 116 | ||
117 | queue: | ||
112 | group->q_len++; | 118 | group->q_len++; |
113 | list_add_tail(&event->list, list); | 119 | list_add_tail(&event->list, list); |
114 | mutex_unlock(&group->notification_mutex); | 120 | mutex_unlock(&group->notification_mutex); |
@@ -132,7 +138,11 @@ struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group *group | |||
132 | 138 | ||
133 | event = list_first_entry(&group->notification_list, | 139 | event = list_first_entry(&group->notification_list, |
134 | struct fsnotify_event, list); | 140 | struct fsnotify_event, list); |
135 | list_del(&event->list); | 141 | /* |
142 | * We need to init list head for the case of overflow event so that | ||
143 | * check in fsnotify_add_notify_events() works | ||
144 | */ | ||
145 | list_del_init(&event->list); | ||
136 | group->q_len--; | 146 | group->q_len--; |
137 | 147 | ||
138 | return event; | 148 | return event; |