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);
}
static bool fanotify_should_merge(struct fsnotify_event *old_fsn,
struct fsnotify_event *new_fsn)
static bool fanotify_should_merge(struct fanotify_event *old,
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);
old = FANOTIFY_E(old_fsn);
new = FANOTIFY_E(new_fsn);
if (old_fsn->objectid != new_fsn->objectid ||
if (old->hash != new->hash ||
old->type != new->type || old->pid != new->pid)
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)
{
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);
new = FANOTIFY_E(event);
/*
* 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;
list_for_each_entry_reverse(test_event, list, list) {
if (fanotify_should_merge(test_event, event)) {
FANOTIFY_E(test_event)->mask |= new->mask;
old = FANOTIFY_E(test_event);
if (fanotify_should_merge(old, new)) {
old->mask |= new->mask;
return 1;
}
}
@@ -533,6 +529,7 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
struct mem_cgroup *old_memcg;
struct inode *child = NULL;
bool name_event = false;
unsigned int hash = 0;
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
* event queue, so event reported on parent is merged with event
* 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))
event->pid = get_pid(task_pid(current));
else

View File

@@ -135,19 +135,29 @@ enum fanotify_event_type {
FANOTIFY_EVENT_TYPE_PATH,
FANOTIFY_EVENT_TYPE_PATH_PERM,
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 fsnotify_event fse;
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;
};
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->pid = NULL;
}

View File

@@ -114,7 +114,7 @@ int inotify_handle_inode_event(struct fsnotify_mark *inode_mark, u32 mask,
mask &= ~IN_ISDIR;
fsn_event = &event->fse;
fsnotify_init_event(fsn_event, 0);
fsnotify_init_event(fsn_event);
event->mask = mask;
event->wd = wd;
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);
}
group->overflow_event = &oevent->fse;
fsnotify_init_event(group->overflow_event, 0);
fsnotify_init_event(group->overflow_event);
oevent->mask = FS_Q_OVERFLOW;
oevent->wd = -1;
oevent->sync_cookie = 0;

View File

@@ -167,7 +167,6 @@ struct fsnotify_ops {
*/
struct fsnotify_event {
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 bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info);
static inline void fsnotify_init_event(struct fsnotify_event *event,
unsigned long objectid)
static inline void fsnotify_init_event(struct fsnotify_event *event)
{
INIT_LIST_HEAD(&event->list);
event->objectid = objectid;
}
#else