fanotify: report file range info with pre-content events

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
This commit is contained in:
Amir Goldstein
2024-11-15 10:30:24 -05:00
committed by Jan Kara
parent 4f8afa3381
commit 870499bc1d
3 changed files with 54 additions and 0 deletions

View 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);

View 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;
}

View 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.