aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/fsnotify.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/notify/fsnotify.c')
-rw-r--r--fs/notify/fsnotify.c68
1 files changed, 36 insertions, 32 deletions
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 3970392b2722..36802420d69a 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -148,13 +148,14 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt,
148 const unsigned char *file_name, 148 const unsigned char *file_name,
149 struct fsnotify_event **event) 149 struct fsnotify_event **event)
150{ 150{
151 struct fsnotify_group *group = inode_mark->group; 151 struct fsnotify_group *group = NULL;
152 __u32 inode_test_mask = (mask & ~FS_EVENT_ON_CHILD); 152 __u32 inode_test_mask = 0;
153 __u32 vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD); 153 __u32 vfsmount_test_mask = 0;
154 154
155 pr_debug("%s: group=%p to_tell=%p mnt=%p mark=%p mask=%x data=%p" 155 if (unlikely(!inode_mark && !vfsmount_mark)) {
156 " data_is=%d cookie=%d event=%p\n", __func__, group, to_tell, 156 BUG();
157 mnt, inode_mark, mask, data, data_is, cookie, *event); 157 return 0;
158 }
158 159
159 /* clear ignored on inode modification */ 160 /* clear ignored on inode modification */
160 if (mask & FS_MODIFY) { 161 if (mask & FS_MODIFY) {
@@ -168,18 +169,29 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt,
168 169
169 /* does the inode mark tell us to do something? */ 170 /* does the inode mark tell us to do something? */
170 if (inode_mark) { 171 if (inode_mark) {
172 group = inode_mark->group;
173 inode_test_mask = (mask & ~FS_EVENT_ON_CHILD);
171 inode_test_mask &= inode_mark->mask; 174 inode_test_mask &= inode_mark->mask;
172 inode_test_mask &= ~inode_mark->ignored_mask; 175 inode_test_mask &= ~inode_mark->ignored_mask;
173 } 176 }
174 177
175 /* does the vfsmount_mark tell us to do something? */ 178 /* does the vfsmount_mark tell us to do something? */
176 if (vfsmount_mark) { 179 if (vfsmount_mark) {
180 vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD);
181 group = vfsmount_mark->group;
177 vfsmount_test_mask &= vfsmount_mark->mask; 182 vfsmount_test_mask &= vfsmount_mark->mask;
178 vfsmount_test_mask &= ~vfsmount_mark->ignored_mask; 183 vfsmount_test_mask &= ~vfsmount_mark->ignored_mask;
179 if (inode_mark) 184 if (inode_mark)
180 vfsmount_test_mask &= ~inode_mark->ignored_mask; 185 vfsmount_test_mask &= ~inode_mark->ignored_mask;
181 } 186 }
182 187
188 pr_debug("%s: group=%p to_tell=%p mnt=%p mask=%x inode_mark=%p"
189 " inode_test_mask=%x vfsmount_mark=%p vfsmount_test_mask=%x"
190 " data=%p data_is=%d cookie=%d event=%p\n",
191 __func__, group, to_tell, mnt, mask, inode_mark,
192 inode_test_mask, vfsmount_mark, vfsmount_test_mask, data,
193 data_is, cookie, *event);
194
183 if (!inode_test_mask && !vfsmount_test_mask) 195 if (!inode_test_mask && !vfsmount_test_mask)
184 return 0; 196 return 0;
185 197
@@ -207,13 +219,12 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt,
207int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, 219int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
208 const unsigned char *file_name, u32 cookie) 220 const unsigned char *file_name, u32 cookie)
209{ 221{
210 struct hlist_node *inode_node, *vfsmount_node; 222 struct hlist_node *inode_node = NULL, *vfsmount_node = NULL;
211 struct fsnotify_mark *inode_mark = NULL, *vfsmount_mark = NULL; 223 struct fsnotify_mark *inode_mark = NULL, *vfsmount_mark = NULL;
212 struct fsnotify_group *inode_group, *vfsmount_group; 224 struct fsnotify_group *inode_group, *vfsmount_group;
213 struct fsnotify_event *event = NULL; 225 struct fsnotify_event *event = NULL;
214 struct vfsmount *mnt; 226 struct vfsmount *mnt;
215 int idx, ret = 0; 227 int idx, ret = 0;
216 bool used_inode = false, used_vfsmount = false;
217 /* global tests shouldn't care about events on child only the specific event */ 228 /* global tests shouldn't care about events on child only the specific event */
218 __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); 229 __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD);
219 230
@@ -238,57 +249,50 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
238 (test_mask & to_tell->i_fsnotify_mask)) 249 (test_mask & to_tell->i_fsnotify_mask))
239 inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first, 250 inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first,
240 &fsnotify_mark_srcu); 251 &fsnotify_mark_srcu);
241 else
242 inode_node = NULL;
243 252
244 if (mnt) { 253 if (mnt && ((mask & FS_MODIFY) ||
245 if ((mask & FS_MODIFY) || 254 (test_mask & mnt->mnt_fsnotify_mask))) {
246 (test_mask & mnt->mnt_fsnotify_mask)) 255 vfsmount_node = srcu_dereference(mnt->mnt_fsnotify_marks.first,
247 vfsmount_node = srcu_dereference(mnt->mnt_fsnotify_marks.first, 256 &fsnotify_mark_srcu);
248 &fsnotify_mark_srcu); 257 inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first,
249 else 258 &fsnotify_mark_srcu);
250 vfsmount_node = NULL;
251 } else {
252 mnt = NULL;
253 vfsmount_node = NULL;
254 } 259 }
255 260
256 while (inode_node || vfsmount_node) { 261 while (inode_node || vfsmount_node) {
262 inode_group = vfsmount_group = NULL;
263
257 if (inode_node) { 264 if (inode_node) {
258 inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu), 265 inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu),
259 struct fsnotify_mark, i.i_list); 266 struct fsnotify_mark, i.i_list);
260 inode_group = inode_mark->group; 267 inode_group = inode_mark->group;
261 } else 268 }
262 inode_group = (void *)-1;
263 269
264 if (vfsmount_node) { 270 if (vfsmount_node) {
265 vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu), 271 vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu),
266 struct fsnotify_mark, m.m_list); 272 struct fsnotify_mark, m.m_list);
267 vfsmount_group = vfsmount_mark->group; 273 vfsmount_group = vfsmount_mark->group;
268 } else 274 }
269 vfsmount_group = (void *)-1;
270 275
271 if (inode_group < vfsmount_group) { 276 if (inode_group > vfsmount_group) {
272 /* handle inode */ 277 /* handle inode */
273 send_to_group(to_tell, NULL, inode_mark, NULL, mask, data, 278 send_to_group(to_tell, NULL, inode_mark, NULL, mask, data,
274 data_is, cookie, file_name, &event); 279 data_is, cookie, file_name, &event);
275 used_inode = true; 280 /* we didn't use the vfsmount_mark */
276 } else if (vfsmount_group < inode_group) { 281 vfsmount_group = NULL;
282 } else if (vfsmount_group > inode_group) {
277 send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data, 283 send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data,
278 data_is, cookie, file_name, &event); 284 data_is, cookie, file_name, &event);
279 used_vfsmount = true; 285 inode_group = NULL;
280 } else { 286 } else {
281 send_to_group(to_tell, mnt, inode_mark, vfsmount_mark, 287 send_to_group(to_tell, mnt, inode_mark, vfsmount_mark,
282 mask, data, data_is, cookie, file_name, 288 mask, data, data_is, cookie, file_name,
283 &event); 289 &event);
284 used_vfsmount = true;
285 used_inode = true;
286 } 290 }
287 291
288 if (used_inode) 292 if (inode_group)
289 inode_node = srcu_dereference(inode_node->next, 293 inode_node = srcu_dereference(inode_node->next,
290 &fsnotify_mark_srcu); 294 &fsnotify_mark_srcu);
291 if (used_vfsmount) 295 if (vfsmount_group)
292 vfsmount_node = srcu_dereference(vfsmount_node->next, 296 vfsmount_node = srcu_dereference(vfsmount_node->next,
293 &fsnotify_mark_srcu); 297 &fsnotify_mark_srcu);
294 } 298 }