aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/inotify
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/inotify
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/inotify')
-rw-r--r--fs/notify/inotify/inotify_fsnotify.c4
-rw-r--r--fs/notify/inotify/inotify_user.c34
2 files changed, 17 insertions, 21 deletions
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index e3cbd746f64a..871569c7d609 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -118,6 +118,7 @@ static int inotify_handle_event(struct fsnotify_group *group,
118 118
119 fsn_event_priv = &event_priv->fsnotify_event_priv_data; 119 fsn_event_priv = &event_priv->fsnotify_event_priv_data;
120 120
121 fsnotify_get_group(group);
121 fsn_event_priv->group = group; 122 fsn_event_priv->group = group;
122 event_priv->wd = wd; 123 event_priv->wd = wd;
123 124
@@ -131,7 +132,7 @@ static int inotify_handle_event(struct fsnotify_group *group,
131 } 132 }
132 133
133 if (inode_mark->mask & IN_ONESHOT) 134 if (inode_mark->mask & IN_ONESHOT)
134 fsnotify_destroy_mark(inode_mark); 135 fsnotify_destroy_mark(inode_mark, group);
135 136
136 return ret; 137 return ret;
137} 138}
@@ -210,6 +211,7 @@ void inotify_free_event_priv(struct fsnotify_event_private_data *fsn_event_priv)
210 event_priv = container_of(fsn_event_priv, struct inotify_event_private_data, 211 event_priv = container_of(fsn_event_priv, struct inotify_event_private_data,
211 fsnotify_event_priv_data); 212 fsnotify_event_priv_data);
212 213
214 fsnotify_put_group(fsn_event_priv->group);
213 kmem_cache_free(event_priv_cachep, event_priv); 215 kmem_cache_free(event_priv_cachep, event_priv);
214} 216}
215 217
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 36cb013c7c13..228a2c2ad8d7 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -265,7 +265,7 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
265 ret = -EAGAIN; 265 ret = -EAGAIN;
266 if (file->f_flags & O_NONBLOCK) 266 if (file->f_flags & O_NONBLOCK)
267 break; 267 break;
268 ret = -EINTR; 268 ret = -ERESTARTSYS;
269 if (signal_pending(current)) 269 if (signal_pending(current))
270 break; 270 break;
271 271
@@ -281,23 +281,17 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
281 return ret; 281 return ret;
282} 282}
283 283
284static int inotify_fasync(int fd, struct file *file, int on)
285{
286 struct fsnotify_group *group = file->private_data;
287
288 return fasync_helper(fd, file, on, &group->inotify_data.fa) >= 0 ? 0 : -EIO;
289}
290
291static int inotify_release(struct inode *ignored, struct file *file) 284static int inotify_release(struct inode *ignored, struct file *file)
292{ 285{
293 struct fsnotify_group *group = file->private_data; 286 struct fsnotify_group *group = file->private_data;
294 287
295 pr_debug("%s: group=%p\n", __func__, group); 288 pr_debug("%s: group=%p\n", __func__, group);
296 289
297 fsnotify_clear_marks_by_group(group); 290 if (file->f_flags & FASYNC)
291 fsnotify_fasync(-1, file, 0);
298 292
299 /* free this group, matching get was inotify_init->fsnotify_obtain_group */ 293 /* free this group, matching get was inotify_init->fsnotify_obtain_group */
300 fsnotify_put_group(group); 294 fsnotify_destroy_group(group);
301 295
302 return 0; 296 return 0;
303} 297}
@@ -339,7 +333,7 @@ static const struct file_operations inotify_fops = {
339 .show_fdinfo = inotify_show_fdinfo, 333 .show_fdinfo = inotify_show_fdinfo,
340 .poll = inotify_poll, 334 .poll = inotify_poll,
341 .read = inotify_read, 335 .read = inotify_read,
342 .fasync = inotify_fasync, 336 .fasync = fsnotify_fasync,
343 .release = inotify_release, 337 .release = inotify_release,
344 .unlocked_ioctl = inotify_ioctl, 338 .unlocked_ioctl = inotify_ioctl,
345 .compat_ioctl = inotify_ioctl, 339 .compat_ioctl = inotify_ioctl,
@@ -521,13 +515,13 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
521 struct fsnotify_event_private_data *fsn_event_priv; 515 struct fsnotify_event_private_data *fsn_event_priv;
522 int ret; 516 int ret;
523 517
518 i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
519
524 ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL, 520 ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL,
525 FSNOTIFY_EVENT_NONE, NULL, 0, 521 FSNOTIFY_EVENT_NONE, NULL, 0,
526 GFP_NOFS); 522 GFP_NOFS);
527 if (!ignored_event) 523 if (!ignored_event)
528 return; 524 goto skip_send_ignore;
529
530 i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
531 525
532 event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS); 526 event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS);
533 if (unlikely(!event_priv)) 527 if (unlikely(!event_priv))
@@ -535,6 +529,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
535 529
536 fsn_event_priv = &event_priv->fsnotify_event_priv_data; 530 fsn_event_priv = &event_priv->fsnotify_event_priv_data;
537 531
532 fsnotify_get_group(group);
538 fsn_event_priv->group = group; 533 fsn_event_priv->group = group;
539 event_priv->wd = i_mark->wd; 534 event_priv->wd = i_mark->wd;
540 535
@@ -548,9 +543,9 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
548 } 543 }
549 544
550skip_send_ignore: 545skip_send_ignore:
551
552 /* matches the reference taken when the event was created */ 546 /* matches the reference taken when the event was created */
553 fsnotify_put_event(ignored_event); 547 if (ignored_event)
548 fsnotify_put_event(ignored_event);
554 549
555 /* remove this mark from the idr */ 550 /* remove this mark from the idr */
556 inotify_remove_from_idr(group, i_mark); 551 inotify_remove_from_idr(group, i_mark);
@@ -709,12 +704,11 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events)
709 spin_lock_init(&group->inotify_data.idr_lock); 704 spin_lock_init(&group->inotify_data.idr_lock);
710 idr_init(&group->inotify_data.idr); 705 idr_init(&group->inotify_data.idr);
711 group->inotify_data.last_wd = 0; 706 group->inotify_data.last_wd = 0;
712 group->inotify_data.fa = NULL;
713 group->inotify_data.user = get_current_user(); 707 group->inotify_data.user = get_current_user();
714 708
715 if (atomic_inc_return(&group->inotify_data.user->inotify_devs) > 709 if (atomic_inc_return(&group->inotify_data.user->inotify_devs) >
716 inotify_max_user_instances) { 710 inotify_max_user_instances) {
717 fsnotify_put_group(group); 711 fsnotify_destroy_group(group);
718 return ERR_PTR(-EMFILE); 712 return ERR_PTR(-EMFILE);
719 } 713 }
720 714
@@ -743,7 +737,7 @@ SYSCALL_DEFINE1(inotify_init1, int, flags)
743 ret = anon_inode_getfd("inotify", &inotify_fops, group, 737 ret = anon_inode_getfd("inotify", &inotify_fops, group,
744 O_RDONLY | flags); 738 O_RDONLY | flags);
745 if (ret < 0) 739 if (ret < 0)
746 fsnotify_put_group(group); 740 fsnotify_destroy_group(group);
747 741
748 return ret; 742 return ret;
749} 743}
@@ -819,7 +813,7 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd)
819 813
820 ret = 0; 814 ret = 0;
821 815
822 fsnotify_destroy_mark(&i_mark->fsn_mark); 816 fsnotify_destroy_mark(&i_mark->fsn_mark, group);
823 817
824 /* match ref taken by inotify_idr_find */ 818 /* match ref taken by inotify_idr_find */
825 fsnotify_put_mark(&i_mark->fsn_mark); 819 fsnotify_put_mark(&i_mark->fsn_mark);