Skip to content

Commit

Permalink
fanotify: reduce event objectid to 29-bit hash
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Amir Goldstein authored and Jan Kara committed Mar 16, 2021
1 parent 6f73171 commit 8988f11
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 22 deletions.
25 changes: 12 additions & 13 deletions fs/notify/fanotify/fanotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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) {
/*
Expand Down Expand Up @@ -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
Expand Down
16 changes: 13 additions & 3 deletions fs/notify/fanotify/fanotify.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/notify/inotify/inotify_fsnotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,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 = i_mark->wd;
event->sync_cookie = cookie;
Expand Down
2 changes: 1 addition & 1 deletion fs/notify/inotify/inotify_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 1 addition & 4 deletions include/linux/fsnotify_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ struct fsnotify_ops {
*/
struct fsnotify_event {
struct list_head list;
unsigned long objectid; /* identifier for queue merges */
};

/*
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 8988f11

Please sign in to comment.