aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/inotify/inotify_user.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/notify/inotify/inotify_user.c')
-rw-r--r--fs/notify/inotify/inotify_user.c255
1 files changed, 175 insertions, 80 deletions
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index ff27a2965844..0e781bc88d1e 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -47,9 +47,6 @@
47 47
48static struct vfsmount *inotify_mnt __read_mostly; 48static struct vfsmount *inotify_mnt __read_mostly;
49 49
50/* this just sits here and wastes global memory. used to just pad userspace messages with zeros */
51static struct inotify_event nul_inotify_event;
52
53/* these are configurable via /proc/sys/fs/inotify/ */ 50/* these are configurable via /proc/sys/fs/inotify/ */
54static int inotify_max_user_instances __read_mostly; 51static int inotify_max_user_instances __read_mostly;
55static int inotify_max_queued_events __read_mostly; 52static int inotify_max_queued_events __read_mostly;
@@ -57,7 +54,6 @@ int inotify_max_user_watches __read_mostly;
57 54
58static struct kmem_cache *inotify_inode_mark_cachep __read_mostly; 55static struct kmem_cache *inotify_inode_mark_cachep __read_mostly;
59struct kmem_cache *event_priv_cachep __read_mostly; 56struct kmem_cache *event_priv_cachep __read_mostly;
60static struct fsnotify_event *inotify_ignored_event;
61 57
62/* 58/*
63 * When inotify registers a new group it increments this and uses that 59 * When inotify registers a new group it increments this and uses that
@@ -200,8 +196,10 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
200 inotify_free_event_priv(fsn_priv); 196 inotify_free_event_priv(fsn_priv);
201 } 197 }
202 198
203 /* round up event->name_len so it is a multiple of event_size */ 199 /* round up event->name_len so it is a multiple of event_size
204 name_len = roundup(event->name_len, event_size); 200 * plus an extra byte for the terminating '\0'.
201 */
202 name_len = roundup(event->name_len + 1, event_size);
205 inotify_event.len = name_len; 203 inotify_event.len = name_len;
206 204
207 inotify_event.mask = inotify_mask_to_arg(event->mask); 205 inotify_event.mask = inotify_mask_to_arg(event->mask);
@@ -225,8 +223,8 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
225 return -EFAULT; 223 return -EFAULT;
226 buf += event->name_len; 224 buf += event->name_len;
227 225
228 /* fill userspace with 0's from nul_inotify_event */ 226 /* fill userspace with 0's */
229 if (copy_to_user(buf, &nul_inotify_event, len_to_zero)) 227 if (clear_user(buf, len_to_zero))
230 return -EFAULT; 228 return -EFAULT;
231 buf += len_to_zero; 229 buf += len_to_zero;
232 event_size += name_len; 230 event_size += name_len;
@@ -366,20 +364,71 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
366} 364}
367 365
368/* 366/*
369 * Send IN_IGNORED for this wd, remove this wd from the idr, and drop the 367 * Remove the mark from the idr (if present) and drop the reference
370 * internal reference help on the mark because it is in the idr. 368 * on the mark because it was in the idr.
369 */
370static void inotify_remove_from_idr(struct fsnotify_group *group,
371 struct inotify_inode_mark_entry *ientry)
372{
373 struct idr *idr;
374 struct fsnotify_mark_entry *entry;
375 struct inotify_inode_mark_entry *found_ientry;
376 int wd;
377
378 spin_lock(&group->inotify_data.idr_lock);
379 idr = &group->inotify_data.idr;
380 wd = ientry->wd;
381
382 if (wd == -1)
383 goto out;
384
385 entry = idr_find(&group->inotify_data.idr, wd);
386 if (unlikely(!entry))
387 goto out;
388
389 found_ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
390 if (unlikely(found_ientry != ientry)) {
391 /* We found an entry in the idr with the right wd, but it's
392 * not the entry we were told to remove. eparis seriously
393 * fucked up somewhere. */
394 WARN_ON(1);
395 ientry->wd = -1;
396 goto out;
397 }
398
399 /* One ref for being in the idr, one ref held by the caller */
400 BUG_ON(atomic_read(&entry->refcnt) < 2);
401
402 idr_remove(idr, wd);
403 ientry->wd = -1;
404
405 /* removed from the idr, drop that ref */
406 fsnotify_put_mark(entry);
407out:
408 spin_unlock(&group->inotify_data.idr_lock);
409}
410
411/*
412 * Send IN_IGNORED for this wd, remove this wd from the idr.
371 */ 413 */
372void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, 414void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
373 struct fsnotify_group *group) 415 struct fsnotify_group *group)
374{ 416{
375 struct inotify_inode_mark_entry *ientry; 417 struct inotify_inode_mark_entry *ientry;
418 struct fsnotify_event *ignored_event;
376 struct inotify_event_private_data *event_priv; 419 struct inotify_event_private_data *event_priv;
377 struct fsnotify_event_private_data *fsn_event_priv; 420 struct fsnotify_event_private_data *fsn_event_priv;
378 struct idr *idr; 421 int ret;
422
423 ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL,
424 FSNOTIFY_EVENT_NONE, NULL, 0,
425 GFP_NOFS);
426 if (!ignored_event)
427 return;
379 428
380 ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); 429 ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
381 430
382 event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL); 431 event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS);
383 if (unlikely(!event_priv)) 432 if (unlikely(!event_priv))
384 goto skip_send_ignore; 433 goto skip_send_ignore;
385 434
@@ -388,22 +437,19 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
388 fsn_event_priv->group = group; 437 fsn_event_priv->group = group;
389 event_priv->wd = ientry->wd; 438 event_priv->wd = ientry->wd;
390 439
391 fsnotify_add_notify_event(group, inotify_ignored_event, fsn_event_priv); 440 ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv);
392 441 if (ret)
393 /* did the private data get added? */
394 if (list_empty(&fsn_event_priv->event_list))
395 inotify_free_event_priv(fsn_event_priv); 442 inotify_free_event_priv(fsn_event_priv);
396 443
397skip_send_ignore: 444skip_send_ignore:
398 445
446 /* matches the reference taken when the event was created */
447 fsnotify_put_event(ignored_event);
448
399 /* remove this entry from the idr */ 449 /* remove this entry from the idr */
400 spin_lock(&group->inotify_data.idr_lock); 450 inotify_remove_from_idr(group, ientry);
401 idr = &group->inotify_data.idr;
402 idr_remove(idr, ientry->wd);
403 spin_unlock(&group->inotify_data.idr_lock);
404 451
405 /* removed from idr, drop that reference */ 452 atomic_dec(&group->inotify_data.user->inotify_watches);
406 fsnotify_put_mark(entry);
407} 453}
408 454
409/* ding dong the mark is dead */ 455/* ding dong the mark is dead */
@@ -414,67 +460,29 @@ static void inotify_free_mark(struct fsnotify_mark_entry *entry)
414 kmem_cache_free(inotify_inode_mark_cachep, ientry); 460 kmem_cache_free(inotify_inode_mark_cachep, ientry);
415} 461}
416 462
417static int inotify_update_watch(struct fsnotify_group *group, struct inode *inode, u32 arg) 463static int inotify_update_existing_watch(struct fsnotify_group *group,
464 struct inode *inode,
465 u32 arg)
418{ 466{
419 struct fsnotify_mark_entry *entry = NULL; 467 struct fsnotify_mark_entry *entry;
420 struct inotify_inode_mark_entry *ientry; 468 struct inotify_inode_mark_entry *ientry;
421 int ret = 0;
422 int add = (arg & IN_MASK_ADD);
423 __u32 mask;
424 __u32 old_mask, new_mask; 469 __u32 old_mask, new_mask;
470 __u32 mask;
471 int add = (arg & IN_MASK_ADD);
472 int ret;
425 473
426 /* don't allow invalid bits: we don't want flags set */ 474 /* don't allow invalid bits: we don't want flags set */
427 mask = inotify_arg_to_mask(arg); 475 mask = inotify_arg_to_mask(arg);
428 if (unlikely(!mask)) 476 if (unlikely(!mask))
429 return -EINVAL; 477 return -EINVAL;
430 478
431 ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
432 if (unlikely(!ientry))
433 return -ENOMEM;
434 /* we set the mask at the end after attaching it */
435 fsnotify_init_mark(&ientry->fsn_entry, inotify_free_mark);
436 ientry->wd = 0;
437
438find_entry:
439 spin_lock(&inode->i_lock); 479 spin_lock(&inode->i_lock);
440 entry = fsnotify_find_mark_entry(group, inode); 480 entry = fsnotify_find_mark_entry(group, inode);
441 spin_unlock(&inode->i_lock); 481 spin_unlock(&inode->i_lock);
442 if (entry) { 482 if (!entry)
443 kmem_cache_free(inotify_inode_mark_cachep, ientry); 483 return -ENOENT;
444 ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
445 } else {
446 if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches) {
447 ret = -ENOSPC;
448 goto out_err;
449 }
450
451 ret = fsnotify_add_mark(&ientry->fsn_entry, group, inode);
452 if (ret == -EEXIST)
453 goto find_entry;
454 else if (ret)
455 goto out_err;
456 484
457 entry = &ientry->fsn_entry; 485 ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
458retry:
459 ret = -ENOMEM;
460 if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL)))
461 goto out_err;
462
463 spin_lock(&group->inotify_data.idr_lock);
464 /* if entry is added to the idr we keep the reference obtained
465 * through fsnotify_mark_add. remember to drop this reference
466 * when entry is removed from idr */
467 ret = idr_get_new_above(&group->inotify_data.idr, entry,
468 ++group->inotify_data.last_wd,
469 &ientry->wd);
470 spin_unlock(&group->inotify_data.idr_lock);
471 if (ret) {
472 if (ret == -EAGAIN)
473 goto retry;
474 goto out_err;
475 }
476 atomic_inc(&group->inotify_data.user->inotify_watches);
477 }
478 486
479 spin_lock(&entry->lock); 487 spin_lock(&entry->lock);
480 488
@@ -506,14 +514,104 @@ retry:
506 fsnotify_recalc_group_mask(group); 514 fsnotify_recalc_group_mask(group);
507 } 515 }
508 516
509 return ientry->wd; 517 /* return the wd */
518 ret = ientry->wd;
510 519
511out_err: 520 /* match the get from fsnotify_find_mark_entry() */
512 /* see this isn't supposed to happen, just kill the watch */ 521 fsnotify_put_mark(entry);
513 if (entry) { 522
514 fsnotify_destroy_mark_by_entry(entry); 523 return ret;
515 fsnotify_put_mark(entry); 524}
525
526static int inotify_new_watch(struct fsnotify_group *group,
527 struct inode *inode,
528 u32 arg)
529{
530 struct inotify_inode_mark_entry *tmp_ientry;
531 __u32 mask;
532 int ret;
533
534 /* don't allow invalid bits: we don't want flags set */
535 mask = inotify_arg_to_mask(arg);
536 if (unlikely(!mask))
537 return -EINVAL;
538
539 tmp_ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
540 if (unlikely(!tmp_ientry))
541 return -ENOMEM;
542
543 fsnotify_init_mark(&tmp_ientry->fsn_entry, inotify_free_mark);
544 tmp_ientry->fsn_entry.mask = mask;
545 tmp_ientry->wd = -1;
546
547 ret = -ENOSPC;
548 if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches)
549 goto out_err;
550retry:
551 ret = -ENOMEM;
552 if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL)))
553 goto out_err;
554
555 spin_lock(&group->inotify_data.idr_lock);
556 ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry,
557 group->inotify_data.last_wd,
558 &tmp_ientry->wd);
559 spin_unlock(&group->inotify_data.idr_lock);
560 if (ret) {
561 /* idr was out of memory allocate and try again */
562 if (ret == -EAGAIN)
563 goto retry;
564 goto out_err;
565 }
566
567 /* we put the mark on the idr, take a reference */
568 fsnotify_get_mark(&tmp_ientry->fsn_entry);
569
570 /* we are on the idr, now get on the inode */
571 ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode);
572 if (ret) {
573 /* we failed to get on the inode, get off the idr */
574 inotify_remove_from_idr(group, tmp_ientry);
575 goto out_err;
516 } 576 }
577
578 /* update the idr hint, who cares about races, it's just a hint */
579 group->inotify_data.last_wd = tmp_ientry->wd;
580
581 /* increment the number of watches the user has */
582 atomic_inc(&group->inotify_data.user->inotify_watches);
583
584 /* return the watch descriptor for this new entry */
585 ret = tmp_ientry->wd;
586
587 /* match the ref from fsnotify_init_markentry() */
588 fsnotify_put_mark(&tmp_ientry->fsn_entry);
589
590out_err:
591 if (ret < 0)
592 kmem_cache_free(inotify_inode_mark_cachep, tmp_ientry);
593
594 return ret;
595}
596
597static int inotify_update_watch(struct fsnotify_group *group, struct inode *inode, u32 arg)
598{
599 int ret = 0;
600
601retry:
602 /* try to update and existing watch with the new arg */
603 ret = inotify_update_existing_watch(group, inode, arg);
604 /* no mark present, try to add a new one */
605 if (ret == -ENOENT)
606 ret = inotify_new_watch(group, inode, arg);
607 /*
608 * inotify_new_watch could race with another thread which did an
609 * inotify_new_watch between the update_existing and the add watch
610 * here, go back and try to update an existing mark again.
611 */
612 if (ret == -EEXIST)
613 goto retry;
614
517 return ret; 615 return ret;
518} 616}
519 617
@@ -532,7 +630,7 @@ static struct fsnotify_group *inotify_new_group(struct user_struct *user, unsign
532 630
533 spin_lock_init(&group->inotify_data.idr_lock); 631 spin_lock_init(&group->inotify_data.idr_lock);
534 idr_init(&group->inotify_data.idr); 632 idr_init(&group->inotify_data.idr);
535 group->inotify_data.last_wd = 0; 633 group->inotify_data.last_wd = 1;
536 group->inotify_data.user = user; 634 group->inotify_data.user = user;
537 group->inotify_data.fa = NULL; 635 group->inotify_data.fa = NULL;
538 636
@@ -721,9 +819,6 @@ static int __init inotify_user_setup(void)
721 819
722 inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark_entry, SLAB_PANIC); 820 inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark_entry, SLAB_PANIC);
723 event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC); 821 event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC);
724 inotify_ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL, FSNOTIFY_EVENT_NONE, NULL, 0);
725 if (!inotify_ignored_event)
726 panic("unable to allocate the inotify ignored event\n");
727 822
728 inotify_max_queued_events = 16384; 823 inotify_max_queued_events = 16384;
729 inotify_max_user_instances = 128; 824 inotify_max_user_instances = 128;