fanotify: reduce event objectid to 29-bit hash

[ Upstream commit 8988f11abb820bacfcc53d498370bfb30f792ec4 ]

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>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Amir Goldstein
2021-03-04 12:48:23 +02:00
committed by Greg Kroah-Hartman
parent 4f14948942
commit 5b57a2b74d
5 changed files with 28 additions and 22 deletions

View File

@@ -88,16 +88,12 @@ static bool fanotify_name_event_equal(struct fanotify_name_event *fne1,
return fanotify_info_equal(info1, info2); return fanotify_info_equal(info1, info2);
} }
static bool fanotify_should_merge(struct fsnotify_event *old_fsn, static bool fanotify_should_merge(struct fanotify_event *old,
struct fsnotify_event *new_fsn) struct fanotify_event *new)
{ {
struct fanotify_event *old, *new; pr_debug("%s: old=%p new=%p\n", __func__, old, new);
pr_debug("%s: old=%p new=%p\n", __func__, old_fsn, new_fsn); if (old->hash != new->hash ||
old = FANOTIFY_E(old_fsn);
new = FANOTIFY_E(new_fsn);
if (old_fsn->objectid != new_fsn->objectid ||
old->type != new->type || old->pid != new->pid) old->type != new->type || old->pid != new->pid)
return false; return false;
@@ -133,10 +129,9 @@ static bool fanotify_should_merge(struct fsnotify_event *old_fsn,
static int fanotify_merge(struct list_head *list, struct fsnotify_event *event) static int fanotify_merge(struct list_head *list, struct fsnotify_event *event)
{ {
struct fsnotify_event *test_event; struct fsnotify_event *test_event;
struct fanotify_event *new; struct fanotify_event *old, *new = FANOTIFY_E(event);
pr_debug("%s: list=%p event=%p\n", __func__, list, event); pr_debug("%s: list=%p event=%p\n", __func__, list, event);
new = FANOTIFY_E(event);
/* /*
* Don't merge a permission event with any other event so that we know * Don't merge a permission event with any other event so that we know
@@ -147,8 +142,9 @@ static int fanotify_merge(struct list_head *list, struct fsnotify_event *event)
return 0; return 0;
list_for_each_entry_reverse(test_event, list, list) { list_for_each_entry_reverse(test_event, list, list) {
if (fanotify_should_merge(test_event, event)) { old = FANOTIFY_E(test_event);
FANOTIFY_E(test_event)->mask |= new->mask; if (fanotify_should_merge(old, new)) {
old->mask |= new->mask;
return 1; return 1;
} }
} }
@@ -533,6 +529,7 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
struct mem_cgroup *old_memcg; struct mem_cgroup *old_memcg;
struct inode *child = NULL; struct inode *child = NULL;
bool name_event = false; bool name_event = false;
unsigned int hash = 0;
if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) { if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) {
/* /*
@@ -600,8 +597,10 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
* Use the victim inode instead of the watching inode as the id for * Use the victim inode instead of the watching inode as the id for
* event queue, so event reported on parent is merged with event * event queue, so event reported on parent is merged with event
* reported on child when both directory and child watches exist. * reported on child when both directory and child watches exist.
* Hash object id for queue merge.
*/ */
fanotify_init_event(event, (unsigned long)id, mask); hash = hash_ptr(id, FANOTIFY_EVENT_HASH_BITS);
fanotify_init_event(event, hash, mask);
if (FAN_GROUP_FLAG(group, FAN_REPORT_TID)) if (FAN_GROUP_FLAG(group, FAN_REPORT_TID))
event->pid = get_pid(task_pid(current)); event->pid = get_pid(task_pid(current));
else else

View File

@@ -135,19 +135,29 @@ enum fanotify_event_type {
FANOTIFY_EVENT_TYPE_PATH, FANOTIFY_EVENT_TYPE_PATH,
FANOTIFY_EVENT_TYPE_PATH_PERM, FANOTIFY_EVENT_TYPE_PATH_PERM,
FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */ FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */
__FANOTIFY_EVENT_TYPE_NUM
}; };
#define FANOTIFY_EVENT_TYPE_BITS \
(ilog2(__FANOTIFY_EVENT_TYPE_NUM - 1) + 1)
#define FANOTIFY_EVENT_HASH_BITS \
(32 - FANOTIFY_EVENT_TYPE_BITS)
struct fanotify_event { struct fanotify_event {
struct fsnotify_event fse; struct fsnotify_event fse;
u32 mask; u32 mask;
enum fanotify_event_type type; struct {
unsigned int type : FANOTIFY_EVENT_TYPE_BITS;
unsigned int hash : FANOTIFY_EVENT_HASH_BITS;
};
struct pid *pid; struct pid *pid;
}; };
static inline void fanotify_init_event(struct fanotify_event *event, static inline void fanotify_init_event(struct fanotify_event *event,
unsigned long id, u32 mask) unsigned int hash, u32 mask)
{ {
fsnotify_init_event(&event->fse, id); fsnotify_init_event(&event->fse);
event->hash = hash;
event->mask = mask; event->mask = mask;
event->pid = NULL; event->pid = NULL;
} }

View File

@@ -114,7 +114,7 @@ int inotify_handle_inode_event(struct fsnotify_mark *inode_mark, u32 mask,
mask &= ~IN_ISDIR; mask &= ~IN_ISDIR;
fsn_event = &event->fse; fsn_event = &event->fse;
fsnotify_init_event(fsn_event, 0); fsnotify_init_event(fsn_event);
event->mask = mask; event->mask = mask;
event->wd = wd; event->wd = wd;
event->sync_cookie = cookie; event->sync_cookie = cookie;

View File

@@ -641,7 +641,7 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
group->overflow_event = &oevent->fse; group->overflow_event = &oevent->fse;
fsnotify_init_event(group->overflow_event, 0); fsnotify_init_event(group->overflow_event);
oevent->mask = FS_Q_OVERFLOW; oevent->mask = FS_Q_OVERFLOW;
oevent->wd = -1; oevent->wd = -1;
oevent->sync_cookie = 0; oevent->sync_cookie = 0;

View File

@@ -167,7 +167,6 @@ struct fsnotify_ops {
*/ */
struct fsnotify_event { struct fsnotify_event {
struct list_head list; struct list_head list;
unsigned long objectid; /* identifier for queue merges */
}; };
/* /*
@@ -582,11 +581,9 @@ extern void fsnotify_put_mark(struct fsnotify_mark *mark);
extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info); extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info);
extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info); extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info);
static inline void fsnotify_init_event(struct fsnotify_event *event, static inline void fsnotify_init_event(struct fsnotify_event *event)
unsigned long objectid)
{ {
INIT_LIST_HEAD(&event->list); INIT_LIST_HEAD(&event->list);
event->objectid = objectid;
} }
#else #else