Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fsnotify: Move object pointer to fsnotify_mark_connector

Move pointer to inode / vfsmount from mark itself to the
fsnotify_mark_connector structure. This is another step on the path
towards decoupling inode / vfsmount lifetime from notification mark
lifetime.

Reviewed-by: Miklos Szeredi <mszeredi@redhat.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>

Jan Kara 86ffe245 9dd813c1

+74 -49
+2 -2
fs/notify/dnotify/dnotify.c
··· 69 69 if (old_mask == new_mask) 70 70 return; 71 71 72 - if (fsn_mark->inode) 73 - fsnotify_recalc_inode_mask(fsn_mark->inode); 72 + if (fsn_mark->connector) 73 + fsnotify_recalc_inode_mask(fsn_mark->connector->inode); 74 74 } 75 75 76 76 /*
+6 -6
fs/notify/fdinfo.c
··· 76 76 struct inotify_inode_mark *inode_mark; 77 77 struct inode *inode; 78 78 79 - if (!(mark->flags & FSNOTIFY_MARK_FLAG_INODE)) 79 + if (!(mark->connector->flags & FSNOTIFY_OBJ_TYPE_INODE)) 80 80 return; 81 81 82 82 inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark); 83 - inode = igrab(mark->inode); 83 + inode = igrab(mark->connector->inode); 84 84 if (inode) { 85 85 /* 86 86 * IN_ALL_EVENTS represents all of the mask bits ··· 115 115 if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY) 116 116 mflags |= FAN_MARK_IGNORED_SURV_MODIFY; 117 117 118 - if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { 119 - inode = igrab(mark->inode); 118 + if (mark->connector->flags & FSNOTIFY_OBJ_TYPE_INODE) { 119 + inode = igrab(mark->connector->inode); 120 120 if (!inode) 121 121 return; 122 122 seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ", ··· 125 125 show_mark_fhandle(m, inode); 126 126 seq_putc(m, '\n'); 127 127 iput(inode); 128 - } else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) { 129 - struct mount *mnt = real_mount(mark->mnt); 128 + } else if (mark->connector->flags & FSNOTIFY_OBJ_TYPE_VFSMOUNT) { 129 + struct mount *mnt = real_mount(mark->connector->mnt); 130 130 131 131 seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n", 132 132 mnt->mnt_id, mflags, mark->mask, mark->ignored_mask);
+2 -1
fs/notify/fsnotify.h
··· 26 26 /* Add mark to a proper place in mark list */ 27 27 extern int fsnotify_add_mark_list(struct fsnotify_mark_connector **connp, 28 28 struct fsnotify_mark *mark, 29 + struct inode *inode, struct vfsmount *mnt, 29 30 int allow_dups); 30 31 /* add a mark to an inode */ 31 32 extern int fsnotify_add_inode_mark(struct fsnotify_mark *mark, ··· 45 44 extern struct fsnotify_mark *fsnotify_find_mark( 46 45 struct fsnotify_mark_connector *conn, 47 46 struct fsnotify_group *group); 48 - /* Destroy all marks in the given list protected by 'lock' */ 47 + /* Destroy all marks connected via given connector protected by 'lock' */ 49 48 extern void fsnotify_destroy_marks(struct fsnotify_mark_connector *conn, 50 49 spinlock_t *lock); 51 50 /* run the list of all marks associated with inode and destroy them */
+7 -11
fs/notify/inode_mark.c
··· 45 45 46 46 void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark) 47 47 { 48 - struct inode *inode = mark->inode; 48 + struct inode *inode = mark->connector->inode; 49 49 50 50 BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); 51 51 assert_spin_locked(&mark->lock); ··· 53 53 spin_lock(&inode->i_lock); 54 54 55 55 hlist_del_init_rcu(&mark->obj_list); 56 - mark->inode = NULL; 56 + mark->connector = NULL; 57 57 58 58 /* 59 59 * this mark is now off the inode->i_fsnotify_marks list and we ··· 69 69 */ 70 70 void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group) 71 71 { 72 - fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_MARK_FLAG_INODE); 72 + fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_OBJ_TYPE_INODE); 73 73 } 74 74 75 75 /* ··· 99 99 100 100 assert_spin_locked(&mark->lock); 101 101 102 - if (mask && 103 - mark->inode && 102 + if (mask && mark->connector && 104 103 !(mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) { 105 104 mark->flags |= FSNOTIFY_MARK_FLAG_OBJECT_PINNED; 106 - inode = igrab(mark->inode); 105 + inode = igrab(mark->connector->inode); 107 106 /* 108 107 * we shouldn't be able to get here if the inode wasn't 109 108 * already safely held in memory. But bug in case it ··· 125 126 { 126 127 int ret; 127 128 128 - mark->flags |= FSNOTIFY_MARK_FLAG_INODE; 129 - 130 129 BUG_ON(!mutex_is_locked(&group->mark_mutex)); 131 130 assert_spin_locked(&mark->lock); 132 131 133 132 spin_lock(&inode->i_lock); 134 - mark->inode = inode; 135 - ret = fsnotify_add_mark_list(&inode->i_fsnotify_marks, mark, 136 - allow_dups); 133 + ret = fsnotify_add_mark_list(&inode->i_fsnotify_marks, mark, inode, 134 + NULL, allow_dups); 137 135 inode->i_fsnotify_mask = fsnotify_recalc_mask(inode->i_fsnotify_marks); 138 136 spin_unlock(&inode->i_lock); 139 137
+22 -10
fs/notify/mark.c
··· 142 142 143 143 mark->flags &= ~FSNOTIFY_MARK_FLAG_ATTACHED; 144 144 145 - if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { 146 - inode = mark->inode; 145 + if (mark->connector->flags & FSNOTIFY_OBJ_TYPE_INODE) { 146 + inode = mark->connector->inode; 147 147 fsnotify_destroy_inode_mark(mark); 148 - } else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) 148 + } else if (mark->connector->flags & FSNOTIFY_OBJ_TYPE_VFSMOUNT) 149 149 fsnotify_destroy_vfsmount_mark(mark); 150 150 else 151 151 BUG(); ··· 275 275 276 276 mark->mask = mask; 277 277 278 - if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) 278 + if (mark->connector && mark->connector->flags & FSNOTIFY_OBJ_TYPE_INODE) 279 279 fsnotify_set_inode_mark_mask_locked(mark, mask); 280 280 } 281 281 ··· 323 323 } 324 324 325 325 static int fsnotify_attach_connector_to_object( 326 - struct fsnotify_mark_connector **connp) 326 + struct fsnotify_mark_connector **connp, 327 + struct inode *inode, 328 + struct vfsmount *mnt) 327 329 { 328 330 struct fsnotify_mark_connector *conn; 329 331 ··· 333 331 if (!conn) 334 332 return -ENOMEM; 335 333 INIT_HLIST_HEAD(&conn->list); 334 + if (inode) { 335 + conn->flags = FSNOTIFY_OBJ_TYPE_INODE; 336 + conn->inode = inode; 337 + } else { 338 + conn->flags = FSNOTIFY_OBJ_TYPE_VFSMOUNT; 339 + conn->mnt = mnt; 340 + } 336 341 /* 337 342 * Make sure 'conn' initialization is visible. Matches 338 343 * lockless_dereference() in fsnotify(). ··· 357 348 * priority, highest number first, and then by the group's location in memory. 358 349 */ 359 350 int fsnotify_add_mark_list(struct fsnotify_mark_connector **connp, 360 - struct fsnotify_mark *mark, int allow_dups) 351 + struct fsnotify_mark *mark, struct inode *inode, 352 + struct vfsmount *mnt, int allow_dups) 361 353 { 362 354 struct fsnotify_mark *lmark, *last = NULL; 363 355 struct fsnotify_mark_connector *conn; ··· 366 356 int err; 367 357 368 358 if (!*connp) { 369 - err = fsnotify_attach_connector_to_object(connp); 359 + err = fsnotify_attach_connector_to_object(connp, inode, mnt); 370 360 if (err) 371 361 return err; 372 362 } ··· 375 365 /* is mark the first mark? */ 376 366 if (hlist_empty(&conn->list)) { 377 367 hlist_add_head_rcu(&mark->obj_list, &conn->list); 378 - return 0; 368 + goto added; 379 369 } 380 370 381 371 /* should mark be in the middle of the current list? */ ··· 388 378 cmp = fsnotify_compare_groups(lmark->group, mark->group); 389 379 if (cmp >= 0) { 390 380 hlist_add_before_rcu(&mark->obj_list, &lmark->obj_list); 391 - return 0; 381 + goto added; 392 382 } 393 383 } 394 384 395 385 BUG_ON(last == NULL); 396 386 /* mark should be the last entry. last is the current last entry */ 397 387 hlist_add_behind_rcu(&mark->obj_list, &last->obj_list); 388 + added: 389 + mark->connector = conn; 398 390 return 0; 399 391 } 400 392 ··· 519 507 */ 520 508 mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); 521 509 list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { 522 - if (mark->flags & flags) 510 + if (mark->connector->flags & flags) 523 511 list_move(&mark->g_list, &to_free); 524 512 } 525 513 mutex_unlock(&group->mark_mutex);
+5 -7
fs/notify/vfsmount_mark.c
··· 31 31 32 32 void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) 33 33 { 34 - fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_MARK_FLAG_VFSMOUNT); 34 + fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_OBJ_TYPE_VFSMOUNT); 35 35 } 36 36 37 37 /* ··· 49 49 50 50 void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark) 51 51 { 52 - struct vfsmount *mnt = mark->mnt; 52 + struct vfsmount *mnt = mark->connector->mnt; 53 53 struct mount *m = real_mount(mnt); 54 54 55 55 BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); ··· 58 58 spin_lock(&mnt->mnt_root->d_lock); 59 59 60 60 hlist_del_init_rcu(&mark->obj_list); 61 - mark->mnt = NULL; 61 + mark->connector = NULL; 62 62 63 63 m->mnt_fsnotify_mask = fsnotify_recalc_mask(m->mnt_fsnotify_marks); 64 64 spin_unlock(&mnt->mnt_root->d_lock); ··· 93 93 struct mount *m = real_mount(mnt); 94 94 int ret; 95 95 96 - mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; 97 - 98 96 BUG_ON(!mutex_is_locked(&group->mark_mutex)); 99 97 assert_spin_locked(&mark->lock); 100 98 101 99 spin_lock(&mnt->mnt_root->d_lock); 102 - mark->mnt = mnt; 103 - ret = fsnotify_add_mark_list(&m->mnt_fsnotify_marks, mark, allow_dups); 100 + ret = fsnotify_add_mark_list(&m->mnt_fsnotify_marks, mark, NULL, mnt, 101 + allow_dups); 104 102 m->mnt_fsnotify_mask = fsnotify_recalc_mask(m->mnt_fsnotify_marks); 105 103 spin_unlock(&mnt->mnt_root->d_lock); 106 104
+10 -7
include/linux/fsnotify_backend.h
··· 200 200 * freed. 201 201 */ 202 202 struct fsnotify_mark_connector { 203 + #define FSNOTIFY_OBJ_TYPE_INODE 0x01 204 + #define FSNOTIFY_OBJ_TYPE_VFSMOUNT 0x02 205 + unsigned int flags; /* Type of object [lock] */ 206 + union { /* Object pointer [lock] */ 207 + struct inode *inode; 208 + struct vfsmount *mnt; 209 + }; 203 210 struct hlist_head list; 204 211 }; 205 212 ··· 241 234 spinlock_t lock; 242 235 /* List of marks for inode / vfsmount [obj_lock] */ 243 236 struct hlist_node obj_list; 244 - union { /* Object pointer [mark->lock, group->mark_mutex] */ 245 - struct inode *inode; /* inode this mark is associated with */ 246 - struct vfsmount *mnt; /* vfsmount this mark is associated with */ 247 - }; 237 + /* Head of list of marks for an object [mark->lock, group->mark_mutex] */ 238 + struct fsnotify_mark_connector *connector; 248 239 /* Events types to ignore [mark->lock, group->mark_mutex] */ 249 240 __u32 ignored_mask; 250 - #define FSNOTIFY_MARK_FLAG_INODE 0x01 251 - #define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02 252 241 #define FSNOTIFY_MARK_FLAG_OBJECT_PINNED 0x04 253 242 #define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x08 254 243 #define FSNOTIFY_MARK_FLAG_ALIVE 0x10 ··· 356 353 extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group); 357 354 /* run all the marks in a group, and clear all of the inode marks */ 358 355 extern void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group); 359 - /* run all the marks in a group, and clear all of the marks where mark->flags & flags is true*/ 356 + /* run all the marks in a group, and clear all of the marks attached to given object type */ 360 357 extern void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, unsigned int flags); 361 358 extern void fsnotify_connector_free(struct fsnotify_mark_connector **connp); 362 359 extern void fsnotify_get_mark(struct fsnotify_mark *mark);
+20 -5
kernel/audit_tree.c
··· 172 172 /* 173 173 * Function to return search key in our hash from chunk. Key 0 is special and 174 174 * should never be present in the hash. 175 + * 176 + * Must be called with chunk->mark.lock held to protect from connector 177 + * becoming NULL. 175 178 */ 179 + static unsigned long __chunk_to_key(struct audit_chunk *chunk) 180 + { 181 + if (!chunk->mark.connector) 182 + return 0; 183 + return (unsigned long)chunk->mark.connector->inode; 184 + } 185 + 176 186 static unsigned long chunk_to_key(struct audit_chunk *chunk) 177 187 { 178 - return (unsigned long)chunk->mark.inode; 188 + unsigned long key; 189 + 190 + spin_lock(&chunk->mark.lock); 191 + key = __chunk_to_key(chunk); 192 + spin_unlock(&chunk->mark.lock); 193 + return key; 179 194 } 180 195 181 196 static inline struct list_head *chunk_hash(unsigned long key) ··· 202 187 /* hash_lock & entry->lock is held by caller */ 203 188 static void insert_hash(struct audit_chunk *chunk) 204 189 { 205 - unsigned long key = chunk_to_key(chunk); 190 + unsigned long key = __chunk_to_key(chunk); 206 191 struct list_head *list; 207 192 208 193 if (!(chunk->mark.flags & FSNOTIFY_MARK_FLAG_ATTACHED)) ··· 291 276 if (!new) 292 277 goto Fallback; 293 278 294 - if (fsnotify_add_mark_locked(&new->mark, entry->group, entry->inode, 295 - NULL, 1)) { 279 + if (fsnotify_add_mark_locked(&new->mark, entry->group, 280 + entry->connector->inode, NULL, 1)) { 296 281 fsnotify_put_mark(&new->mark); 297 282 goto Fallback; 298 283 } ··· 433 418 } 434 419 435 420 if (fsnotify_add_mark_locked(chunk_entry, old_entry->group, 436 - old_entry->inode, NULL, 1)) { 421 + old_entry->connector->inode, NULL, 1)) { 437 422 spin_unlock(&old_entry->lock); 438 423 mutex_unlock(&old_entry->group->mark_mutex); 439 424 fsnotify_put_mark(chunk_entry);