diff options
author | Eric Paris <eparis@redhat.com> | 2009-05-21 17:01:50 -0400 |
---|---|---|
committer | Eric Paris <eparis@redhat.com> | 2009-06-11 14:57:54 -0400 |
commit | e4aff117368cfdd3567ee41844d216d079b55173 (patch) | |
tree | c467bc38edc7ba3154bbf6875dca635b855e1c8c /fs/notify/notification.c | |
parent | 47882c6f51e8ef41fbbe2bbb746a1ea3228dd7ca (diff) |
fsnotify: allow groups to add private data to events
inotify needs per group information attached to events. This patch allows
groups to attach private information and implements a callback so that
information can be freed when an event is being destroyed.
Signed-off-by: Eric Paris <eparis@redhat.com>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/notify/notification.c')
-rw-r--r-- | fs/notify/notification.c | 52 |
1 files changed, 48 insertions, 4 deletions
diff --git a/fs/notify/notification.c b/fs/notify/notification.c index 346f6e5c355..959b73e756f 100644 --- a/fs/notify/notification.c +++ b/fs/notify/notification.c | |||
@@ -90,6 +90,8 @@ void fsnotify_put_event(struct fsnotify_event *event) | |||
90 | if (event->data_type == FSNOTIFY_EVENT_PATH) | 90 | if (event->data_type == FSNOTIFY_EVENT_PATH) |
91 | path_put(&event->path); | 91 | path_put(&event->path); |
92 | 92 | ||
93 | BUG_ON(!list_empty(&event->private_data_list)); | ||
94 | |||
93 | kfree(event->file_name); | 95 | kfree(event->file_name); |
94 | kmem_cache_free(fsnotify_event_cachep, event); | 96 | kmem_cache_free(fsnotify_event_cachep, event); |
95 | } | 97 | } |
@@ -106,7 +108,29 @@ void fsnotify_destroy_event_holder(struct fsnotify_event_holder *holder) | |||
106 | } | 108 | } |
107 | 109 | ||
108 | /* | 110 | /* |
109 | * check if 2 events contain the same information. | 111 | * Find the private data that the group previously attached to this event when |
112 | * the group added the event to the notification queue (fsnotify_add_notify_event) | ||
113 | */ | ||
114 | struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struct fsnotify_group *group, struct fsnotify_event *event) | ||
115 | { | ||
116 | struct fsnotify_event_private_data *lpriv; | ||
117 | struct fsnotify_event_private_data *priv = NULL; | ||
118 | |||
119 | assert_spin_locked(&event->lock); | ||
120 | |||
121 | list_for_each_entry(lpriv, &event->private_data_list, event_list) { | ||
122 | if (lpriv->group == group) { | ||
123 | priv = lpriv; | ||
124 | list_del(&priv->event_list); | ||
125 | break; | ||
126 | } | ||
127 | } | ||
128 | return priv; | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * Check if 2 events contain the same information. We do not compare private data | ||
133 | * but at this moment that isn't a problem for any know fsnotify listeners. | ||
110 | */ | 134 | */ |
111 | static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new) | 135 | static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new) |
112 | { | 136 | { |
@@ -134,13 +158,17 @@ static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new | |||
134 | * event off the queue to deal with. If the event is successfully added to the | 158 | * event off the queue to deal with. If the event is successfully added to the |
135 | * group's notification queue, a reference is taken on event. | 159 | * group's notification queue, a reference is taken on event. |
136 | */ | 160 | */ |
137 | int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event) | 161 | int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event, |
162 | struct fsnotify_event_private_data *priv) | ||
138 | { | 163 | { |
139 | struct fsnotify_event_holder *holder = NULL; | 164 | struct fsnotify_event_holder *holder = NULL; |
140 | struct list_head *list = &group->notification_list; | 165 | struct list_head *list = &group->notification_list; |
141 | struct fsnotify_event_holder *last_holder; | 166 | struct fsnotify_event_holder *last_holder; |
142 | struct fsnotify_event *last_event; | 167 | struct fsnotify_event *last_event; |
143 | 168 | ||
169 | /* easy to tell if priv was attached to the event */ | ||
170 | INIT_LIST_HEAD(&priv->event_list); | ||
171 | |||
144 | /* | 172 | /* |
145 | * There is one fsnotify_event_holder embedded inside each fsnotify_event. | 173 | * There is one fsnotify_event_holder embedded inside each fsnotify_event. |
146 | * Check if we expect to be able to use that holder. If not alloc a new | 174 | * Check if we expect to be able to use that holder. If not alloc a new |
@@ -158,8 +186,11 @@ alloc_holder: | |||
158 | 186 | ||
159 | mutex_lock(&group->notification_mutex); | 187 | mutex_lock(&group->notification_mutex); |
160 | 188 | ||
161 | if (group->q_len >= group->max_events) | 189 | if (group->q_len >= group->max_events) { |
162 | event = &q_overflow_event; | 190 | event = &q_overflow_event; |
191 | /* sorry, no private data on the overflow event */ | ||
192 | priv = NULL; | ||
193 | } | ||
163 | 194 | ||
164 | spin_lock(&event->lock); | 195 | spin_lock(&event->lock); |
165 | 196 | ||
@@ -183,7 +214,7 @@ alloc_holder: | |||
183 | mutex_unlock(&group->notification_mutex); | 214 | mutex_unlock(&group->notification_mutex); |
184 | if (holder != &event->holder) | 215 | if (holder != &event->holder) |
185 | fsnotify_destroy_event_holder(holder); | 216 | fsnotify_destroy_event_holder(holder); |
186 | return 0; | 217 | return -EEXIST; |
187 | } | 218 | } |
188 | } | 219 | } |
189 | 220 | ||
@@ -192,6 +223,8 @@ alloc_holder: | |||
192 | 223 | ||
193 | fsnotify_get_event(event); | 224 | fsnotify_get_event(event); |
194 | list_add_tail(&holder->event_list, list); | 225 | list_add_tail(&holder->event_list, list); |
226 | if (priv) | ||
227 | list_add_tail(&priv->event_list, &event->private_data_list); | ||
195 | spin_unlock(&event->lock); | 228 | spin_unlock(&event->lock); |
196 | mutex_unlock(&group->notification_mutex); | 229 | mutex_unlock(&group->notification_mutex); |
197 | 230 | ||
@@ -252,10 +285,19 @@ struct fsnotify_event *fsnotify_peek_notify_event(struct fsnotify_group *group) | |||
252 | void fsnotify_flush_notify(struct fsnotify_group *group) | 285 | void fsnotify_flush_notify(struct fsnotify_group *group) |
253 | { | 286 | { |
254 | struct fsnotify_event *event; | 287 | struct fsnotify_event *event; |
288 | struct fsnotify_event_private_data *priv; | ||
255 | 289 | ||
256 | mutex_lock(&group->notification_mutex); | 290 | mutex_lock(&group->notification_mutex); |
257 | while (!fsnotify_notify_queue_is_empty(group)) { | 291 | while (!fsnotify_notify_queue_is_empty(group)) { |
258 | event = fsnotify_remove_notify_event(group); | 292 | event = fsnotify_remove_notify_event(group); |
293 | /* if they don't implement free_event_priv they better not have attached any */ | ||
294 | if (group->ops->free_event_priv) { | ||
295 | spin_lock(&event->lock); | ||
296 | priv = fsnotify_remove_priv_from_event(group, event); | ||
297 | spin_unlock(&event->lock); | ||
298 | if (priv) | ||
299 | group->ops->free_event_priv(priv); | ||
300 | } | ||
259 | fsnotify_put_event(event); /* matches fsnotify_add_notify_event */ | 301 | fsnotify_put_event(event); /* matches fsnotify_add_notify_event */ |
260 | } | 302 | } |
261 | mutex_unlock(&group->notification_mutex); | 303 | mutex_unlock(&group->notification_mutex); |
@@ -274,6 +316,8 @@ static void initialize_event(struct fsnotify_event *event) | |||
274 | event->inode = NULL; | 316 | event->inode = NULL; |
275 | event->data_type = FSNOTIFY_EVENT_NONE; | 317 | event->data_type = FSNOTIFY_EVENT_NONE; |
276 | 318 | ||
319 | INIT_LIST_HEAD(&event->private_data_list); | ||
320 | |||
277 | event->to_tell = NULL; | 321 | event->to_tell = NULL; |
278 | 322 | ||
279 | event->file_name = NULL; | 323 | event->file_name = NULL; |