aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/fanotify
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-12-20 23:11:52 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-20 23:11:52 -0500
commit96680d2b9174668100824d763382240c71baa811 (patch)
treeec84c2347df47913cc98e3cfc1d43f427d51fa1f /fs/notify/fanotify
parent4c9a44aebeaef35570a67aed17b72a2cf8d0b219 (diff)
parent1ca39ab9d21ac93f94b9e3eb364ea9a5cf2aba06 (diff)
Merge branch 'for-next' of git://git.infradead.org/users/eparis/notify
Pull filesystem notification updates from Eric Paris: "This pull mostly is about locking changes in the fsnotify system. By switching the group lock from a spin_lock() to a mutex() we can now hold the lock across things like iput(). This fixes a problem involving unmounting a fs and having inodes be busy, first pointed out by FAT, but reproducible with tmpfs. This also restores signal driven I/O for inotify, which has been broken since about 2.6.32." Ugh. I *hate* the timing of this. It was rebased after the merge window opened, and then left to sit with the pull request coming the day before the merge window closes. That's just crap. But apparently the patches themselves have been around for over a year, just gathering dust, so now it's suddenly critical. Fixed up semantic conflict in fs/notify/fdinfo.c as per Stephen Rothwell's fixes from -next. * 'for-next' of git://git.infradead.org/users/eparis/notify: inotify: automatically restart syscalls inotify: dont skip removal of watch descriptor if creation of ignored event failed fanotify: dont merge permission events fsnotify: make fasync generic for both inotify and fanotify fsnotify: change locking order fsnotify: dont put marks on temporary list when clearing marks by group fsnotify: introduce locked versions of fsnotify_add_mark() and fsnotify_remove_mark() fsnotify: pass group to fsnotify_destroy_mark() fsnotify: use a mutex instead of a spinlock to protect a groups mark list fanotify: add an extra flag to mark_remove_from_mask that indicates wheather a mark should be destroyed fsnotify: take groups mark_lock before mark lock fsnotify: use reference counting for groups fsnotify: introduce fsnotify_get_group() inotify, fanotify: replace fsnotify_put_group() with fsnotify_destroy_group()
Diffstat (limited to 'fs/notify/fanotify')
-rw-r--r--fs/notify/fanotify/fanotify.c6
-rw-r--r--fs/notify/fanotify/fanotify_user.c37
2 files changed, 31 insertions, 12 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index a50636025364..0c2f9122b262 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -18,6 +18,12 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new)
18 old->tgid == new->tgid) { 18 old->tgid == new->tgid) {
19 switch (old->data_type) { 19 switch (old->data_type) {
20 case (FSNOTIFY_EVENT_PATH): 20 case (FSNOTIFY_EVENT_PATH):
21#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
22 /* dont merge two permission events */
23 if ((old->mask & FAN_ALL_PERM_EVENTS) &&
24 (new->mask & FAN_ALL_PERM_EVENTS))
25 return false;
26#endif
21 if ((old->path.mnt == new->path.mnt) && 27 if ((old->path.mnt == new->path.mnt) &&
22 (old->path.dentry == new->path.dentry)) 28 (old->path.dentry == new->path.dentry))
23 return true; 29 return true;
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index a5cd9bba022f..9ff4a5ee6e20 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -397,8 +397,12 @@ static int fanotify_release(struct inode *ignored, struct file *file)
397 397
398 wake_up(&group->fanotify_data.access_waitq); 398 wake_up(&group->fanotify_data.access_waitq);
399#endif 399#endif
400
401 if (file->f_flags & FASYNC)
402 fsnotify_fasync(-1, file, 0);
403
400 /* matches the fanotify_init->fsnotify_alloc_group */ 404 /* matches the fanotify_init->fsnotify_alloc_group */
401 fsnotify_put_group(group); 405 fsnotify_destroy_group(group);
402 406
403 return 0; 407 return 0;
404} 408}
@@ -493,7 +497,8 @@ out:
493 497
494static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, 498static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
495 __u32 mask, 499 __u32 mask,
496 unsigned int flags) 500 unsigned int flags,
501 int *destroy)
497{ 502{
498 __u32 oldmask; 503 __u32 oldmask;
499 504
@@ -507,8 +512,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
507 } 512 }
508 spin_unlock(&fsn_mark->lock); 513 spin_unlock(&fsn_mark->lock);
509 514
510 if (!(oldmask & ~mask)) 515 *destroy = !(oldmask & ~mask);
511 fsnotify_destroy_mark(fsn_mark);
512 516
513 return mask & oldmask; 517 return mask & oldmask;
514} 518}
@@ -519,12 +523,17 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,
519{ 523{
520 struct fsnotify_mark *fsn_mark = NULL; 524 struct fsnotify_mark *fsn_mark = NULL;
521 __u32 removed; 525 __u32 removed;
526 int destroy_mark;
522 527
523 fsn_mark = fsnotify_find_vfsmount_mark(group, mnt); 528 fsn_mark = fsnotify_find_vfsmount_mark(group, mnt);
524 if (!fsn_mark) 529 if (!fsn_mark)
525 return -ENOENT; 530 return -ENOENT;
526 531
527 removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags); 532 removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags,
533 &destroy_mark);
534 if (destroy_mark)
535 fsnotify_destroy_mark(fsn_mark, group);
536
528 fsnotify_put_mark(fsn_mark); 537 fsnotify_put_mark(fsn_mark);
529 if (removed & real_mount(mnt)->mnt_fsnotify_mask) 538 if (removed & real_mount(mnt)->mnt_fsnotify_mask)
530 fsnotify_recalc_vfsmount_mask(mnt); 539 fsnotify_recalc_vfsmount_mask(mnt);
@@ -538,12 +547,16 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group,
538{ 547{
539 struct fsnotify_mark *fsn_mark = NULL; 548 struct fsnotify_mark *fsn_mark = NULL;
540 __u32 removed; 549 __u32 removed;
550 int destroy_mark;
541 551
542 fsn_mark = fsnotify_find_inode_mark(group, inode); 552 fsn_mark = fsnotify_find_inode_mark(group, inode);
543 if (!fsn_mark) 553 if (!fsn_mark)
544 return -ENOENT; 554 return -ENOENT;
545 555
546 removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags); 556 removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags,
557 &destroy_mark);
558 if (destroy_mark)
559 fsnotify_destroy_mark(fsn_mark, group);
547 /* matches the fsnotify_find_inode_mark() */ 560 /* matches the fsnotify_find_inode_mark() */
548 fsnotify_put_mark(fsn_mark); 561 fsnotify_put_mark(fsn_mark);
549 if (removed & inode->i_fsnotify_mask) 562 if (removed & inode->i_fsnotify_mask)
@@ -710,13 +723,13 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
710 break; 723 break;
711 default: 724 default:
712 fd = -EINVAL; 725 fd = -EINVAL;
713 goto out_put_group; 726 goto out_destroy_group;
714 } 727 }
715 728
716 if (flags & FAN_UNLIMITED_QUEUE) { 729 if (flags & FAN_UNLIMITED_QUEUE) {
717 fd = -EPERM; 730 fd = -EPERM;
718 if (!capable(CAP_SYS_ADMIN)) 731 if (!capable(CAP_SYS_ADMIN))
719 goto out_put_group; 732 goto out_destroy_group;
720 group->max_events = UINT_MAX; 733 group->max_events = UINT_MAX;
721 } else { 734 } else {
722 group->max_events = FANOTIFY_DEFAULT_MAX_EVENTS; 735 group->max_events = FANOTIFY_DEFAULT_MAX_EVENTS;
@@ -725,7 +738,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
725 if (flags & FAN_UNLIMITED_MARKS) { 738 if (flags & FAN_UNLIMITED_MARKS) {
726 fd = -EPERM; 739 fd = -EPERM;
727 if (!capable(CAP_SYS_ADMIN)) 740 if (!capable(CAP_SYS_ADMIN))
728 goto out_put_group; 741 goto out_destroy_group;
729 group->fanotify_data.max_marks = UINT_MAX; 742 group->fanotify_data.max_marks = UINT_MAX;
730 } else { 743 } else {
731 group->fanotify_data.max_marks = FANOTIFY_DEFAULT_MAX_MARKS; 744 group->fanotify_data.max_marks = FANOTIFY_DEFAULT_MAX_MARKS;
@@ -733,12 +746,12 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
733 746
734 fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags); 747 fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags);
735 if (fd < 0) 748 if (fd < 0)
736 goto out_put_group; 749 goto out_destroy_group;
737 750
738 return fd; 751 return fd;
739 752
740out_put_group: 753out_destroy_group:
741 fsnotify_put_group(group); 754 fsnotify_destroy_group(group);
742 return fd; 755 return fd;
743} 756}
744 757