From: Amir Goldstein <amir7...@gmail.com>

With group class FAN_CLASS_PRE_CONTENT, report offset and length info
along with FAN_PRE_ACCESS and FAN_PRE_MODIFY permission events.

This information is meant to be used by hierarchical storage managers
that want to fill partial content of files on first access to range.

Signed-off-by: Amir Goldstein <amir7...@gmail.com>
---
 fs/notify/fanotify/fanotify.h      |  8 +++++++
 fs/notify/fanotify/fanotify_user.c | 38 ++++++++++++++++++++++++++++++
 include/uapi/linux/fanotify.h      |  7 ++++++
 3 files changed, 53 insertions(+)

diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h
index 93598b7d5952..7f06355afa1f 100644
--- a/fs/notify/fanotify/fanotify.h
+++ b/fs/notify/fanotify/fanotify.h
@@ -448,6 +448,14 @@ static inline bool fanotify_is_perm_event(u32 mask)
                mask & FANOTIFY_PERM_EVENTS;
 }
 
+static inline bool fanotify_event_has_access_range(struct fanotify_event 
*event)
+{
+       if (!(event->mask & FANOTIFY_PRE_CONTENT_EVENTS))
+               return false;
+
+       return FANOTIFY_PERM(event)->ppos;
+}
+
 static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse)
 {
        return container_of(fse, struct fanotify_event, fse);
diff --git a/fs/notify/fanotify/fanotify_user.c 
b/fs/notify/fanotify/fanotify_user.c
index 5ece186d5c50..ed56fe6f5ec7 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -123,6 +123,8 @@ struct kmem_cache *fanotify_perm_event_cachep 
__ro_after_init;
        sizeof(struct fanotify_event_info_pidfd)
 #define FANOTIFY_ERROR_INFO_LEN \
        (sizeof(struct fanotify_event_info_error))
+#define FANOTIFY_RANGE_INFO_LEN \
+       (sizeof(struct fanotify_event_info_range))
 
 static int fanotify_fid_info_len(int fh_len, int name_len)
 {
@@ -182,6 +184,9 @@ static size_t fanotify_event_len(unsigned int info_mode,
        if (info_mode & FAN_REPORT_PIDFD)
                event_len += FANOTIFY_PIDFD_INFO_LEN;
 
+       if (fanotify_event_has_access_range(event))
+               event_len += FANOTIFY_RANGE_INFO_LEN;
+
        return event_len;
 }
 
@@ -526,6 +531,30 @@ static int copy_pidfd_info_to_user(int pidfd,
        return info_len;
 }
 
+static size_t copy_range_info_to_user(struct fanotify_event *event,
+                                     char __user *buf, int count)
+{
+       struct fanotify_perm_event *pevent = FANOTIFY_PERM(event);
+       struct fanotify_event_info_range info = { };
+       size_t info_len = FANOTIFY_RANGE_INFO_LEN;
+
+       if (WARN_ON_ONCE(info_len > count))
+               return -EFAULT;
+
+       if (WARN_ON_ONCE(!pevent->ppos))
+               return -EINVAL;
+
+       info.hdr.info_type = FAN_EVENT_INFO_TYPE_RANGE;
+       info.hdr.len = info_len;
+       info.offset = *(pevent->ppos);
+       info.count = pevent->count;
+
+       if (copy_to_user(buf, &info, info_len))
+               return -EFAULT;
+
+       return info_len;
+}
+
 static int copy_info_records_to_user(struct fanotify_event *event,
                                     struct fanotify_info *info,
                                     unsigned int info_mode, int pidfd,
@@ -647,6 +676,15 @@ static int copy_info_records_to_user(struct fanotify_event 
*event,
                total_bytes += ret;
        }
 
+       if (fanotify_event_has_access_range(event)) {
+               ret = copy_range_info_to_user(event, buf, count);
+               if (ret < 0)
+                       return ret;
+               buf += ret;
+               count -= ret;
+               total_bytes += ret;
+       }
+
        return total_bytes;
 }
 
diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h
index ac00fad66416..cc28dce5f744 100644
--- a/include/uapi/linux/fanotify.h
+++ b/include/uapi/linux/fanotify.h
@@ -145,6 +145,7 @@ struct fanotify_event_metadata {
 #define FAN_EVENT_INFO_TYPE_DFID       3
 #define FAN_EVENT_INFO_TYPE_PIDFD      4
 #define FAN_EVENT_INFO_TYPE_ERROR      5
+#define FAN_EVENT_INFO_TYPE_RANGE      6
 
 /* Special info types for FAN_RENAME */
 #define FAN_EVENT_INFO_TYPE_OLD_DFID_NAME      10
@@ -191,6 +192,12 @@ struct fanotify_event_info_error {
        __u32 error_count;
 };
 
+struct fanotify_event_info_range {
+       struct fanotify_event_info_header hdr;
+       __u64 offset;
+       __u64 count;
+};
+
 /*
  * User space may need to record additional information about its decision.
  * The extra information type records what kind of information is included.
-- 
2.43.0


Reply via email to