diff options
Diffstat (limited to 'fs/notify/fsnotify.c')
| -rw-r--r-- | fs/notify/fsnotify.c | 68 |
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, | |||
| 207 | int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, | 219 | int 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 | } |
