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:

committed by
Greg Kroah-Hartman

parent
4f14948942
commit
5b57a2b74d
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user