From: Amir Goldstein <[email protected]>

We would like to add file range information to pre-content events.

Pass a struct file_range with optional offset and length to event handler
along with pre-content permission event.

Signed-off-by: Amir Goldstein <[email protected]>
---
 fs/notify/fanotify/fanotify.c    | 10 ++++++++--
 fs/notify/fanotify/fanotify.h    |  2 ++
 include/linux/fsnotify.h         | 17 ++++++++++++++++-
 include/linux/fsnotify_backend.h | 32 ++++++++++++++++++++++++++++++++
 4 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index b163594843f5..4e8dce39fa8f 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -549,9 +549,13 @@ static struct fanotify_event 
*fanotify_alloc_path_event(const struct path *path,
        return &pevent->fae;
 }
 
-static struct fanotify_event *fanotify_alloc_perm_event(const struct path 
*path,
+static struct fanotify_event *fanotify_alloc_perm_event(const void *data,
+                                                       int data_type,
                                                        gfp_t gfp)
 {
+       const struct path *path = fsnotify_data_path(data, data_type);
+       const struct file_range *range =
+                           fsnotify_data_file_range(data, data_type);
        struct fanotify_perm_event *pevent;
 
        pevent = kmem_cache_alloc(fanotify_perm_event_cachep, gfp);
@@ -565,6 +569,8 @@ static struct fanotify_event 
*fanotify_alloc_perm_event(const struct path *path,
        pevent->hdr.len = 0;
        pevent->state = FAN_EVENT_INIT;
        pevent->path = *path;
+       pevent->ppos = range ? range->ppos : NULL;
+       pevent->count = range ? range->count : 0;
        path_get(path);
 
        return &pevent->fae;
@@ -802,7 +808,7 @@ static struct fanotify_event *fanotify_alloc_event(
        old_memcg = set_active_memcg(group->memcg);
 
        if (fanotify_is_perm_event(mask)) {
-               event = fanotify_alloc_perm_event(path, gfp);
+               event = fanotify_alloc_perm_event(data, data_type, gfp);
        } else if (fanotify_is_error_event(mask)) {
                event = fanotify_alloc_error_event(group, fsid, data,
                                                   data_type, &hash);
diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h
index e5ab33cae6a7..93598b7d5952 100644
--- a/fs/notify/fanotify/fanotify.h
+++ b/fs/notify/fanotify/fanotify.h
@@ -425,6 +425,8 @@ FANOTIFY_PE(struct fanotify_event *event)
 struct fanotify_perm_event {
        struct fanotify_event fae;
        struct path path;
+       const loff_t *ppos;             /* optional file range info */
+       size_t count;
        u32 response;                   /* userspace answer to the event */
        unsigned short state;           /* state of the event */
        int fd;         /* fd we passed to userspace for this event */
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index fb3837b8de4c..9d001d328619 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -132,6 +132,21 @@ static inline int fsnotify_file(struct file *file, __u32 
mask)
 }
 
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+static inline int fsnotify_file_range(struct file *file, __u32 mask,
+                                     const loff_t *ppos, size_t count)
+{
+       struct file_range range;
+
+       if (file->f_mode & FMODE_NONOTIFY)
+               return 0;
+
+       range.path = &file->f_path;
+       range.ppos = ppos;
+       range.count = count;
+       return fsnotify_parent(range.path->dentry, mask, &range,
+                              FSNOTIFY_EVENT_FILE_RANGE);
+}
+
 /*
  * fsnotify_file_area_perm - permission hook before access/modify of file range
  */
@@ -175,7 +190,7 @@ static inline int fsnotify_file_area_perm(struct file 
*file, int perm_mask,
        else
                return 0;
 
-       return fsnotify_file(file, fsnotify_mask);
+       return fsnotify_file_range(file, fsnotify_mask, ppos, count);
 }
 
 /*
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 200a5e3b1cd4..276320846bfd 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -298,6 +298,7 @@ static inline void fsnotify_group_assert_locked(struct 
fsnotify_group *group)
 /* When calling fsnotify tell it if the data is a path or inode */
 enum fsnotify_data_type {
        FSNOTIFY_EVENT_NONE,
+       FSNOTIFY_EVENT_FILE_RANGE,
        FSNOTIFY_EVENT_PATH,
        FSNOTIFY_EVENT_INODE,
        FSNOTIFY_EVENT_DENTRY,
@@ -310,6 +311,17 @@ struct fs_error_report {
        struct super_block *sb;
 };
 
+struct file_range {
+       const struct path *path;
+       const loff_t *ppos;
+       size_t count;
+};
+
+static inline const struct path *file_range_path(const struct file_range 
*range)
+{
+       return range->path;
+}
+
 static inline struct inode *fsnotify_data_inode(const void *data, int 
data_type)
 {
        switch (data_type) {
@@ -319,6 +331,8 @@ static inline struct inode *fsnotify_data_inode(const void 
*data, int data_type)
                return d_inode(data);
        case FSNOTIFY_EVENT_PATH:
                return d_inode(((const struct path *)data)->dentry);
+       case FSNOTIFY_EVENT_FILE_RANGE:
+               return d_inode(file_range_path(data)->dentry);
        case FSNOTIFY_EVENT_ERROR:
                return ((struct fs_error_report *)data)->inode;
        default:
@@ -334,6 +348,8 @@ static inline struct dentry *fsnotify_data_dentry(const 
void *data, int data_typ
                return (struct dentry *)data;
        case FSNOTIFY_EVENT_PATH:
                return ((const struct path *)data)->dentry;
+       case FSNOTIFY_EVENT_FILE_RANGE:
+               return file_range_path(data)->dentry;
        default:
                return NULL;
        }
@@ -345,6 +361,8 @@ static inline const struct path *fsnotify_data_path(const 
void *data,
        switch (data_type) {
        case FSNOTIFY_EVENT_PATH:
                return data;
+       case FSNOTIFY_EVENT_FILE_RANGE:
+               return file_range_path(data);
        default:
                return NULL;
        }
@@ -360,6 +378,8 @@ static inline struct super_block *fsnotify_data_sb(const 
void *data,
                return ((struct dentry *)data)->d_sb;
        case FSNOTIFY_EVENT_PATH:
                return ((const struct path *)data)->dentry->d_sb;
+       case FSNOTIFY_EVENT_FILE_RANGE:
+               return file_range_path(data)->dentry->d_sb;
        case FSNOTIFY_EVENT_ERROR:
                return ((struct fs_error_report *) data)->sb;
        default:
@@ -379,6 +399,18 @@ static inline struct fs_error_report 
*fsnotify_data_error_report(
        }
 }
 
+static inline const struct file_range *fsnotify_data_file_range(
+                                                       const void *data,
+                                                       int data_type)
+{
+       switch (data_type) {
+       case FSNOTIFY_EVENT_FILE_RANGE:
+               return (struct file_range *)data;
+       default:
+               return NULL;
+       }
+}
+
 /*
  * Index to merged marks iterator array that correlates to a type of watch.
  * The type of watched object can be deduced from the iterator type, but not
-- 
2.43.0


Reply via email to