Merge tag 'fsnotify_for_v4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull fsnotify updates from Jan Kara:
"fsnotify cleanups unifying handling of different watch types.

This is the shortened fsnotify series from Amir with the last five
patches pulled out. Amir has modified those patches to not change
struct inode but obviously it's too late for those to go into this
merge window"

* tag 'fsnotify_for_v4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
fsnotify: add fsnotify_add_inode_mark() wrappers
fanotify: generalize fanotify_should_send_event()
fsnotify: generalize send_to_group()
fsnotify: generalize iteration of marks by object type
fsnotify: introduce marks iteration helpers
fsnotify: remove redundant arguments to handle_event()
fsnotify: use type id to identify connector object type

+4 -4
fs/notify/dnotify/dnotify.c
··· 79 79 */ 80 80 static int dnotify_handle_event(struct fsnotify_group *group, 81 81 struct inode *inode, 82 - struct fsnotify_mark *inode_mark, 83 - struct fsnotify_mark *vfsmount_mark, 84 82 u32 mask, const void *data, int data_type, 85 83 const unsigned char *file_name, u32 cookie, 86 84 struct fsnotify_iter_info *iter_info) 87 85 { 86 + struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info); 88 87 struct dnotify_mark *dn_mark; 89 88 struct dnotify_struct *dn; 90 89 struct dnotify_struct **prev; ··· 94 95 if (!S_ISDIR(inode->i_mode)) 95 96 return 0; 96 97 97 - BUG_ON(vfsmount_mark); 98 + if (WARN_ON(fsnotify_iter_vfsmount_mark(iter_info))) 99 + return 0; 98 100 99 101 dn_mark = container_of(inode_mark, struct dnotify_mark, fsn_mark); 100 102 ··· 319 319 dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); 320 320 spin_lock(&fsn_mark->lock); 321 321 } else { 322 - error = fsnotify_add_mark_locked(new_fsn_mark, inode, NULL, 0); 322 + error = fsnotify_add_inode_mark_locked(new_fsn_mark, inode, 0); 323 323 if (error) { 324 324 mutex_unlock(&dnotify_group->mark_mutex); 325 325 goto out_err;
+22 -24
fs/notify/fanotify/fanotify.c
··· 87 87 return ret; 88 88 } 89 89 90 - static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark, 91 - struct fsnotify_mark *vfsmnt_mark, 92 - u32 event_mask, 93 - const void *data, int data_type) 90 + static bool fanotify_should_send_event(struct fsnotify_iter_info *iter_info, 91 + u32 event_mask, const void *data, 92 + int data_type) 94 93 { 95 94 __u32 marks_mask = 0, marks_ignored_mask = 0; 96 95 const struct path *path = data; 96 + struct fsnotify_mark *mark; 97 + int type; 97 98 98 - pr_debug("%s: inode_mark=%p vfsmnt_mark=%p mask=%x data=%p" 99 - " data_type=%d\n", __func__, inode_mark, vfsmnt_mark, 100 - event_mask, data, data_type); 99 + pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n", 100 + __func__, iter_info->report_mask, event_mask, data, data_type); 101 101 102 102 /* if we don't have enough info to send an event to userspace say no */ 103 103 if (data_type != FSNOTIFY_EVENT_PATH) ··· 108 108 !d_can_lookup(path->dentry)) 109 109 return false; 110 110 111 - /* 112 - * if the event is for a child and this inode doesn't care about 113 - * events on the child, don't send it! 114 - */ 115 - if (inode_mark && 116 - (!(event_mask & FS_EVENT_ON_CHILD) || 117 - (inode_mark->mask & FS_EVENT_ON_CHILD))) { 118 - marks_mask |= inode_mark->mask; 119 - marks_ignored_mask |= inode_mark->ignored_mask; 120 - } 111 + fsnotify_foreach_obj_type(type) { 112 + if (!fsnotify_iter_should_report_type(iter_info, type)) 113 + continue; 114 + mark = iter_info->marks[type]; 115 + /* 116 + * if the event is for a child and this inode doesn't care about 117 + * events on the child, don't send it! 118 + */ 119 + if (type == FSNOTIFY_OBJ_TYPE_INODE && 120 + (event_mask & FS_EVENT_ON_CHILD) && 121 + !(mark->mask & FS_EVENT_ON_CHILD)) 122 + continue; 121 123 122 - if (vfsmnt_mark) { 123 - marks_mask |= vfsmnt_mark->mask; 124 - marks_ignored_mask |= vfsmnt_mark->ignored_mask; 124 + marks_mask |= mark->mask; 125 + marks_ignored_mask |= mark->ignored_mask; 125 126 } 126 127 127 128 if (d_is_dir(path->dentry) && ··· 179 178 180 179 static int fanotify_handle_event(struct fsnotify_group *group, 181 180 struct inode *inode, 182 - struct fsnotify_mark *inode_mark, 183 - struct fsnotify_mark *fanotify_mark, 184 181 u32 mask, const void *data, int data_type, 185 182 const unsigned char *file_name, u32 cookie, 186 183 struct fsnotify_iter_info *iter_info) ··· 198 199 BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM); 199 200 BUILD_BUG_ON(FAN_ONDIR != FS_ISDIR); 200 201 201 - if (!fanotify_should_send_event(inode_mark, fanotify_mark, mask, data, 202 - data_type)) 202 + if (!fanotify_should_send_event(iter_info, mask, data, data_type)) 203 203 return 0; 204 204 205 205 pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode,
+3 -3
fs/notify/fdinfo.c
··· 77 77 struct inotify_inode_mark *inode_mark; 78 78 struct inode *inode; 79 79 80 - if (!(mark->connector->flags & FSNOTIFY_OBJ_TYPE_INODE)) 80 + if (mark->connector->type != FSNOTIFY_OBJ_TYPE_INODE) 81 81 return; 82 82 83 83 inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark); ··· 116 116 if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY) 117 117 mflags |= FAN_MARK_IGNORED_SURV_MODIFY; 118 118 119 - if (mark->connector->flags & FSNOTIFY_OBJ_TYPE_INODE) { 119 + if (mark->connector->type == FSNOTIFY_OBJ_TYPE_INODE) { 120 120 inode = igrab(mark->connector->inode); 121 121 if (!inode) 122 122 return; ··· 126 126 show_mark_fhandle(m, inode); 127 127 seq_putc(m, '\n'); 128 128 iput(inode); 129 - } else if (mark->connector->flags & FSNOTIFY_OBJ_TYPE_VFSMOUNT) { 129 + } else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) { 130 130 struct mount *mnt = real_mount(mark->connector->mnt); 131 131 132 132 seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n",
+83 -55
fs/notify/fsnotify.c
··· 184 184 EXPORT_SYMBOL_GPL(__fsnotify_parent); 185 185 186 186 static int send_to_group(struct inode *to_tell, 187 - struct fsnotify_mark *inode_mark, 188 - struct fsnotify_mark *vfsmount_mark, 189 187 __u32 mask, const void *data, 190 188 int data_is, u32 cookie, 191 189 const unsigned char *file_name, ··· 193 195 __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); 194 196 __u32 marks_mask = 0; 195 197 __u32 marks_ignored_mask = 0; 198 + struct fsnotify_mark *mark; 199 + int type; 196 200 197 - if (unlikely(!inode_mark && !vfsmount_mark)) { 198 - BUG(); 201 + if (WARN_ON(!iter_info->report_mask)) 199 202 return 0; 200 - } 201 203 202 204 /* clear ignored on inode modification */ 203 205 if (mask & FS_MODIFY) { 204 - if (inode_mark && 205 - !(inode_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) 206 - inode_mark->ignored_mask = 0; 207 - if (vfsmount_mark && 208 - !(vfsmount_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) 209 - vfsmount_mark->ignored_mask = 0; 206 + fsnotify_foreach_obj_type(type) { 207 + if (!fsnotify_iter_should_report_type(iter_info, type)) 208 + continue; 209 + mark = iter_info->marks[type]; 210 + if (mark && 211 + !(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) 212 + mark->ignored_mask = 0; 213 + } 210 214 } 211 215 212 - /* does the inode mark tell us to do something? */ 213 - if (inode_mark) { 214 - group = inode_mark->group; 215 - marks_mask |= inode_mark->mask; 216 - marks_ignored_mask |= inode_mark->ignored_mask; 216 + fsnotify_foreach_obj_type(type) { 217 + if (!fsnotify_iter_should_report_type(iter_info, type)) 218 + continue; 219 + mark = iter_info->marks[type]; 220 + /* does the object mark tell us to do something? */ 221 + if (mark) { 222 + group = mark->group; 223 + marks_mask |= mark->mask; 224 + marks_ignored_mask |= mark->ignored_mask; 225 + } 217 226 } 218 227 219 - /* does the vfsmount_mark tell us to do something? */ 220 - if (vfsmount_mark) { 221 - group = vfsmount_mark->group; 222 - marks_mask |= vfsmount_mark->mask; 223 - marks_ignored_mask |= vfsmount_mark->ignored_mask; 224 - } 225 - 226 - pr_debug("%s: group=%p to_tell=%p mask=%x inode_mark=%p" 227 - " vfsmount_mark=%p marks_mask=%x marks_ignored_mask=%x" 228 + pr_debug("%s: group=%p to_tell=%p mask=%x marks_mask=%x marks_ignored_mask=%x" 228 229 " data=%p data_is=%d cookie=%d\n", 229 - __func__, group, to_tell, mask, inode_mark, vfsmount_mark, 230 - marks_mask, marks_ignored_mask, data, 231 - data_is, cookie); 230 + __func__, group, to_tell, mask, marks_mask, marks_ignored_mask, 231 + data, data_is, cookie); 232 232 233 233 if (!(test_mask & marks_mask & ~marks_ignored_mask)) 234 234 return 0; 235 235 236 - return group->ops->handle_event(group, to_tell, inode_mark, 237 - vfsmount_mark, mask, data, data_is, 236 + return group->ops->handle_event(group, to_tell, mask, data, data_is, 238 237 file_name, cookie, iter_info); 239 238 } 240 239 ··· 256 261 &fsnotify_mark_srcu); 257 262 258 263 return hlist_entry_safe(node, struct fsnotify_mark, obj_list); 264 + } 265 + 266 + /* 267 + * iter_info is a multi head priority queue of marks. 268 + * Pick a subset of marks from queue heads, all with the 269 + * same group and set the report_mask for selected subset. 270 + * Returns the report_mask of the selected subset. 271 + */ 272 + static unsigned int fsnotify_iter_select_report_types( 273 + struct fsnotify_iter_info *iter_info) 274 + { 275 + struct fsnotify_group *max_prio_group = NULL; 276 + struct fsnotify_mark *mark; 277 + int type; 278 + 279 + /* Choose max prio group among groups of all queue heads */ 280 + fsnotify_foreach_obj_type(type) { 281 + mark = iter_info->marks[type]; 282 + if (mark && 283 + fsnotify_compare_groups(max_prio_group, mark->group) > 0) 284 + max_prio_group = mark->group; 285 + } 286 + 287 + if (!max_prio_group) 288 + return 0; 289 + 290 + /* Set the report mask for marks from same group as max prio group */ 291 + iter_info->report_mask = 0; 292 + fsnotify_foreach_obj_type(type) { 293 + mark = iter_info->marks[type]; 294 + if (mark && 295 + fsnotify_compare_groups(max_prio_group, mark->group) == 0) 296 + fsnotify_iter_set_report_type(iter_info, type); 297 + } 298 + 299 + return iter_info->report_mask; 300 + } 301 + 302 + /* 303 + * Pop from iter_info multi head queue, the marks that were iterated in the 304 + * current iteration step. 305 + */ 306 + static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info) 307 + { 308 + int type; 309 + 310 + fsnotify_foreach_obj_type(type) { 311 + if (fsnotify_iter_should_report_type(iter_info, type)) 312 + iter_info->marks[type] = 313 + fsnotify_next_mark(iter_info->marks[type]); 314 + } 259 315 } 260 316 261 317 /* ··· 353 307 354 308 if ((mask & FS_MODIFY) || 355 309 (test_mask & to_tell->i_fsnotify_mask)) { 356 - iter_info.inode_mark = 310 + iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] = 357 311 fsnotify_first_mark(&to_tell->i_fsnotify_marks); 358 312 } 359 313 360 314 if (mnt && ((mask & FS_MODIFY) || 361 315 (test_mask & mnt->mnt_fsnotify_mask))) { 362 - iter_info.inode_mark = 316 + iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] = 363 317 fsnotify_first_mark(&to_tell->i_fsnotify_marks); 364 - iter_info.vfsmount_mark = 318 + iter_info.marks[FSNOTIFY_OBJ_TYPE_VFSMOUNT] = 365 319 fsnotify_first_mark(&mnt->mnt_fsnotify_marks); 366 320 } 367 321 ··· 370 324 * ignore masks are properly reflected for mount mark notifications. 371 325 * That's why this traversal is so complicated... 372 326 */ 373 - while (iter_info.inode_mark || iter_info.vfsmount_mark) { 374 - struct fsnotify_mark *inode_mark = iter_info.inode_mark; 375 - struct fsnotify_mark *vfsmount_mark = iter_info.vfsmount_mark; 376 - 377 - if (inode_mark && vfsmount_mark) { 378 - int cmp = fsnotify_compare_groups(inode_mark->group, 379 - vfsmount_mark->group); 380 - if (cmp > 0) 381 - inode_mark = NULL; 382 - else if (cmp < 0) 383 - vfsmount_mark = NULL; 384 - } 385 - 386 - ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask, 387 - data, data_is, cookie, file_name, 388 - &iter_info); 327 + while (fsnotify_iter_select_report_types(&iter_info)) { 328 + ret = send_to_group(to_tell, mask, data, data_is, cookie, 329 + file_name, &iter_info); 389 330 390 331 if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS)) 391 332 goto out; 392 333 393 - if (inode_mark) 394 - iter_info.inode_mark = 395 - fsnotify_next_mark(iter_info.inode_mark); 396 - if (vfsmount_mark) 397 - iter_info.vfsmount_mark = 398 - fsnotify_next_mark(iter_info.vfsmount_mark); 334 + fsnotify_iter_next(&iter_info); 399 335 } 400 336 ret = 0; 401 337 out:
-6
fs/notify/fsnotify.h
··· 9 9 10 10 #include "../mount.h" 11 11 12 - struct fsnotify_iter_info { 13 - struct fsnotify_mark *inode_mark; 14 - struct fsnotify_mark *vfsmount_mark; 15 - int srcu_idx; 16 - }; 17 - 18 12 /* destroy all events sitting in this groups notification queue */ 19 13 extern void fsnotify_flush_notify(struct fsnotify_group *group); 20 14
+1 -1
fs/notify/group.c
··· 67 67 fsnotify_group_stop_queueing(group); 68 68 69 69 /* Clear all marks for this group and queue them for destruction */ 70 - fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_ALL_TYPES); 70 + fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_ALL_TYPES_MASK); 71 71 72 72 /* 73 73 * Some marks can still be pinned when waiting for response from
-2
fs/notify/inotify/inotify.h
··· 25 25 struct fsnotify_group *group); 26 26 extern int inotify_handle_event(struct fsnotify_group *group, 27 27 struct inode *inode, 28 - struct fsnotify_mark *inode_mark, 29 - struct fsnotify_mark *vfsmount_mark, 30 28 u32 mask, const void *data, int data_type, 31 29 const unsigned char *file_name, u32 cookie, 32 30 struct fsnotify_iter_info *iter_info);
+3 -3
fs/notify/inotify/inotify_fsnotify.c
··· 65 65 66 66 int inotify_handle_event(struct fsnotify_group *group, 67 67 struct inode *inode, 68 - struct fsnotify_mark *inode_mark, 69 - struct fsnotify_mark *vfsmount_mark, 70 68 u32 mask, const void *data, int data_type, 71 69 const unsigned char *file_name, u32 cookie, 72 70 struct fsnotify_iter_info *iter_info) 73 71 { 72 + struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info); 74 73 struct inotify_inode_mark *i_mark; 75 74 struct inotify_event_info *event; 76 75 struct fsnotify_event *fsn_event; ··· 77 78 int len = 0; 78 79 int alloc_len = sizeof(struct inotify_event_info); 79 80 80 - BUG_ON(vfsmount_mark); 81 + if (WARN_ON(fsnotify_iter_vfsmount_mark(iter_info))) 82 + return 0; 81 83 82 84 if ((inode_mark->mask & FS_EXCL_UNLINK) && 83 85 (data_type == FSNOTIFY_EVENT_PATH)) {
+7 -3
fs/notify/inotify/inotify_user.c
··· 485 485 struct fsnotify_group *group) 486 486 { 487 487 struct inotify_inode_mark *i_mark; 488 + struct fsnotify_iter_info iter_info = { }; 489 + 490 + fsnotify_iter_set_report_type_mark(&iter_info, FSNOTIFY_OBJ_TYPE_INODE, 491 + fsn_mark); 488 492 489 493 /* Queue ignore event for the watch */ 490 - inotify_handle_event(group, NULL, fsn_mark, NULL, FS_IN_IGNORED, 491 - NULL, FSNOTIFY_EVENT_NONE, NULL, 0, NULL); 494 + inotify_handle_event(group, NULL, FS_IN_IGNORED, NULL, 495 + FSNOTIFY_EVENT_NONE, NULL, 0, &iter_info); 492 496 493 497 i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark); 494 498 /* remove this mark from the idr */ ··· 582 578 } 583 579 584 580 /* we are on the idr, now get on the inode */ 585 - ret = fsnotify_add_mark_locked(&tmp_i_mark->fsn_mark, inode, NULL, 0); 581 + ret = fsnotify_add_inode_mark_locked(&tmp_i_mark->fsn_mark, inode, 0); 586 582 if (ret) { 587 583 /* we failed to get on the inode, get off the idr */ 588 584 inotify_remove_from_idr(group, tmp_i_mark);
+29 -23
fs/notify/mark.c
··· 119 119 if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) 120 120 new_mask |= mark->mask; 121 121 } 122 - if (conn->flags & FSNOTIFY_OBJ_TYPE_INODE) 122 + if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) 123 123 conn->inode->i_fsnotify_mask = new_mask; 124 - else if (conn->flags & FSNOTIFY_OBJ_TYPE_VFSMOUNT) 124 + else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) 125 125 real_mount(conn->mnt)->mnt_fsnotify_mask = new_mask; 126 126 } 127 127 ··· 139 139 spin_lock(&conn->lock); 140 140 __fsnotify_recalc_mask(conn); 141 141 spin_unlock(&conn->lock); 142 - if (conn->flags & FSNOTIFY_OBJ_TYPE_INODE) 142 + if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) 143 143 __fsnotify_update_child_dentry_flags(conn->inode); 144 144 } 145 145 ··· 166 166 { 167 167 struct inode *inode = NULL; 168 168 169 - if (conn->flags & FSNOTIFY_OBJ_TYPE_INODE) { 169 + if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) { 170 170 inode = conn->inode; 171 171 rcu_assign_pointer(inode->i_fsnotify_marks, NULL); 172 172 inode->i_fsnotify_mask = 0; 173 173 conn->inode = NULL; 174 - conn->flags &= ~FSNOTIFY_OBJ_TYPE_INODE; 175 - } else if (conn->flags & FSNOTIFY_OBJ_TYPE_VFSMOUNT) { 174 + conn->type = FSNOTIFY_OBJ_TYPE_DETACHED; 175 + } else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) { 176 176 rcu_assign_pointer(real_mount(conn->mnt)->mnt_fsnotify_marks, 177 177 NULL); 178 178 real_mount(conn->mnt)->mnt_fsnotify_mask = 0; 179 179 conn->mnt = NULL; 180 - conn->flags &= ~FSNOTIFY_OBJ_TYPE_VFSMOUNT; 180 + conn->type = FSNOTIFY_OBJ_TYPE_DETACHED; 181 181 } 182 182 183 183 return inode; ··· 294 294 295 295 bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info) 296 296 { 297 - /* This can fail if mark is being removed */ 298 - if (!fsnotify_get_mark_safe(iter_info->inode_mark)) 299 - return false; 300 - if (!fsnotify_get_mark_safe(iter_info->vfsmount_mark)) { 301 - fsnotify_put_mark_wake(iter_info->inode_mark); 302 - return false; 297 + int type; 298 + 299 + fsnotify_foreach_obj_type(type) { 300 + /* This can fail if mark is being removed */ 301 + if (!fsnotify_get_mark_safe(iter_info->marks[type])) 302 + goto fail; 303 303 } 304 304 305 305 /* ··· 310 310 srcu_read_unlock(&fsnotify_mark_srcu, iter_info->srcu_idx); 311 311 312 312 return true; 313 + 314 + fail: 315 + for (type--; type >= 0; type--) 316 + fsnotify_put_mark_wake(iter_info->marks[type]); 317 + return false; 313 318 } 314 319 315 320 void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info) 316 321 { 322 + int type; 323 + 317 324 iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); 318 - fsnotify_put_mark_wake(iter_info->inode_mark); 319 - fsnotify_put_mark_wake(iter_info->vfsmount_mark); 325 + fsnotify_foreach_obj_type(type) 326 + fsnotify_put_mark_wake(iter_info->marks[type]); 320 327 } 321 328 322 329 /* ··· 449 442 spin_lock_init(&conn->lock); 450 443 INIT_HLIST_HEAD(&conn->list); 451 444 if (inode) { 452 - conn->flags = FSNOTIFY_OBJ_TYPE_INODE; 445 + conn->type = FSNOTIFY_OBJ_TYPE_INODE; 453 446 conn->inode = igrab(inode); 454 447 } else { 455 - conn->flags = FSNOTIFY_OBJ_TYPE_VFSMOUNT; 448 + conn->type = FSNOTIFY_OBJ_TYPE_VFSMOUNT; 456 449 conn->mnt = mnt; 457 450 } 458 451 /* ··· 486 479 if (!conn) 487 480 goto out; 488 481 spin_lock(&conn->lock); 489 - if (!(conn->flags & (FSNOTIFY_OBJ_TYPE_INODE | 490 - FSNOTIFY_OBJ_TYPE_VFSMOUNT))) { 482 + if (conn->type == FSNOTIFY_OBJ_TYPE_DETACHED) { 491 483 spin_unlock(&conn->lock); 492 484 srcu_read_unlock(&fsnotify_mark_srcu, idx); 493 485 return NULL; ··· 652 646 return NULL; 653 647 } 654 648 655 - /* Clear any marks in a group with given type */ 649 + /* Clear any marks in a group with given type mask */ 656 650 void fsnotify_clear_marks_by_group(struct fsnotify_group *group, 657 - unsigned int type) 651 + unsigned int type_mask) 658 652 { 659 653 struct fsnotify_mark *lmark, *mark; 660 654 LIST_HEAD(to_free); 661 655 struct list_head *head = &to_free; 662 656 663 657 /* Skip selection step if we want to clear all marks. */ 664 - if (type == FSNOTIFY_OBJ_ALL_TYPES) { 658 + if (type_mask == FSNOTIFY_OBJ_ALL_TYPES_MASK) { 665 659 head = &group->marks_list; 666 660 goto clear; 667 661 } ··· 676 670 */ 677 671 mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); 678 672 list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { 679 - if (mark->connector->flags & type) 673 + if ((1U << mark->connector->type) & type_mask) 680 674 list_move(&mark->g_list, &to_free); 681 675 } 682 676 mutex_unlock(&group->mark_mutex);
+69 -10
include/linux/fsnotify_backend.h
··· 98 98 struct fsnotify_ops { 99 99 int (*handle_event)(struct fsnotify_group *group, 100 100 struct inode *inode, 101 - struct fsnotify_mark *inode_mark, 102 - struct fsnotify_mark *vfsmount_mark, 103 101 u32 mask, const void *data, int data_type, 104 102 const unsigned char *file_name, u32 cookie, 105 103 struct fsnotify_iter_info *iter_info); ··· 199 201 #define FSNOTIFY_EVENT_PATH 1 200 202 #define FSNOTIFY_EVENT_INODE 2 201 203 204 + enum fsnotify_obj_type { 205 + FSNOTIFY_OBJ_TYPE_INODE, 206 + FSNOTIFY_OBJ_TYPE_VFSMOUNT, 207 + FSNOTIFY_OBJ_TYPE_COUNT, 208 + FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT 209 + }; 210 + 211 + #define FSNOTIFY_OBJ_TYPE_INODE_FL (1U << FSNOTIFY_OBJ_TYPE_INODE) 212 + #define FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL (1U << FSNOTIFY_OBJ_TYPE_VFSMOUNT) 213 + #define FSNOTIFY_OBJ_ALL_TYPES_MASK ((1U << FSNOTIFY_OBJ_TYPE_COUNT) - 1) 214 + 215 + struct fsnotify_iter_info { 216 + struct fsnotify_mark *marks[FSNOTIFY_OBJ_TYPE_COUNT]; 217 + unsigned int report_mask; 218 + int srcu_idx; 219 + }; 220 + 221 + static inline bool fsnotify_iter_should_report_type( 222 + struct fsnotify_iter_info *iter_info, int type) 223 + { 224 + return (iter_info->report_mask & (1U << type)); 225 + } 226 + 227 + static inline void fsnotify_iter_set_report_type( 228 + struct fsnotify_iter_info *iter_info, int type) 229 + { 230 + iter_info->report_mask |= (1U << type); 231 + } 232 + 233 + static inline void fsnotify_iter_set_report_type_mark( 234 + struct fsnotify_iter_info *iter_info, int type, 235 + struct fsnotify_mark *mark) 236 + { 237 + iter_info->marks[type] = mark; 238 + iter_info->report_mask |= (1U << type); 239 + } 240 + 241 + #define FSNOTIFY_ITER_FUNCS(name, NAME) \ 242 + static inline struct fsnotify_mark *fsnotify_iter_##name##_mark( \ 243 + struct fsnotify_iter_info *iter_info) \ 244 + { \ 245 + return (iter_info->report_mask & FSNOTIFY_OBJ_TYPE_##NAME##_FL) ? \ 246 + iter_info->marks[FSNOTIFY_OBJ_TYPE_##NAME] : NULL; \ 247 + } 248 + 249 + FSNOTIFY_ITER_FUNCS(inode, INODE) 250 + FSNOTIFY_ITER_FUNCS(vfsmount, VFSMOUNT) 251 + 252 + #define fsnotify_foreach_obj_type(type) \ 253 + for (type = 0; type < FSNOTIFY_OBJ_TYPE_COUNT; type++) 254 + 202 255 /* 203 256 * Inode / vfsmount point to this structure which tracks all marks attached to 204 257 * the inode / vfsmount. The reference to inode / vfsmount is held by this ··· 258 209 */ 259 210 struct fsnotify_mark_connector { 260 211 spinlock_t lock; 261 - #define FSNOTIFY_OBJ_TYPE_INODE 0x01 262 - #define FSNOTIFY_OBJ_TYPE_VFSMOUNT 0x02 263 - #define FSNOTIFY_OBJ_ALL_TYPES (FSNOTIFY_OBJ_TYPE_INODE | \ 264 - FSNOTIFY_OBJ_TYPE_VFSMOUNT) 265 - unsigned int flags; /* Type of object [lock] */ 212 + unsigned int type; /* Type of object [lock] */ 266 213 union { /* Object pointer [lock] */ 267 214 struct inode *inode; 268 215 struct vfsmount *mnt; ··· 401 356 extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct inode *inode, 402 357 struct vfsmount *mnt, int allow_dups); 403 358 extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark, 404 - struct inode *inode, struct vfsmount *mnt, int allow_dups); 359 + struct inode *inode, struct vfsmount *mnt, 360 + int allow_dups); 361 + /* attach the mark to the inode */ 362 + static inline int fsnotify_add_inode_mark(struct fsnotify_mark *mark, 363 + struct inode *inode, 364 + int allow_dups) 365 + { 366 + return fsnotify_add_mark(mark, inode, NULL, allow_dups); 367 + } 368 + static inline int fsnotify_add_inode_mark_locked(struct fsnotify_mark *mark, 369 + struct inode *inode, 370 + int allow_dups) 371 + { 372 + return fsnotify_add_mark_locked(mark, inode, NULL, allow_dups); 373 + } 405 374 /* given a group and a mark, flag mark to be freed when all references are dropped */ 406 375 extern void fsnotify_destroy_mark(struct fsnotify_mark *mark, 407 376 struct fsnotify_group *group); ··· 428 369 /* run all the marks in a group, and clear all of the vfsmount marks */ 429 370 static inline void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) 430 371 { 431 - fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_VFSMOUNT); 372 + fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL); 432 373 } 433 374 /* run all the marks in a group, and clear all of the inode marks */ 434 375 static inline void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group) 435 376 { 436 - fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_INODE); 377 + fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_INODE_FL); 437 378 } 438 379 extern void fsnotify_get_mark(struct fsnotify_mark *mark); 439 380 extern void fsnotify_put_mark(struct fsnotify_mark *mark);
+2 -3
kernel/audit_fsnotify.c
··· 109 109 audit_update_mark(audit_mark, dentry->d_inode); 110 110 audit_mark->rule = krule; 111 111 112 - ret = fsnotify_add_mark(&audit_mark->mark, inode, NULL, true); 112 + ret = fsnotify_add_inode_mark(&audit_mark->mark, inode, true); 113 113 if (ret < 0) { 114 114 fsnotify_put_mark(&audit_mark->mark); 115 115 audit_mark = ERR_PTR(ret); ··· 165 165 /* Update mark data in audit rules based on fsnotify events. */ 166 166 static int audit_mark_handle_event(struct fsnotify_group *group, 167 167 struct inode *to_tell, 168 - struct fsnotify_mark *inode_mark, 169 - struct fsnotify_mark *vfsmount_mark, 170 168 u32 mask, const void *data, int data_type, 171 169 const unsigned char *dname, u32 cookie, 172 170 struct fsnotify_iter_info *iter_info) 173 171 { 172 + struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info); 174 173 struct audit_fsnotify_mark *audit_mark; 175 174 const struct inode *inode = NULL; 176 175
+5 -7
kernel/audit_tree.c
··· 288 288 if (!new) 289 289 goto Fallback; 290 290 291 - if (fsnotify_add_mark_locked(&new->mark, entry->connector->inode, 292 - NULL, 1)) { 291 + if (fsnotify_add_inode_mark_locked(&new->mark, entry->connector->inode, 292 + 1)) { 293 293 fsnotify_put_mark(&new->mark); 294 294 goto Fallback; 295 295 } ··· 354 354 return -ENOMEM; 355 355 356 356 entry = &chunk->mark; 357 - if (fsnotify_add_mark(entry, inode, NULL, 0)) { 357 + if (fsnotify_add_inode_mark(entry, inode, 0)) { 358 358 fsnotify_put_mark(entry); 359 359 return -ENOSPC; 360 360 } ··· 434 434 return -ENOENT; 435 435 } 436 436 437 - if (fsnotify_add_mark_locked(chunk_entry, 438 - old_entry->connector->inode, NULL, 1)) { 437 + if (fsnotify_add_inode_mark_locked(chunk_entry, 438 + old_entry->connector->inode, 1)) { 439 439 spin_unlock(&old_entry->lock); 440 440 mutex_unlock(&old_entry->group->mark_mutex); 441 441 fsnotify_put_mark(chunk_entry); ··· 989 989 990 990 static int audit_tree_handle_event(struct fsnotify_group *group, 991 991 struct inode *to_tell, 992 - struct fsnotify_mark *inode_mark, 993 - struct fsnotify_mark *vfsmount_mark, 994 992 u32 mask, const void *data, int data_type, 995 993 const unsigned char *file_name, u32 cookie, 996 994 struct fsnotify_iter_info *iter_info)
+2 -3
kernel/audit_watch.c
··· 160 160 161 161 fsnotify_init_mark(&parent->mark, audit_watch_group); 162 162 parent->mark.mask = AUDIT_FS_WATCH; 163 - ret = fsnotify_add_mark(&parent->mark, inode, NULL, 0); 163 + ret = fsnotify_add_inode_mark(&parent->mark, inode, 0); 164 164 if (ret < 0) { 165 165 audit_free_parent(parent); 166 166 return ERR_PTR(ret); ··· 472 472 /* Update watch data in audit rules based on fsnotify events. */ 473 473 static int audit_watch_handle_event(struct fsnotify_group *group, 474 474 struct inode *to_tell, 475 - struct fsnotify_mark *inode_mark, 476 - struct fsnotify_mark *vfsmount_mark, 477 475 u32 mask, const void *data, int data_type, 478 476 const unsigned char *dname, u32 cookie, 479 477 struct fsnotify_iter_info *iter_info) 480 478 { 479 + struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info); 481 480 const struct inode *inode; 482 481 struct audit_parent *parent; 483 482