]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
fanotify: report file range info with pre-content events
authorAmir Goldstein <amir73il@gmail.com>
Fri, 15 Nov 2024 15:30:24 +0000 (10:30 -0500)
committerJan Kara <jack@suse.cz>
Tue, 10 Dec 2024 11:03:17 +0000 (12:03 +0100)
With group class FAN_CLASS_PRE_CONTENT, report offset and length info
along with FAN_PRE_ACCESS pre-content 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 <amir73il@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/b90a9e6c809dd3cad5684da90f23ea93ec6ce8c8.1731684329.git.josef@toxicpanda.com
fs/notify/fanotify/fanotify.h
fs/notify/fanotify/fanotify_user.c
include/uapi/linux/fanotify.h

index 93598b7d5952c524fefb76af6d8ef0f2a61d974b..7f06355afa1f35920d87c65de5e025186501da25 100644 (file)
@@ -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);
index 08e4d8659ef51a3fdb785b0531aac1e4484d95f4..6ef3cc7de5e42b6b2bde6394157704f897253068 100644 (file)
@@ -121,6 +121,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)
 {
@@ -180,6 +182,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;
 }
 
@@ -516,6 +521,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,
@@ -637,6 +666,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;
 }
 
index 7596168c80ebf0d5fa3b9d8b2a241d154bd3ee85..0636a9c85dd013e486deac1024cec84667ea9d9e 100644 (file)
@@ -146,6 +146,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
@@ -192,6 +193,13 @@ struct fanotify_event_info_error {
        __u32 error_count;
 };
 
+struct fanotify_event_info_range {
+       struct fanotify_event_info_header hdr;
+       __u32 pad;
+       __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.