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

Configure Feed

Select the types of activity you want to include in your feed.

fanotify: reduce event objectid to 29-bit hash

objectid is only used by fanotify backend and it is just an optimization
for event merge before comparing all fields in event.

Move the objectid member from common struct fsnotify_event into struct
fanotify_event and reduce it to 29-bit hash to cram it together with the
3-bit event type.

Events of different types are never merged, so the combination of event
type and hash form a 32-bit key for fast compare of events.

This reduces the size of events by one pointer and paves the way for
adding hashed queue support for fanotify.

Link: https://lore.kernel.org/r/20210304104826.3993892-3-amir73il@gmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>

authored by

Amir Goldstein and committed by
Jan Kara
8988f11a 6f73171e

+28 -22
+12 -13
fs/notify/fanotify/fanotify.c
··· 88 88 return fanotify_info_equal(info1, info2); 89 89 } 90 90 91 - static bool fanotify_should_merge(struct fsnotify_event *old_fsn, 92 - struct fsnotify_event *new_fsn) 91 + static bool fanotify_should_merge(struct fanotify_event *old, 92 + struct fanotify_event *new) 93 93 { 94 - struct fanotify_event *old, *new; 94 + pr_debug("%s: old=%p new=%p\n", __func__, old, new); 95 95 96 - pr_debug("%s: old=%p new=%p\n", __func__, old_fsn, new_fsn); 97 - old = FANOTIFY_E(old_fsn); 98 - new = FANOTIFY_E(new_fsn); 99 - 100 - if (old_fsn->objectid != new_fsn->objectid || 96 + if (old->hash != new->hash || 101 97 old->type != new->type || old->pid != new->pid) 102 98 return false; 103 99 ··· 129 133 static int fanotify_merge(struct list_head *list, struct fsnotify_event *event) 130 134 { 131 135 struct fsnotify_event *test_event; 132 - struct fanotify_event *new; 136 + struct fanotify_event *old, *new = FANOTIFY_E(event); 133 137 134 138 pr_debug("%s: list=%p event=%p\n", __func__, list, event); 135 - new = FANOTIFY_E(event); 136 139 137 140 /* 138 141 * Don't merge a permission event with any other event so that we know ··· 142 147 return 0; 143 148 144 149 list_for_each_entry_reverse(test_event, list, list) { 145 - if (fanotify_should_merge(test_event, event)) { 146 - FANOTIFY_E(test_event)->mask |= new->mask; 150 + old = FANOTIFY_E(test_event); 151 + if (fanotify_should_merge(old, new)) { 152 + old->mask |= new->mask; 147 153 return 1; 148 154 } 149 155 } ··· 529 533 struct mem_cgroup *old_memcg; 530 534 struct inode *child = NULL; 531 535 bool name_event = false; 536 + unsigned int hash = 0; 532 537 533 538 if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) { 534 539 /* ··· 597 600 * Use the victim inode instead of the watching inode as the id for 598 601 * event queue, so event reported on parent is merged with event 599 602 * reported on child when both directory and child watches exist. 603 + * Hash object id for queue merge. 600 604 */ 601 - fanotify_init_event(event, (unsigned long)id, mask); 605 + hash = hash_ptr(id, FANOTIFY_EVENT_HASH_BITS); 606 + fanotify_init_event(event, hash, mask); 602 607 if (FAN_GROUP_FLAG(group, FAN_REPORT_TID)) 603 608 event->pid = get_pid(task_pid(current)); 604 609 else
+13 -3
fs/notify/fanotify/fanotify.h
··· 135 135 FANOTIFY_EVENT_TYPE_PATH, 136 136 FANOTIFY_EVENT_TYPE_PATH_PERM, 137 137 FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */ 138 + __FANOTIFY_EVENT_TYPE_NUM 138 139 }; 140 + 141 + #define FANOTIFY_EVENT_TYPE_BITS \ 142 + (ilog2(__FANOTIFY_EVENT_TYPE_NUM - 1) + 1) 143 + #define FANOTIFY_EVENT_HASH_BITS \ 144 + (32 - FANOTIFY_EVENT_TYPE_BITS) 139 145 140 146 struct fanotify_event { 141 147 struct fsnotify_event fse; 142 148 u32 mask; 143 - enum fanotify_event_type type; 149 + struct { 150 + unsigned int type : FANOTIFY_EVENT_TYPE_BITS; 151 + unsigned int hash : FANOTIFY_EVENT_HASH_BITS; 152 + }; 144 153 struct pid *pid; 145 154 }; 146 155 147 156 static inline void fanotify_init_event(struct fanotify_event *event, 148 - unsigned long id, u32 mask) 157 + unsigned int hash, u32 mask) 149 158 { 150 - fsnotify_init_event(&event->fse, id); 159 + fsnotify_init_event(&event->fse); 160 + event->hash = hash; 151 161 event->mask = mask; 152 162 event->pid = NULL; 153 163 }
+1 -1
fs/notify/inotify/inotify_fsnotify.c
··· 107 107 mask &= ~IN_ISDIR; 108 108 109 109 fsn_event = &event->fse; 110 - fsnotify_init_event(fsn_event, 0); 110 + fsnotify_init_event(fsn_event); 111 111 event->mask = mask; 112 112 event->wd = i_mark->wd; 113 113 event->sync_cookie = cookie;
+1 -1
fs/notify/inotify/inotify_user.c
··· 641 641 return ERR_PTR(-ENOMEM); 642 642 } 643 643 group->overflow_event = &oevent->fse; 644 - fsnotify_init_event(group->overflow_event, 0); 644 + fsnotify_init_event(group->overflow_event); 645 645 oevent->mask = FS_Q_OVERFLOW; 646 646 oevent->wd = -1; 647 647 oevent->sync_cookie = 0;
+1 -4
include/linux/fsnotify_backend.h
··· 167 167 */ 168 168 struct fsnotify_event { 169 169 struct list_head list; 170 - unsigned long objectid; /* identifier for queue merges */ 171 170 }; 172 171 173 172 /* ··· 581 582 extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info); 582 583 extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info); 583 584 584 - static inline void fsnotify_init_event(struct fsnotify_event *event, 585 - unsigned long objectid) 585 + static inline void fsnotify_init_event(struct fsnotify_event *event) 586 586 { 587 587 INIT_LIST_HEAD(&event->list); 588 - event->objectid = objectid; 589 588 } 590 589 591 590 #else