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.c245
1 files changed, 158 insertions, 87 deletions
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index dc32ed8323b..dcd2040d330 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;
@@ -157,7 +154,8 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group,
157 154
158 event = fsnotify_peek_notify_event(group); 155 event = fsnotify_peek_notify_event(group);
159 156
160 event_size += roundup(event->name_len, event_size); 157 if (event->name_len)
158 event_size += roundup(event->name_len + 1, event_size);
161 159
162 if (event_size > count) 160 if (event_size > count)
163 return ERR_PTR(-EINVAL); 161 return ERR_PTR(-EINVAL);
@@ -183,7 +181,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
183 struct fsnotify_event_private_data *fsn_priv; 181 struct fsnotify_event_private_data *fsn_priv;
184 struct inotify_event_private_data *priv; 182 struct inotify_event_private_data *priv;
185 size_t event_size = sizeof(struct inotify_event); 183 size_t event_size = sizeof(struct inotify_event);
186 size_t name_len; 184 size_t name_len = 0;
187 185
188 /* we get the inotify watch descriptor from the event private data */ 186 /* we get the inotify watch descriptor from the event private data */
189 spin_lock(&event->lock); 187 spin_lock(&event->lock);
@@ -199,8 +197,12 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
199 inotify_free_event_priv(fsn_priv); 197 inotify_free_event_priv(fsn_priv);
200 } 198 }
201 199
202 /* round up event->name_len so it is a multiple of event_size */ 200 /*
203 name_len = roundup(event->name_len, event_size); 201 * round up event->name_len so it is a multiple of event_size
202 * plus an extra byte for the terminating '\0'.
203 */
204 if (event->name_len)
205 name_len = roundup(event->name_len + 1, event_size);
204 inotify_event.len = name_len; 206 inotify_event.len = name_len;
205 207
206 inotify_event.mask = inotify_mask_to_arg(event->mask); 208 inotify_event.mask = inotify_mask_to_arg(event->mask);
@@ -224,8 +226,8 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
224 return -EFAULT; 226 return -EFAULT;
225 buf += event->name_len; 227 buf += event->name_len;
226 228
227 /* fill userspace with 0's from nul_inotify_event */ 229 /* fill userspace with 0's */
228 if (copy_to_user(buf, &nul_inotify_event, len_to_zero)) 230 if (clear_user(buf, len_to_zero))
229 return -EFAULT; 231 return -EFAULT;
230 buf += len_to_zero; 232 buf += len_to_zero;
231 event_size += name_len; 233 event_size += name_len;
@@ -326,8 +328,9 @@ static long inotify_ioctl(struct file *file, unsigned int cmd,
326 list_for_each_entry(holder, &group->notification_list, event_list) { 328 list_for_each_entry(holder, &group->notification_list, event_list) {
327 event = holder->event; 329 event = holder->event;
328 send_len += sizeof(struct inotify_event); 330 send_len += sizeof(struct inotify_event);
329 send_len += roundup(event->name_len, 331 if (event->name_len)
330 sizeof(struct inotify_event)); 332 send_len += roundup(event->name_len + 1,
333 sizeof(struct inotify_event));
331 } 334 }
332 mutex_unlock(&group->notification_mutex); 335 mutex_unlock(&group->notification_mutex);
333 ret = put_user(send_len, (int __user *) p); 336 ret = put_user(send_len, (int __user *) p);
@@ -364,20 +367,53 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
364 return error; 367 return error;
365} 368}
366 369
370/*
371 * Remove the mark from the idr (if present) and drop the reference
372 * on the mark because it was in the idr.
373 */
367static void inotify_remove_from_idr(struct fsnotify_group *group, 374static void inotify_remove_from_idr(struct fsnotify_group *group,
368 struct inotify_inode_mark_entry *ientry) 375 struct inotify_inode_mark_entry *ientry)
369{ 376{
370 struct idr *idr; 377 struct idr *idr;
378 struct fsnotify_mark_entry *entry;
379 struct inotify_inode_mark_entry *found_ientry;
380 int wd;
371 381
372 spin_lock(&group->inotify_data.idr_lock); 382 spin_lock(&group->inotify_data.idr_lock);
373 idr = &group->inotify_data.idr; 383 idr = &group->inotify_data.idr;
374 idr_remove(idr, ientry->wd); 384 wd = ientry->wd;
375 spin_unlock(&group->inotify_data.idr_lock); 385
386 if (wd == -1)
387 goto out;
388
389 entry = idr_find(&group->inotify_data.idr, wd);
390 if (unlikely(!entry))
391 goto out;
392
393 found_ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
394 if (unlikely(found_ientry != ientry)) {
395 /* We found an entry in the idr with the right wd, but it's
396 * not the entry we were told to remove. eparis seriously
397 * fucked up somewhere. */
398 WARN_ON(1);
399 ientry->wd = -1;
400 goto out;
401 }
402
403 /* One ref for being in the idr, one ref held by the caller */
404 BUG_ON(atomic_read(&entry->refcnt) < 2);
405
406 idr_remove(idr, wd);
376 ientry->wd = -1; 407 ientry->wd = -1;
408
409 /* removed from the idr, drop that ref */
410 fsnotify_put_mark(entry);
411out:
412 spin_unlock(&group->inotify_data.idr_lock);
377} 413}
414
378/* 415/*
379 * Send IN_IGNORED for this wd, remove this wd from the idr, and drop the 416 * Send IN_IGNORED for this wd, remove this wd from the idr.
380 * internal reference help on the mark because it is in the idr.
381 */ 417 */
382void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, 418void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
383 struct fsnotify_group *group) 419 struct fsnotify_group *group)
@@ -417,9 +453,6 @@ skip_send_ignore:
417 /* remove this entry from the idr */ 453 /* remove this entry from the idr */
418 inotify_remove_from_idr(group, ientry); 454 inotify_remove_from_idr(group, ientry);
419 455
420 /* removed from idr, drop that reference */
421 fsnotify_put_mark(entry);
422
423 atomic_dec(&group->inotify_data.user->inotify_watches); 456 atomic_dec(&group->inotify_data.user->inotify_watches);
424} 457}
425 458
@@ -431,80 +464,29 @@ static void inotify_free_mark(struct fsnotify_mark_entry *entry)
431 kmem_cache_free(inotify_inode_mark_cachep, ientry); 464 kmem_cache_free(inotify_inode_mark_cachep, ientry);
432} 465}
433 466
434static int inotify_update_watch(struct fsnotify_group *group, struct inode *inode, u32 arg) 467static int inotify_update_existing_watch(struct fsnotify_group *group,
468 struct inode *inode,
469 u32 arg)
435{ 470{
436 struct fsnotify_mark_entry *entry = NULL; 471 struct fsnotify_mark_entry *entry;
437 struct inotify_inode_mark_entry *ientry; 472 struct inotify_inode_mark_entry *ientry;
438 struct inotify_inode_mark_entry *tmp_ientry;
439 int ret = 0;
440 int add = (arg & IN_MASK_ADD);
441 __u32 mask;
442 __u32 old_mask, new_mask; 473 __u32 old_mask, new_mask;
474 __u32 mask;
475 int add = (arg & IN_MASK_ADD);
476 int ret;
443 477
444 /* don't allow invalid bits: we don't want flags set */ 478 /* don't allow invalid bits: we don't want flags set */
445 mask = inotify_arg_to_mask(arg); 479 mask = inotify_arg_to_mask(arg);
446 if (unlikely(!mask)) 480 if (unlikely(!mask))
447 return -EINVAL; 481 return -EINVAL;
448 482
449 tmp_ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
450 if (unlikely(!tmp_ientry))
451 return -ENOMEM;
452 /* we set the mask at the end after attaching it */
453 fsnotify_init_mark(&tmp_ientry->fsn_entry, inotify_free_mark);
454 tmp_ientry->wd = -1;
455
456find_entry:
457 spin_lock(&inode->i_lock); 483 spin_lock(&inode->i_lock);
458 entry = fsnotify_find_mark_entry(group, inode); 484 entry = fsnotify_find_mark_entry(group, inode);
459 spin_unlock(&inode->i_lock); 485 spin_unlock(&inode->i_lock);
460 if (entry) { 486 if (!entry)
461 ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); 487 return -ENOENT;
462 } else {
463 ret = -ENOSPC;
464 if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches)
465 goto out_err;
466retry:
467 ret = -ENOMEM;
468 if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL)))
469 goto out_err;
470
471 spin_lock(&group->inotify_data.idr_lock);
472 ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry,
473 group->inotify_data.last_wd,
474 &tmp_ientry->wd);
475 spin_unlock(&group->inotify_data.idr_lock);
476 if (ret) {
477 if (ret == -EAGAIN)
478 goto retry;
479 goto out_err;
480 }
481
482 ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode);
483 if (ret) {
484 inotify_remove_from_idr(group, tmp_ientry);
485 if (ret == -EEXIST)
486 goto find_entry;
487 goto out_err;
488 }
489
490 /* tmp_ientry has been added to the inode, so we are all set up.
491 * now we just need to make sure tmp_ientry doesn't get freed and
492 * we need to set up entry and ientry so the generic code can
493 * do its thing. */
494 ientry = tmp_ientry;
495 entry = &ientry->fsn_entry;
496 tmp_ientry = NULL;
497
498 atomic_inc(&group->inotify_data.user->inotify_watches);
499
500 /* update the idr hint */
501 group->inotify_data.last_wd = ientry->wd;
502
503 /* we put the mark on the idr, take a reference */
504 fsnotify_get_mark(entry);
505 }
506 488
507 ret = ientry->wd; 489 ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
508 490
509 spin_lock(&entry->lock); 491 spin_lock(&entry->lock);
510 492
@@ -536,18 +518,107 @@ retry:
536 fsnotify_recalc_group_mask(group); 518 fsnotify_recalc_group_mask(group);
537 } 519 }
538 520
539 /* this either matches fsnotify_find_mark_entry, or init_mark_entry 521 /* return the wd */
540 * depending on which path we took... */ 522 ret = ientry->wd;
523
524 /* match the get from fsnotify_find_mark_entry() */
541 fsnotify_put_mark(entry); 525 fsnotify_put_mark(entry);
542 526
527 return ret;
528}
529
530static int inotify_new_watch(struct fsnotify_group *group,
531 struct inode *inode,
532 u32 arg)
533{
534 struct inotify_inode_mark_entry *tmp_ientry;
535 __u32 mask;
536 int ret;
537
538 /* don't allow invalid bits: we don't want flags set */
539 mask = inotify_arg_to_mask(arg);
540 if (unlikely(!mask))
541 return -EINVAL;
542
543 tmp_ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
544 if (unlikely(!tmp_ientry))
545 return -ENOMEM;
546
547 fsnotify_init_mark(&tmp_ientry->fsn_entry, inotify_free_mark);
548 tmp_ientry->fsn_entry.mask = mask;
549 tmp_ientry->wd = -1;
550
551 ret = -ENOSPC;
552 if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches)
553 goto out_err;
554retry:
555 ret = -ENOMEM;
556 if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL)))
557 goto out_err;
558
559 spin_lock(&group->inotify_data.idr_lock);
560 ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry,
561 group->inotify_data.last_wd,
562 &tmp_ientry->wd);
563 spin_unlock(&group->inotify_data.idr_lock);
564 if (ret) {
565 /* idr was out of memory allocate and try again */
566 if (ret == -EAGAIN)
567 goto retry;
568 goto out_err;
569 }
570
571 /* we put the mark on the idr, take a reference */
572 fsnotify_get_mark(&tmp_ientry->fsn_entry);
573
574 /* we are on the idr, now get on the inode */
575 ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode);
576 if (ret) {
577 /* we failed to get on the inode, get off the idr */
578 inotify_remove_from_idr(group, tmp_ientry);
579 goto out_err;
580 }
581
582 /* update the idr hint, who cares about races, it's just a hint */
583 group->inotify_data.last_wd = tmp_ientry->wd;
584
585 /* increment the number of watches the user has */
586 atomic_inc(&group->inotify_data.user->inotify_watches);
587
588 /* return the watch descriptor for this new entry */
589 ret = tmp_ientry->wd;
590
591 /* match the ref from fsnotify_init_markentry() */
592 fsnotify_put_mark(&tmp_ientry->fsn_entry);
593
594 /* if this mark added a new event update the group mask */
595 if (mask & ~group->mask)
596 fsnotify_recalc_group_mask(group);
597
543out_err: 598out_err:
544 /* could be an error, could be that we found an existing mark */ 599 if (ret < 0)
545 if (tmp_ientry) {
546 /* on the idr but didn't make it on the inode */
547 if (tmp_ientry->wd != -1)
548 inotify_remove_from_idr(group, tmp_ientry);
549 kmem_cache_free(inotify_inode_mark_cachep, tmp_ientry); 600 kmem_cache_free(inotify_inode_mark_cachep, tmp_ientry);
550 } 601
602 return ret;
603}
604
605static int inotify_update_watch(struct fsnotify_group *group, struct inode *inode, u32 arg)
606{
607 int ret = 0;
608
609retry:
610 /* try to update and existing watch with the new arg */
611 ret = inotify_update_existing_watch(group, inode, arg);
612 /* no mark present, try to add a new one */
613 if (ret == -ENOENT)
614 ret = inotify_new_watch(group, inode, arg);
615 /*
616 * inotify_new_watch could race with another thread which did an
617 * inotify_new_watch between the update_existing and the add watch
618 * here, go back and try to update an existing mark again.
619 */
620 if (ret == -EEXIST)
621 goto retry;
551 622
552 return ret; 623 return ret;
553} 624}