aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/notify/dnotify/dnotify.c18
-rw-r--r--fs/notify/fanotify/fanotify.c15
-rw-r--r--fs/notify/fsnotify.c70
-rw-r--r--fs/notify/inotify/inotify_fsnotify.c12
4 files changed, 77 insertions, 38 deletions
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index e92b2c87ae94..bda588b831ad 100644
--- a/fs/notify/dnotify/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -83,7 +83,8 @@ static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark)
83 * events. 83 * events.
84 */ 84 */
85static int dnotify_handle_event(struct fsnotify_group *group, 85static int dnotify_handle_event(struct fsnotify_group *group,
86 struct fsnotify_mark *mark, 86 struct fsnotify_mark *inode_mark,
87 struct fsnotify_mark *vfsmount_mark,
87 struct fsnotify_event *event) 88 struct fsnotify_event *event)
88{ 89{
89 struct dnotify_mark *dn_mark; 90 struct dnotify_mark *dn_mark;
@@ -93,11 +94,13 @@ static int dnotify_handle_event(struct fsnotify_group *group,
93 struct fown_struct *fown; 94 struct fown_struct *fown;
94 __u32 test_mask = event->mask & ~FS_EVENT_ON_CHILD; 95 __u32 test_mask = event->mask & ~FS_EVENT_ON_CHILD;
95 96
97 BUG_ON(vfsmount_mark);
98
96 to_tell = event->to_tell; 99 to_tell = event->to_tell;
97 100
98 dn_mark = container_of(mark, struct dnotify_mark, fsn_mark); 101 dn_mark = container_of(inode_mark, struct dnotify_mark, fsn_mark);
99 102
100 spin_lock(&mark->lock); 103 spin_lock(&inode_mark->lock);
101 prev = &dn_mark->dn; 104 prev = &dn_mark->dn;
102 while ((dn = *prev) != NULL) { 105 while ((dn = *prev) != NULL) {
103 if ((dn->dn_mask & test_mask) == 0) { 106 if ((dn->dn_mask & test_mask) == 0) {
@@ -111,11 +114,11 @@ static int dnotify_handle_event(struct fsnotify_group *group,
111 else { 114 else {
112 *prev = dn->dn_next; 115 *prev = dn->dn_next;
113 kmem_cache_free(dnotify_struct_cache, dn); 116 kmem_cache_free(dnotify_struct_cache, dn);
114 dnotify_recalc_inode_mask(mark); 117 dnotify_recalc_inode_mask(inode_mark);
115 } 118 }
116 } 119 }
117 120
118 spin_unlock(&mark->lock); 121 spin_unlock(&inode_mark->lock);
119 122
120 return 0; 123 return 0;
121} 124}
@@ -126,8 +129,9 @@ static int dnotify_handle_event(struct fsnotify_group *group,
126 */ 129 */
127static bool dnotify_should_send_event(struct fsnotify_group *group, 130static bool dnotify_should_send_event(struct fsnotify_group *group,
128 struct inode *inode, struct vfsmount *mnt, 131 struct inode *inode, struct vfsmount *mnt,
129 struct fsnotify_mark *mark, __u32 mask, 132 struct fsnotify_mark *inode_mark,
130 void *data, int data_type) 133 struct fsnotify_mark *vfsmount_mark,
134 __u32 mask, void *data, int data_type)
131{ 135{
132 /* not a dir, dnotify doesn't care */ 136 /* not a dir, dnotify doesn't care */
133 if (!S_ISDIR(inode->i_mode)) 137 if (!S_ISDIR(inode->i_mode))
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index fbd7f35c6134..ef4fa4a45c94 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -115,7 +115,8 @@ static int fanotify_get_response_from_access(struct fsnotify_group *group,
115#endif 115#endif
116 116
117static int fanotify_handle_event(struct fsnotify_group *group, 117static int fanotify_handle_event(struct fsnotify_group *group,
118 struct fsnotify_mark *mark, 118 struct fsnotify_mark *inode_mark,
119 struct fsnotify_mark *fanotify_mark,
119 struct fsnotify_event *event) 120 struct fsnotify_event *event)
120{ 121{
121 int ret = 0; 122 int ret = 0;
@@ -196,8 +197,11 @@ static bool should_send_inode_event(struct fsnotify_group *group,
196 return true; 197 return true;
197} 198}
198 199
199static bool fanotify_should_send_event(struct fsnotify_group *group, struct inode *to_tell, 200static bool fanotify_should_send_event(struct fsnotify_group *group,
200 struct vfsmount *mnt, struct fsnotify_mark *mark, 201 struct inode *to_tell,
202 struct vfsmount *mnt,
203 struct fsnotify_mark *inode_mark,
204 struct fsnotify_mark *vfsmount_mark,
201 __u32 mask, void *data, int data_type) 205 __u32 mask, void *data, int data_type)
202{ 206{
203 pr_debug("%s: group=%p to_tell=%p mnt=%p mask=%x data=%p data_type=%d\n", 207 pr_debug("%s: group=%p to_tell=%p mnt=%p mask=%x data=%p data_type=%d\n",
@@ -213,9 +217,10 @@ static bool fanotify_should_send_event(struct fsnotify_group *group, struct inod
213 return false; 217 return false;
214 218
215 if (mnt) 219 if (mnt)
216 return should_send_vfsmount_event(group, mnt, to_tell, mark, mask); 220 return should_send_vfsmount_event(group, mnt, to_tell,
221 vfsmount_mark, mask);
217 else 222 else
218 return should_send_inode_event(group, to_tell, mark, mask); 223 return should_send_inode_event(group, to_tell, inode_mark, mask);
219} 224}
220 225
221const struct fsnotify_ops fanotify_fsnotify_ops = { 226const struct fsnotify_ops fanotify_fsnotify_ops = {
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index cdaa51cb698c..090b64c3b4f9 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -141,28 +141,51 @@ void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
141EXPORT_SYMBOL_GPL(__fsnotify_parent); 141EXPORT_SYMBOL_GPL(__fsnotify_parent);
142 142
143static int send_to_group(struct inode *to_tell, struct vfsmount *mnt, 143static int send_to_group(struct inode *to_tell, struct vfsmount *mnt,
144 struct fsnotify_mark *mark, 144 struct fsnotify_mark *inode_mark,
145 __u32 mask, void *data, 145 struct fsnotify_mark *vfsmount_mark,
146 __u32 mask, void *data,
146 int data_is, u32 cookie, 147 int data_is, u32 cookie,
147 const unsigned char *file_name, 148 const unsigned char *file_name,
148 struct fsnotify_event **event) 149 struct fsnotify_event **event)
149{ 150{
150 struct fsnotify_group *group = mark->group; 151 struct fsnotify_group *group = inode_mark->group;
151 __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); 152 __u32 inode_test_mask = (mask & ~FS_EVENT_ON_CHILD);
153 __u32 vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD);
152 154
153 pr_debug("%s: group=%p to_tell=%p mnt=%p mark=%p mask=%x data=%p" 155 pr_debug("%s: group=%p to_tell=%p mnt=%p mark=%p mask=%x data=%p"
154 " data_is=%d cookie=%d event=%p\n", __func__, group, to_tell, 156 " data_is=%d cookie=%d event=%p\n", __func__, group, to_tell,
155 mnt, mark, mask, data, data_is, cookie, *event); 157 mnt, inode_mark, mask, data, data_is, cookie, *event);
158
159 /* clear ignored on inode modification */
160 if (mask & FS_MODIFY) {
161 if (inode_mark &&
162 !(inode_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
163 inode_mark->ignored_mask = 0;
164 if (vfsmount_mark &&
165 !(vfsmount_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
166 vfsmount_mark->ignored_mask = 0;
167 }
156 168
157 if ((mask & FS_MODIFY) && 169 /* does the inode mark tell us to do something? */
158 !(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) 170 if (inode_mark) {
159 mark->ignored_mask = 0; 171 inode_test_mask &= inode_mark->mask;
172 inode_test_mask &= ~inode_mark->ignored_mask;
173 }
160 174
161 if (!(test_mask & mark->mask & ~mark->ignored_mask)) 175 /* does the vfsmount_mark tell us to do something? */
176 if (vfsmount_mark) {
177 vfsmount_test_mask &= vfsmount_mark->mask;
178 vfsmount_test_mask &= ~vfsmount_mark->ignored_mask;
179 if (inode_mark)
180 vfsmount_test_mask &= ~inode_mark->ignored_mask;
181 }
182
183 if (!inode_test_mask && !vfsmount_test_mask)
162 return 0; 184 return 0;
163 185
164 if (group->ops->should_send_event(group, to_tell, mnt, mark, mask, 186 if (group->ops->should_send_event(group, to_tell, mnt, inode_mark,
165 data, data_is) == false) 187 vfsmount_mark, mask, data,
188 data_is) == false)
166 return 0; 189 return 0;
167 190
168 if (!*event) { 191 if (!*event) {
@@ -172,7 +195,7 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt,
172 if (!*event) 195 if (!*event)
173 return -ENOMEM; 196 return -ENOMEM;
174 } 197 }
175 return group->ops->handle_event(group, mark, *event); 198 return group->ops->handle_event(group, inode_mark, vfsmount_mark, *event);
176} 199}
177 200
178/* 201/*
@@ -213,14 +236,16 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
213 236
214 if ((mask & FS_MODIFY) || 237 if ((mask & FS_MODIFY) ||
215 (test_mask & to_tell->i_fsnotify_mask)) 238 (test_mask & to_tell->i_fsnotify_mask))
216 inode_node = to_tell->i_fsnotify_marks.first; 239 inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first,
240 &fsnotify_mark_srcu);
217 else 241 else
218 inode_node = NULL; 242 inode_node = NULL;
219 243
220 if (mnt) { 244 if (mnt) {
221 if ((mask & FS_MODIFY) || 245 if ((mask & FS_MODIFY) ||
222 (test_mask & mnt->mnt_fsnotify_mask)) 246 (test_mask & mnt->mnt_fsnotify_mask))
223 vfsmount_node = mnt->mnt_fsnotify_marks.first; 247 vfsmount_node = srcu_dereference(mnt->mnt_fsnotify_marks.first,
248 &fsnotify_mark_srcu);
224 else 249 else
225 vfsmount_node = NULL; 250 vfsmount_node = NULL;
226 } else { 251 } else {
@@ -245,26 +270,27 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
245 270
246 if (inode_group < vfsmount_group) { 271 if (inode_group < vfsmount_group) {
247 /* handle inode */ 272 /* handle inode */
248 send_to_group(to_tell, NULL, inode_mark, mask, data, 273 send_to_group(to_tell, NULL, inode_mark, NULL, mask, data,
249 data_is, cookie, file_name, &event); 274 data_is, cookie, file_name, &event);
250 used_inode = true; 275 used_inode = true;
251 } else if (vfsmount_group < inode_group) { 276 } else if (vfsmount_group < inode_group) {
252 send_to_group(to_tell, mnt, vfsmount_mark, mask, data, 277 send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data,
253 data_is, cookie, file_name, &event); 278 data_is, cookie, file_name, &event);
254 used_vfsmount = true; 279 used_vfsmount = true;
255 } else { 280 } else {
256 send_to_group(to_tell, mnt, vfsmount_mark, mask, data, 281 send_to_group(to_tell, mnt, inode_mark, vfsmount_mark,
257 data_is, cookie, file_name, &event); 282 mask, data, data_is, cookie, file_name,
283 &event);
258 used_vfsmount = true; 284 used_vfsmount = true;
259 send_to_group(to_tell, NULL, inode_mark, mask, data,
260 data_is, cookie, file_name, &event);
261 used_inode = true; 285 used_inode = true;
262 } 286 }
263 287
264 if (used_inode) 288 if (used_inode)
265 inode_node = inode_node->next; 289 inode_node = srcu_dereference(inode_node->next,
290 &fsnotify_mark_srcu);
266 if (used_vfsmount) 291 if (used_vfsmount)
267 vfsmount_node = vfsmount_node->next; 292 vfsmount_node = srcu_dereference(vfsmount_node->next,
293 &fsnotify_mark_srcu);
268 } 294 }
269 295
270 srcu_read_unlock(&fsnotify_mark_srcu, idx); 296 srcu_read_unlock(&fsnotify_mark_srcu, idx);
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index 7cf518b25daa..e53f49731b6e 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -90,7 +90,8 @@ static struct fsnotify_event *inotify_merge(struct list_head *list,
90} 90}
91 91
92static int inotify_handle_event(struct fsnotify_group *group, 92static int inotify_handle_event(struct fsnotify_group *group,
93 struct fsnotify_mark *mark, 93 struct fsnotify_mark *inode_mark,
94 struct fsnotify_mark *vfsmount_mark,
94 struct fsnotify_event *event) 95 struct fsnotify_event *event)
95{ 96{
96 struct inotify_inode_mark *i_mark; 97 struct inotify_inode_mark *i_mark;
@@ -100,12 +101,14 @@ static int inotify_handle_event(struct fsnotify_group *group,
100 struct fsnotify_event *added_event; 101 struct fsnotify_event *added_event;
101 int wd, ret = 0; 102 int wd, ret = 0;
102 103
104 BUG_ON(vfsmount_mark);
105
103 pr_debug("%s: group=%p event=%p to_tell=%p mask=%x\n", __func__, group, 106 pr_debug("%s: group=%p event=%p to_tell=%p mask=%x\n", __func__, group,
104 event, event->to_tell, event->mask); 107 event, event->to_tell, event->mask);
105 108
106 to_tell = event->to_tell; 109 to_tell = event->to_tell;
107 110
108 i_mark = container_of(mark, struct inotify_inode_mark, 111 i_mark = container_of(inode_mark, struct inotify_inode_mark,
109 fsn_mark); 112 fsn_mark);
110 wd = i_mark->wd; 113 wd = i_mark->wd;
111 114
@@ -127,8 +130,8 @@ static int inotify_handle_event(struct fsnotify_group *group,
127 ret = PTR_ERR(added_event); 130 ret = PTR_ERR(added_event);
128 } 131 }
129 132
130 if (mark->mask & IN_ONESHOT) 133 if (inode_mark->mask & IN_ONESHOT)
131 fsnotify_destroy_mark(mark); 134 fsnotify_destroy_mark(inode_mark);
132 135
133 return ret; 136 return ret;
134} 137}
@@ -140,6 +143,7 @@ static void inotify_freeing_mark(struct fsnotify_mark *fsn_mark, struct fsnotify
140 143
141static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, 144static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode,
142 struct vfsmount *mnt, struct fsnotify_mark *mark, 145 struct vfsmount *mnt, struct fsnotify_mark *mark,
146 struct fsnotify_mark *vfsmount_mark,
143 __u32 mask, void *data, int data_type) 147 __u32 mask, void *data, int data_type)
144{ 148{
145 if ((mark->mask & FS_EXCL_UNLINK) && 149 if ((mark->mask & FS_EXCL_UNLINK) &&