aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/notification.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/notify/notification.c')
-rw-r--r--fs/notify/notification.c236
1 files changed, 145 insertions, 91 deletions
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index b8bf53b4c108..d6c435adc7a2 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -31,6 +31,7 @@
31 * allocated and used. 31 * allocated and used.
32 */ 32 */
33 33
34#include <linux/file.h>
34#include <linux/fs.h> 35#include <linux/fs.h>
35#include <linux/init.h> 36#include <linux/init.h>
36#include <linux/kernel.h> 37#include <linux/kernel.h>
@@ -56,7 +57,7 @@ static struct kmem_cache *fsnotify_event_holder_cachep;
56 * it is needed. It's refcnt is set 1 at kernel init time and will never 57 * it is needed. It's refcnt is set 1 at kernel init time and will never
57 * get set to 0 so it will never get 'freed' 58 * get set to 0 so it will never get 'freed'
58 */ 59 */
59static struct fsnotify_event q_overflow_event; 60static struct fsnotify_event *q_overflow_event;
60static atomic_t fsnotify_sync_cookie = ATOMIC_INIT(0); 61static atomic_t fsnotify_sync_cookie = ATOMIC_INIT(0);
61 62
62/** 63/**
@@ -87,12 +88,15 @@ void fsnotify_put_event(struct fsnotify_event *event)
87 return; 88 return;
88 89
89 if (atomic_dec_and_test(&event->refcnt)) { 90 if (atomic_dec_and_test(&event->refcnt)) {
90 if (event->data_type == FSNOTIFY_EVENT_PATH) 91 pr_debug("%s: event=%p\n", __func__, event);
91 path_put(&event->path); 92
93 if (event->data_type == FSNOTIFY_EVENT_FILE)
94 fput(event->file);
92 95
93 BUG_ON(!list_empty(&event->private_data_list)); 96 BUG_ON(!list_empty(&event->private_data_list));
94 97
95 kfree(event->file_name); 98 kfree(event->file_name);
99 put_pid(event->tgid);
96 kmem_cache_free(fsnotify_event_cachep, event); 100 kmem_cache_free(fsnotify_event_cachep, event);
97 } 101 }
98} 102}
@@ -104,7 +108,8 @@ struct fsnotify_event_holder *fsnotify_alloc_event_holder(void)
104 108
105void fsnotify_destroy_event_holder(struct fsnotify_event_holder *holder) 109void fsnotify_destroy_event_holder(struct fsnotify_event_holder *holder)
106{ 110{
107 kmem_cache_free(fsnotify_event_holder_cachep, holder); 111 if (holder)
112 kmem_cache_free(fsnotify_event_holder_cachep, holder);
108} 113}
109 114
110/* 115/*
@@ -129,53 +134,20 @@ struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struct fsnot
129} 134}
130 135
131/* 136/*
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.
134 */
135static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new)
136{
137 if ((old->mask == new->mask) &&
138 (old->to_tell == new->to_tell) &&
139 (old->data_type == new->data_type) &&
140 (old->name_len == new->name_len)) {
141 switch (old->data_type) {
142 case (FSNOTIFY_EVENT_INODE):
143 /* remember, after old was put on the wait_q we aren't
144 * allowed to look at the inode any more, only thing
145 * left to check was if the file_name is the same */
146 if (!old->name_len ||
147 !strcmp(old->file_name, new->file_name))
148 return true;
149 break;
150 case (FSNOTIFY_EVENT_PATH):
151 if ((old->path.mnt == new->path.mnt) &&
152 (old->path.dentry == new->path.dentry))
153 return true;
154 break;
155 case (FSNOTIFY_EVENT_NONE):
156 if (old->mask & FS_Q_OVERFLOW)
157 return true;
158 else if (old->mask & FS_IN_IGNORED)
159 return false;
160 return false;
161 };
162 }
163 return false;
164}
165
166/*
167 * Add an event to the group notification queue. The group can later pull this 137 * Add an event to the group notification queue. The group can later pull this
168 * event off the queue to deal with. If the event is successfully added to the 138 * event off the queue to deal with. If the event is successfully added to the
169 * group's notification queue, a reference is taken on event. 139 * group's notification queue, a reference is taken on event.
170 */ 140 */
171int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event, 141struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
172 struct fsnotify_event_private_data *priv) 142 struct fsnotify_event_private_data *priv,
143 struct fsnotify_event *(*merge)(struct list_head *,
144 struct fsnotify_event *))
173{ 145{
146 struct fsnotify_event *return_event = NULL;
174 struct fsnotify_event_holder *holder = NULL; 147 struct fsnotify_event_holder *holder = NULL;
175 struct list_head *list = &group->notification_list; 148 struct list_head *list = &group->notification_list;
176 struct fsnotify_event_holder *last_holder; 149
177 struct fsnotify_event *last_event; 150 pr_debug("%s: group=%p event=%p priv=%p\n", __func__, group, event, priv);
178 int ret = 0;
179 151
180 /* 152 /*
181 * There is one fsnotify_event_holder embedded inside each fsnotify_event. 153 * There is one fsnotify_event_holder embedded inside each fsnotify_event.
@@ -189,18 +161,40 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_even
189alloc_holder: 161alloc_holder:
190 holder = fsnotify_alloc_event_holder(); 162 holder = fsnotify_alloc_event_holder();
191 if (!holder) 163 if (!holder)
192 return -ENOMEM; 164 return ERR_PTR(-ENOMEM);
193 } 165 }
194 166
195 mutex_lock(&group->notification_mutex); 167 mutex_lock(&group->notification_mutex);
196 168
197 if (group->q_len >= group->max_events) { 169 if (group->q_len >= group->max_events) {
198 event = &q_overflow_event; 170 event = q_overflow_event;
199 ret = -EOVERFLOW; 171
172 /*
173 * we need to return the overflow event
174 * which means we need a ref
175 */
176 fsnotify_get_event(event);
177 return_event = event;
178
200 /* sorry, no private data on the overflow event */ 179 /* sorry, no private data on the overflow event */
201 priv = NULL; 180 priv = NULL;
202 } 181 }
203 182
183 if (!list_empty(list) && merge) {
184 struct fsnotify_event *tmp;
185
186 tmp = merge(list, event);
187 if (tmp) {
188 mutex_unlock(&group->notification_mutex);
189
190 if (return_event)
191 fsnotify_put_event(return_event);
192 if (holder != &event->holder)
193 fsnotify_destroy_event_holder(holder);
194 return tmp;
195 }
196 }
197
204 spin_lock(&event->lock); 198 spin_lock(&event->lock);
205 199
206 if (list_empty(&event->holder.event_list)) { 200 if (list_empty(&event->holder.event_list)) {
@@ -212,19 +206,13 @@ alloc_holder:
212 * event holder was used, go back and get a new one */ 206 * event holder was used, go back and get a new one */
213 spin_unlock(&event->lock); 207 spin_unlock(&event->lock);
214 mutex_unlock(&group->notification_mutex); 208 mutex_unlock(&group->notification_mutex);
215 goto alloc_holder;
216 }
217 209
218 if (!list_empty(list)) { 210 if (return_event) {
219 last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list); 211 fsnotify_put_event(return_event);
220 last_event = last_holder->event; 212 return_event = NULL;
221 if (event_compare(last_event, event)) {
222 spin_unlock(&event->lock);
223 mutex_unlock(&group->notification_mutex);
224 if (holder != &event->holder)
225 fsnotify_destroy_event_holder(holder);
226 return -EEXIST;
227 } 213 }
214
215 goto alloc_holder;
228 } 216 }
229 217
230 group->q_len++; 218 group->q_len++;
@@ -238,7 +226,7 @@ alloc_holder:
238 mutex_unlock(&group->notification_mutex); 226 mutex_unlock(&group->notification_mutex);
239 227
240 wake_up(&group->notification_waitq); 228 wake_up(&group->notification_waitq);
241 return ret; 229 return return_event;
242} 230}
243 231
244/* 232/*
@@ -253,6 +241,8 @@ struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group *group
253 241
254 BUG_ON(!mutex_is_locked(&group->notification_mutex)); 242 BUG_ON(!mutex_is_locked(&group->notification_mutex));
255 243
244 pr_debug("%s: group=%p\n", __func__, group);
245
256 holder = list_first_entry(&group->notification_list, struct fsnotify_event_holder, event_list); 246 holder = list_first_entry(&group->notification_list, struct fsnotify_event_holder, event_list);
257 247
258 event = holder->event; 248 event = holder->event;
@@ -314,25 +304,82 @@ void fsnotify_flush_notify(struct fsnotify_group *group)
314 304
315static void initialize_event(struct fsnotify_event *event) 305static void initialize_event(struct fsnotify_event *event)
316{ 306{
317 event->holder.event = NULL;
318 INIT_LIST_HEAD(&event->holder.event_list); 307 INIT_LIST_HEAD(&event->holder.event_list);
319 atomic_set(&event->refcnt, 1); 308 atomic_set(&event->refcnt, 1);
320 309
321 spin_lock_init(&event->lock); 310 spin_lock_init(&event->lock);
322 311
323 event->path.dentry = NULL;
324 event->path.mnt = NULL;
325 event->inode = NULL;
326 event->data_type = FSNOTIFY_EVENT_NONE;
327
328 INIT_LIST_HEAD(&event->private_data_list); 312 INIT_LIST_HEAD(&event->private_data_list);
313}
329 314
330 event->to_tell = NULL; 315/*
316 * Caller damn well better be holding whatever mutex is protecting the
317 * old_holder->event_list and the new_event must be a clean event which
318 * cannot be found anywhere else in the kernel.
319 */
320int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
321 struct fsnotify_event *new_event)
322{
323 struct fsnotify_event *old_event = old_holder->event;
324 struct fsnotify_event_holder *new_holder = &new_event->holder;
331 325
332 event->file_name = NULL; 326 enum event_spinlock_class {
333 event->name_len = 0; 327 SPINLOCK_OLD,
328 SPINLOCK_NEW,
329 };
334 330
335 event->sync_cookie = 0; 331 pr_debug("%s: old_event=%p new_event=%p\n", __func__, old_event, new_event);
332
333 /*
334 * if the new_event's embedded holder is in use someone
335 * screwed up and didn't give us a clean new event.
336 */
337 BUG_ON(!list_empty(&new_holder->event_list));
338
339 spin_lock_nested(&old_event->lock, SPINLOCK_OLD);
340 spin_lock_nested(&new_event->lock, SPINLOCK_NEW);
341
342 new_holder->event = new_event;
343 list_replace_init(&old_holder->event_list, &new_holder->event_list);
344
345 spin_unlock(&new_event->lock);
346 spin_unlock(&old_event->lock);
347
348 /* event == holder means we are referenced through the in event holder */
349 if (old_holder != &old_event->holder)
350 fsnotify_destroy_event_holder(old_holder);
351
352 fsnotify_get_event(new_event); /* on the list take reference */
353 fsnotify_put_event(old_event); /* off the list, drop reference */
354
355 return 0;
356}
357
358struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event)
359{
360 struct fsnotify_event *event;
361
362 event = kmem_cache_alloc(fsnotify_event_cachep, GFP_KERNEL);
363 if (!event)
364 return NULL;
365
366 pr_debug("%s: old_event=%p new_event=%p\n", __func__, old_event, event);
367
368 memcpy(event, old_event, sizeof(*event));
369 initialize_event(event);
370
371 if (event->name_len) {
372 event->file_name = kstrdup(old_event->file_name, GFP_KERNEL);
373 if (!event->file_name) {
374 kmem_cache_free(fsnotify_event_cachep, event);
375 return NULL;
376 }
377 }
378 event->tgid = get_pid(old_event->tgid);
379 if (event->data_type == FSNOTIFY_EVENT_FILE)
380 get_file(event->file);
381
382 return event;
336} 383}
337 384
338/* 385/*
@@ -348,15 +395,18 @@ static void initialize_event(struct fsnotify_event *event)
348 * @name the filename, if available 395 * @name the filename, if available
349 */ 396 */
350struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, void *data, 397struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, void *data,
351 int data_type, const char *name, u32 cookie, 398 int data_type, const unsigned char *name,
352 gfp_t gfp) 399 u32 cookie, gfp_t gfp)
353{ 400{
354 struct fsnotify_event *event; 401 struct fsnotify_event *event;
355 402
356 event = kmem_cache_alloc(fsnotify_event_cachep, gfp); 403 event = kmem_cache_zalloc(fsnotify_event_cachep, gfp);
357 if (!event) 404 if (!event)
358 return NULL; 405 return NULL;
359 406
407 pr_debug("%s: event=%p to_tell=%p mask=%x data=%p data_type=%d\n",
408 __func__, event, to_tell, mask, data, data_type);
409
360 initialize_event(event); 410 initialize_event(event);
361 411
362 if (name) { 412 if (name) {
@@ -368,35 +418,36 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
368 event->name_len = strlen(event->file_name); 418 event->name_len = strlen(event->file_name);
369 } 419 }
370 420
421 event->tgid = get_pid(task_tgid(current));
371 event->sync_cookie = cookie; 422 event->sync_cookie = cookie;
372 event->to_tell = to_tell; 423 event->to_tell = to_tell;
424 event->data_type = data_type;
373 425
374 switch (data_type) { 426 switch (data_type) {
375 case FSNOTIFY_EVENT_FILE: { 427 case FSNOTIFY_EVENT_FILE: {
376 struct file *file = data; 428 event->file = data;
377 struct path *path = &file->f_path; 429 /*
378 event->path.dentry = path->dentry; 430 * if this file is about to disappear hold an extra reference
379 event->path.mnt = path->mnt; 431 * until we return to __fput so we don't have to worry about
380 path_get(&event->path); 432 * future get/put destroying the file under us or generating
381 event->data_type = FSNOTIFY_EVENT_PATH; 433 * additional events. Notice that we change f_mode without
382 break; 434 * holding f_lock. This is safe since this is the only possible
383 } 435 * reference to this object in the kernel (it was about to be
384 case FSNOTIFY_EVENT_PATH: { 436 * freed, remember?)
385 struct path *path = data; 437 */
386 event->path.dentry = path->dentry; 438 if (!atomic_long_read(&event->file->f_count)) {
387 event->path.mnt = path->mnt; 439 event->file->f_mode |= FMODE_NONOTIFY;
388 path_get(&event->path); 440 get_file(event->file);
389 event->data_type = FSNOTIFY_EVENT_PATH; 441 }
442 get_file(event->file);
390 break; 443 break;
391 } 444 }
392 case FSNOTIFY_EVENT_INODE: 445 case FSNOTIFY_EVENT_INODE:
393 event->inode = data; 446 event->inode = data;
394 event->data_type = FSNOTIFY_EVENT_INODE;
395 break; 447 break;
396 case FSNOTIFY_EVENT_NONE: 448 case FSNOTIFY_EVENT_NONE:
397 event->inode = NULL; 449 event->inode = NULL;
398 event->path.dentry = NULL; 450 event->file = NULL;
399 event->path.mnt = NULL;
400 break; 451 break;
401 default: 452 default:
402 BUG(); 453 BUG();
@@ -412,8 +463,11 @@ __init int fsnotify_notification_init(void)
412 fsnotify_event_cachep = KMEM_CACHE(fsnotify_event, SLAB_PANIC); 463 fsnotify_event_cachep = KMEM_CACHE(fsnotify_event, SLAB_PANIC);
413 fsnotify_event_holder_cachep = KMEM_CACHE(fsnotify_event_holder, SLAB_PANIC); 464 fsnotify_event_holder_cachep = KMEM_CACHE(fsnotify_event_holder, SLAB_PANIC);
414 465
415 initialize_event(&q_overflow_event); 466 q_overflow_event = fsnotify_create_event(NULL, FS_Q_OVERFLOW, NULL,
416 q_overflow_event.mask = FS_Q_OVERFLOW; 467 FSNOTIFY_EVENT_NONE, NULL, 0,
468 GFP_KERNEL);
469 if (!q_overflow_event)
470 panic("unable to allocate fsnotify q_overflow_event\n");
417 471
418 return 0; 472 return 0;
419} 473}