diff options
-rw-r--r-- | fs/notify/fdinfo.c | 5 | ||||
-rw-r--r-- | fs/notify/fsnotify.c | 8 | ||||
-rw-r--r-- | fs/notify/fsnotify.h | 11 | ||||
-rw-r--r-- | fs/notify/mark.c | 4 | ||||
-rw-r--r-- | fs/super.c | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 5 | ||||
-rw-r--r-- | include/linux/fsnotify_backend.h | 17 |
7 files changed, 47 insertions, 5 deletions
diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c index 86fcf5814279..25385e336ac7 100644 --- a/fs/notify/fdinfo.c +++ b/fs/notify/fdinfo.c | |||
@@ -131,6 +131,11 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) | |||
131 | 131 | ||
132 | seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n", | 132 | seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n", |
133 | mnt->mnt_id, mflags, mark->mask, mark->ignored_mask); | 133 | mnt->mnt_id, mflags, mark->mask, mark->ignored_mask); |
134 | } else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_SB) { | ||
135 | struct super_block *sb = fsnotify_conn_sb(mark->connector); | ||
136 | |||
137 | seq_printf(m, "fanotify sdev:%x mflags:%x mask:%x ignored_mask:%x\n", | ||
138 | sb->s_dev, mflags, mark->mask, mark->ignored_mask); | ||
134 | } | 139 | } |
135 | } | 140 | } |
136 | 141 | ||
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index ababdbfab537..2971803d151c 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c | |||
@@ -48,7 +48,7 @@ void __fsnotify_vfsmount_delete(struct vfsmount *mnt) | |||
48 | * Called during unmount with no locks held, so needs to be safe against | 48 | * Called during unmount with no locks held, so needs to be safe against |
49 | * concurrent modifiers. We temporarily drop sb->s_inode_list_lock and CAN block. | 49 | * concurrent modifiers. We temporarily drop sb->s_inode_list_lock and CAN block. |
50 | */ | 50 | */ |
51 | void fsnotify_unmount_inodes(struct super_block *sb) | 51 | static void fsnotify_unmount_inodes(struct super_block *sb) |
52 | { | 52 | { |
53 | struct inode *inode, *iput_inode = NULL; | 53 | struct inode *inode, *iput_inode = NULL; |
54 | 54 | ||
@@ -98,6 +98,12 @@ void fsnotify_unmount_inodes(struct super_block *sb) | |||
98 | iput(iput_inode); | 98 | iput(iput_inode); |
99 | } | 99 | } |
100 | 100 | ||
101 | void fsnotify_sb_delete(struct super_block *sb) | ||
102 | { | ||
103 | fsnotify_unmount_inodes(sb); | ||
104 | fsnotify_clear_marks_by_sb(sb); | ||
105 | } | ||
106 | |||
101 | /* | 107 | /* |
102 | * Given an inode, first check if we care what happens to our children. Inotify | 108 | * Given an inode, first check if we care what happens to our children. Inotify |
103 | * and dnotify both tell their parents about events. If we care about any event | 109 | * and dnotify both tell their parents about events. If we care about any event |
diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h index 7902653dd577..5a00121fb219 100644 --- a/fs/notify/fsnotify.h +++ b/fs/notify/fsnotify.h | |||
@@ -21,6 +21,12 @@ static inline struct mount *fsnotify_conn_mount( | |||
21 | return container_of(conn->obj, struct mount, mnt_fsnotify_marks); | 21 | return container_of(conn->obj, struct mount, mnt_fsnotify_marks); |
22 | } | 22 | } |
23 | 23 | ||
24 | static inline struct super_block *fsnotify_conn_sb( | ||
25 | struct fsnotify_mark_connector *conn) | ||
26 | { | ||
27 | return container_of(conn->obj, struct super_block, s_fsnotify_marks); | ||
28 | } | ||
29 | |||
24 | /* destroy all events sitting in this groups notification queue */ | 30 | /* destroy all events sitting in this groups notification queue */ |
25 | extern void fsnotify_flush_notify(struct fsnotify_group *group); | 31 | extern void fsnotify_flush_notify(struct fsnotify_group *group); |
26 | 32 | ||
@@ -43,6 +49,11 @@ static inline void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) | |||
43 | { | 49 | { |
44 | fsnotify_destroy_marks(&real_mount(mnt)->mnt_fsnotify_marks); | 50 | fsnotify_destroy_marks(&real_mount(mnt)->mnt_fsnotify_marks); |
45 | } | 51 | } |
52 | /* run the list of all marks associated with sb and destroy them */ | ||
53 | static inline void fsnotify_clear_marks_by_sb(struct super_block *sb) | ||
54 | { | ||
55 | fsnotify_destroy_marks(&sb->s_fsnotify_marks); | ||
56 | } | ||
46 | /* Wait until all marks queued for destruction are destroyed */ | 57 | /* Wait until all marks queued for destruction are destroyed */ |
47 | extern void fsnotify_wait_marks_destroyed(void); | 58 | extern void fsnotify_wait_marks_destroyed(void); |
48 | 59 | ||
diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 59cdb27826de..b5172ccb2e60 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c | |||
@@ -115,6 +115,8 @@ static __u32 *fsnotify_conn_mask_p(struct fsnotify_mark_connector *conn) | |||
115 | return &fsnotify_conn_inode(conn)->i_fsnotify_mask; | 115 | return &fsnotify_conn_inode(conn)->i_fsnotify_mask; |
116 | else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) | 116 | else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) |
117 | return &fsnotify_conn_mount(conn)->mnt_fsnotify_mask; | 117 | return &fsnotify_conn_mount(conn)->mnt_fsnotify_mask; |
118 | else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) | ||
119 | return &fsnotify_conn_sb(conn)->s_fsnotify_mask; | ||
118 | return NULL; | 120 | return NULL; |
119 | } | 121 | } |
120 | 122 | ||
@@ -192,6 +194,8 @@ static struct inode *fsnotify_detach_connector_from_object( | |||
192 | inode->i_fsnotify_mask = 0; | 194 | inode->i_fsnotify_mask = 0; |
193 | } else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) { | 195 | } else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) { |
194 | fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0; | 196 | fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0; |
197 | } else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) { | ||
198 | fsnotify_conn_sb(conn)->s_fsnotify_mask = 0; | ||
195 | } | 199 | } |
196 | 200 | ||
197 | rcu_assign_pointer(*(conn->obj), NULL); | 201 | rcu_assign_pointer(*(conn->obj), NULL); |
diff --git a/fs/super.c b/fs/super.c index f3a8c008e164..ca53a08497ed 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -442,7 +442,7 @@ void generic_shutdown_super(struct super_block *sb) | |||
442 | sync_filesystem(sb); | 442 | sync_filesystem(sb); |
443 | sb->s_flags &= ~SB_ACTIVE; | 443 | sb->s_flags &= ~SB_ACTIVE; |
444 | 444 | ||
445 | fsnotify_unmount_inodes(sb); | 445 | fsnotify_sb_delete(sb); |
446 | cgroup_writeback_umount(); | 446 | cgroup_writeback_umount(); |
447 | 447 | ||
448 | evict_inodes(sb); | 448 | evict_inodes(sb); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 33322702c910..2c14801d0aa3 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1464,6 +1464,11 @@ struct super_block { | |||
1464 | 1464 | ||
1465 | spinlock_t s_inode_wblist_lock; | 1465 | spinlock_t s_inode_wblist_lock; |
1466 | struct list_head s_inodes_wb; /* writeback inodes */ | 1466 | struct list_head s_inodes_wb; /* writeback inodes */ |
1467 | |||
1468 | #ifdef CONFIG_FSNOTIFY | ||
1469 | __u32 s_fsnotify_mask; | ||
1470 | struct fsnotify_mark_connector __rcu *s_fsnotify_marks; | ||
1471 | #endif | ||
1467 | } __randomize_layout; | 1472 | } __randomize_layout; |
1468 | 1473 | ||
1469 | /* Helper functions so that in most cases filesystems will | 1474 | /* Helper functions so that in most cases filesystems will |
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index b8f4182f42f1..81b88fc9df31 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h | |||
@@ -206,12 +206,14 @@ struct fsnotify_group { | |||
206 | enum fsnotify_obj_type { | 206 | enum fsnotify_obj_type { |
207 | FSNOTIFY_OBJ_TYPE_INODE, | 207 | FSNOTIFY_OBJ_TYPE_INODE, |
208 | FSNOTIFY_OBJ_TYPE_VFSMOUNT, | 208 | FSNOTIFY_OBJ_TYPE_VFSMOUNT, |
209 | FSNOTIFY_OBJ_TYPE_SB, | ||
209 | FSNOTIFY_OBJ_TYPE_COUNT, | 210 | FSNOTIFY_OBJ_TYPE_COUNT, |
210 | FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT | 211 | FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT |
211 | }; | 212 | }; |
212 | 213 | ||
213 | #define FSNOTIFY_OBJ_TYPE_INODE_FL (1U << FSNOTIFY_OBJ_TYPE_INODE) | 214 | #define FSNOTIFY_OBJ_TYPE_INODE_FL (1U << FSNOTIFY_OBJ_TYPE_INODE) |
214 | #define FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL (1U << FSNOTIFY_OBJ_TYPE_VFSMOUNT) | 215 | #define FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL (1U << FSNOTIFY_OBJ_TYPE_VFSMOUNT) |
216 | #define FSNOTIFY_OBJ_TYPE_SB_FL (1U << FSNOTIFY_OBJ_TYPE_SB) | ||
215 | #define FSNOTIFY_OBJ_ALL_TYPES_MASK ((1U << FSNOTIFY_OBJ_TYPE_COUNT) - 1) | 217 | #define FSNOTIFY_OBJ_ALL_TYPES_MASK ((1U << FSNOTIFY_OBJ_TYPE_COUNT) - 1) |
216 | 218 | ||
217 | static inline bool fsnotify_valid_obj_type(unsigned int type) | 219 | static inline bool fsnotify_valid_obj_type(unsigned int type) |
@@ -255,6 +257,7 @@ static inline struct fsnotify_mark *fsnotify_iter_##name##_mark( \ | |||
255 | 257 | ||
256 | FSNOTIFY_ITER_FUNCS(inode, INODE) | 258 | FSNOTIFY_ITER_FUNCS(inode, INODE) |
257 | FSNOTIFY_ITER_FUNCS(vfsmount, VFSMOUNT) | 259 | FSNOTIFY_ITER_FUNCS(vfsmount, VFSMOUNT) |
260 | FSNOTIFY_ITER_FUNCS(sb, SB) | ||
258 | 261 | ||
259 | #define fsnotify_foreach_obj_type(type) \ | 262 | #define fsnotify_foreach_obj_type(type) \ |
260 | for (type = 0; type < FSNOTIFY_OBJ_TYPE_COUNT; type++) | 263 | for (type = 0; type < FSNOTIFY_OBJ_TYPE_COUNT; type++) |
@@ -267,8 +270,8 @@ struct fsnotify_mark_connector; | |||
267 | typedef struct fsnotify_mark_connector __rcu *fsnotify_connp_t; | 270 | typedef struct fsnotify_mark_connector __rcu *fsnotify_connp_t; |
268 | 271 | ||
269 | /* | 272 | /* |
270 | * Inode / vfsmount point to this structure which tracks all marks attached to | 273 | * Inode/vfsmount/sb point to this structure which tracks all marks attached to |
271 | * the inode / vfsmount. The reference to inode / vfsmount is held by this | 274 | * the inode/vfsmount/sb. The reference to inode/vfsmount/sb is held by this |
272 | * structure. We destroy this structure when there are no more marks attached | 275 | * structure. We destroy this structure when there are no more marks attached |
273 | * to it. The structure is protected by fsnotify_mark_srcu. | 276 | * to it. The structure is protected by fsnotify_mark_srcu. |
274 | */ | 277 | */ |
@@ -335,6 +338,7 @@ extern int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int dat | |||
335 | extern int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask); | 338 | extern int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask); |
336 | extern void __fsnotify_inode_delete(struct inode *inode); | 339 | extern void __fsnotify_inode_delete(struct inode *inode); |
337 | extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); | 340 | extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); |
341 | extern void fsnotify_sb_delete(struct super_block *sb); | ||
338 | extern u32 fsnotify_get_cookie(void); | 342 | extern u32 fsnotify_get_cookie(void); |
339 | 343 | ||
340 | static inline int fsnotify_inode_watches_children(struct inode *inode) | 344 | static inline int fsnotify_inode_watches_children(struct inode *inode) |
@@ -455,9 +459,13 @@ static inline void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *gr | |||
455 | { | 459 | { |
456 | fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_INODE_FL); | 460 | fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_INODE_FL); |
457 | } | 461 | } |
462 | /* run all the marks in a group, and clear all of the sn marks */ | ||
463 | static inline void fsnotify_clear_sb_marks_by_group(struct fsnotify_group *group) | ||
464 | { | ||
465 | fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_SB_FL); | ||
466 | } | ||
458 | extern void fsnotify_get_mark(struct fsnotify_mark *mark); | 467 | extern void fsnotify_get_mark(struct fsnotify_mark *mark); |
459 | extern void fsnotify_put_mark(struct fsnotify_mark *mark); | 468 | extern void fsnotify_put_mark(struct fsnotify_mark *mark); |
460 | extern void fsnotify_unmount_inodes(struct super_block *sb); | ||
461 | extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info); | 469 | extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info); |
462 | extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info); | 470 | extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info); |
463 | 471 | ||
@@ -484,6 +492,9 @@ static inline void __fsnotify_inode_delete(struct inode *inode) | |||
484 | static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt) | 492 | static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt) |
485 | {} | 493 | {} |
486 | 494 | ||
495 | static inline void fsnotify_sb_delete(struct super_block *sb) | ||
496 | {} | ||
497 | |||
487 | static inline void fsnotify_update_flags(struct dentry *dentry) | 498 | static inline void fsnotify_update_flags(struct dentry *dentry) |
488 | {} | 499 | {} |
489 | 500 | ||