fanotify: create overflow event type
authorAmir Goldstein <amir73il@gmail.com>
Wed, 8 Jul 2020 11:11:42 +0000 (14:11 +0300)
committerJan Kara <jack@suse.cz>
Wed, 15 Jul 2020 15:37:03 +0000 (17:37 +0200)
The special overflow event is allocated as struct fanotify_path_event,
but with a null path.

Use a special event type to identify the overflow event, so the helper
fanotify_has_event_path() will always indicate a non null path.

Allocating the overflow event doesn't need any of the fancy stuff in
fanotify_alloc_event(), so create a simplified helper for allocating the
overflow event.

There is also no need to store and report the pid with an overflow event.

Link: https://lore.kernel.org/r/20200708111156.24659-7-amir73il@gmail.com
Suggested-by: Jan Kara <jack@suse.cz>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>
fs/notify/fanotify/fanotify.c
fs/notify/fanotify/fanotify.h
fs/notify/fanotify/fanotify_user.c

index d9fc83d..921ff05 100644 (file)
@@ -344,11 +344,11 @@ static struct inode *fanotify_fid_inode(struct inode *to_tell, u32 event_mask,
        return fsnotify_data_inode(data, data_type);
 }
 
-struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
-                                           struct inode *inode, u32 mask,
-                                           const void *data, int data_type,
-                                           const struct qstr *file_name,
-                                           __kernel_fsid_t *fsid)
+static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
+                                               struct inode *inode, u32 mask,
+                                               const void *data, int data_type,
+                                               const struct qstr *file_name,
+                                               __kernel_fsid_t *fsid)
 {
        struct fanotify_event *event = NULL;
        struct fanotify_fid_event *ffe = NULL;
@@ -426,8 +426,7 @@ init:
         * event queue, so event reported on parent is merged with event
         * reported on child when both directory and child watches exist.
         */
-       fsnotify_init_event(&event->fse, (unsigned long)id);
-       event->mask = mask;
+       fanotify_init_event(event, (unsigned long)id, mask);
        if (FAN_GROUP_FLAG(group, FAN_REPORT_TID))
                event->pid = get_pid(task_pid(current));
        else
@@ -443,15 +442,8 @@ init:
                fanotify_encode_fh(fanotify_event_dir_fh(event), id, gfp);
 
        if (fanotify_event_has_path(event)) {
-               struct path *p = fanotify_event_path(event);
-
-               if (path) {
-                       *p = *path;
-                       path_get(path);
-               } else {
-                       p->mnt = NULL;
-                       p->dentry = NULL;
-               }
+               *fanotify_event_path(event) = *path;
+               path_get(path);
        }
 out:
        memalloc_unuse_memcg();
@@ -640,6 +632,9 @@ static void fanotify_free_event(struct fsnotify_event *fsn_event)
        case FANOTIFY_EVENT_TYPE_FID_NAME:
                fanotify_free_name_event(event);
                break;
+       case FANOTIFY_EVENT_TYPE_OVERFLOW:
+               kfree(event);
+               break;
        default:
                WARN_ON_ONCE(1);
        }
index 8ce7ccf..1b2a3bb 100644 (file)
@@ -63,6 +63,7 @@ enum fanotify_event_type {
        FANOTIFY_EVENT_TYPE_FID_NAME, /* variable length */
        FANOTIFY_EVENT_TYPE_PATH,
        FANOTIFY_EVENT_TYPE_PATH_PERM,
+       FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */
 };
 
 struct fanotify_event {
@@ -72,6 +73,14 @@ struct fanotify_event {
        struct pid *pid;
 };
 
+static inline void fanotify_init_event(struct fanotify_event *event,
+                                      unsigned long id, u32 mask)
+{
+       fsnotify_init_event(&event->fse, id);
+       event->mask = mask;
+       event->pid = NULL;
+}
+
 struct fanotify_fid_event {
        struct fanotify_event fae;
        __kernel_fsid_t fsid;
@@ -202,9 +211,3 @@ static inline struct path *fanotify_event_path(struct fanotify_event *event)
        else
                return NULL;
 }
-
-struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
-                                           struct inode *inode, u32 mask,
-                                           const void *data, int data_type,
-                                           const struct qstr *file_name,
-                                           __kernel_fsid_t *fsid);
index d7f63ae..c9a824e 100644 (file)
@@ -836,13 +836,26 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,
                                 FSNOTIFY_OBJ_TYPE_INODE, mask, flags, fsid);
 }
 
+static struct fsnotify_event *fanotify_alloc_overflow_event(void)
+{
+       struct fanotify_event *oevent;
+
+       oevent = kmalloc(sizeof(*oevent), GFP_KERNEL_ACCOUNT);
+       if (!oevent)
+               return NULL;
+
+       fanotify_init_event(oevent, 0, FS_Q_OVERFLOW);
+       oevent->type = FANOTIFY_EVENT_TYPE_OVERFLOW;
+
+       return &oevent->fse;
+}
+
 /* fanotify syscalls */
 SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 {
        struct fsnotify_group *group;
        int f_flags, fd;
        struct user_struct *user;
-       struct fanotify_event *oevent;
 
        pr_debug("%s: flags=%x event_f_flags=%x\n",
                 __func__, flags, event_f_flags);
@@ -897,13 +910,11 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
        atomic_inc(&user->fanotify_listeners);
        group->memcg = get_mem_cgroup_from_mm(current->mm);
 
-       oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL,
-                                     FSNOTIFY_EVENT_NONE, NULL, NULL);
-       if (unlikely(!oevent)) {
+       group->overflow_event = fanotify_alloc_overflow_event();
+       if (unlikely(!group->overflow_event)) {
                fd = -ENOMEM;
                goto out_destroy_group;
        }
-       group->overflow_event = &oevent->fse;
 
        if (force_o_largefile())
                event_f_flags |= O_LARGEFILE;