diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-20 23:11:52 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-20 23:11:52 -0500 |
commit | 96680d2b9174668100824d763382240c71baa811 (patch) | |
tree | ec84c2347df47913cc98e3cfc1d43f427d51fa1f /include | |
parent | 4c9a44aebeaef35570a67aed17b72a2cf8d0b219 (diff) | |
parent | 1ca39ab9d21ac93f94b9e3eb364ea9a5cf2aba06 (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 'include')
-rw-r--r-- | include/linux/fsnotify_backend.h | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 63d966d5c2ea..d5b0910d4961 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h | |||
@@ -88,9 +88,10 @@ struct fsnotify_event_private_data; | |||
88 | * if the group is interested in this event. | 88 | * if the group is interested in this event. |
89 | * handle_event - main call for a group to handle an fs event | 89 | * handle_event - main call for a group to handle an fs event |
90 | * free_group_priv - called when a group refcnt hits 0 to clean up the private union | 90 | * free_group_priv - called when a group refcnt hits 0 to clean up the private union |
91 | * freeing-mark - this means that a mark has been flagged to die when everything | 91 | * freeing_mark - called when a mark is being destroyed for some reason. The group |
92 | * finishes using it. The function is supplied with what must be a | 92 | * MUST be holding a reference on each mark and that reference must be |
93 | * valid group and inode to use to clean up. | 93 | * dropped in this function. inotify uses this function to send |
94 | * userspace messages that marks have been removed. | ||
94 | */ | 95 | */ |
95 | struct fsnotify_ops { | 96 | struct fsnotify_ops { |
96 | bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode, | 97 | bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode, |
@@ -141,12 +142,14 @@ struct fsnotify_group { | |||
141 | unsigned int priority; | 142 | unsigned int priority; |
142 | 143 | ||
143 | /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */ | 144 | /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */ |
144 | spinlock_t mark_lock; /* protect marks_list */ | 145 | struct mutex mark_mutex; /* protect marks_list */ |
145 | atomic_t num_marks; /* 1 for each mark and 1 for not being | 146 | atomic_t num_marks; /* 1 for each mark and 1 for not being |
146 | * past the point of no return when freeing | 147 | * past the point of no return when freeing |
147 | * a group */ | 148 | * a group */ |
148 | struct list_head marks_list; /* all inode marks for this group */ | 149 | struct list_head marks_list; /* all inode marks for this group */ |
149 | 150 | ||
151 | struct fasync_struct *fsn_fa; /* async notification */ | ||
152 | |||
150 | /* groups can define private fields here or use the void *private */ | 153 | /* groups can define private fields here or use the void *private */ |
151 | union { | 154 | union { |
152 | void *private; | 155 | void *private; |
@@ -155,7 +158,6 @@ struct fsnotify_group { | |||
155 | spinlock_t idr_lock; | 158 | spinlock_t idr_lock; |
156 | struct idr idr; | 159 | struct idr idr; |
157 | u32 last_wd; | 160 | u32 last_wd; |
158 | struct fasync_struct *fa; /* async notification */ | ||
159 | struct user_struct *user; | 161 | struct user_struct *user; |
160 | } inotify_data; | 162 | } inotify_data; |
161 | #endif | 163 | #endif |
@@ -287,7 +289,6 @@ struct fsnotify_mark { | |||
287 | struct fsnotify_inode_mark i; | 289 | struct fsnotify_inode_mark i; |
288 | struct fsnotify_vfsmount_mark m; | 290 | struct fsnotify_vfsmount_mark m; |
289 | }; | 291 | }; |
290 | struct list_head free_g_list; /* tmp list used when freeing this mark */ | ||
291 | __u32 ignored_mask; /* events types to ignore */ | 292 | __u32 ignored_mask; /* events types to ignore */ |
292 | #define FSNOTIFY_MARK_FLAG_INODE 0x01 | 293 | #define FSNOTIFY_MARK_FLAG_INODE 0x01 |
293 | #define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02 | 294 | #define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02 |
@@ -360,11 +361,16 @@ static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode | |||
360 | 361 | ||
361 | /* called from fsnotify listeners, such as fanotify or dnotify */ | 362 | /* called from fsnotify listeners, such as fanotify or dnotify */ |
362 | 363 | ||
363 | /* get a reference to an existing or create a new group */ | 364 | /* create a new group */ |
364 | extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops); | 365 | extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops); |
366 | /* get reference to a group */ | ||
367 | extern void fsnotify_get_group(struct fsnotify_group *group); | ||
365 | /* drop reference on a group from fsnotify_alloc_group */ | 368 | /* drop reference on a group from fsnotify_alloc_group */ |
366 | extern void fsnotify_put_group(struct fsnotify_group *group); | 369 | extern void fsnotify_put_group(struct fsnotify_group *group); |
367 | 370 | /* destroy group */ | |
371 | extern void fsnotify_destroy_group(struct fsnotify_group *group); | ||
372 | /* fasync handler function */ | ||
373 | extern int fsnotify_fasync(int fd, struct file *file, int on); | ||
368 | /* take a reference to an event */ | 374 | /* take a reference to an event */ |
369 | extern void fsnotify_get_event(struct fsnotify_event *event); | 375 | extern void fsnotify_get_event(struct fsnotify_event *event); |
370 | extern void fsnotify_put_event(struct fsnotify_event *event); | 376 | extern void fsnotify_put_event(struct fsnotify_event *event); |
@@ -405,8 +411,13 @@ extern void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask | |||
405 | /* attach the mark to both the group and the inode */ | 411 | /* attach the mark to both the group and the inode */ |
406 | extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, | 412 | extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, |
407 | struct inode *inode, struct vfsmount *mnt, int allow_dups); | 413 | struct inode *inode, struct vfsmount *mnt, int allow_dups); |
408 | /* given a mark, flag it to be freed when all references are dropped */ | 414 | extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct fsnotify_group *group, |
409 | extern void fsnotify_destroy_mark(struct fsnotify_mark *mark); | 415 | struct inode *inode, struct vfsmount *mnt, int allow_dups); |
416 | /* given a group and a mark, flag mark to be freed when all references are dropped */ | ||
417 | extern void fsnotify_destroy_mark(struct fsnotify_mark *mark, | ||
418 | struct fsnotify_group *group); | ||
419 | extern void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, | ||
420 | struct fsnotify_group *group); | ||
410 | /* run all the marks in a group, and clear all of the vfsmount marks */ | 421 | /* run all the marks in a group, and clear all of the vfsmount marks */ |
411 | extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group); | 422 | extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group); |
412 | /* run all the marks in a group, and clear all of the inode marks */ | 423 | /* run all the marks in a group, and clear all of the inode marks */ |