Commit 870499bc authored by Amir Goldstein's avatar Amir Goldstein Committed by Jan Kara
Browse files

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: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Link: https://patch.msgid.link/b90a9e6c809dd3cad5684da90f23ea93ec6ce8c8.1731684329.git.josef@toxicpanda.com
parent 4f8afa33
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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);
+38 −0
Original line number Diff line number Diff line
@@ -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;
}

+8 −0
Original line number Diff line number Diff line
@@ -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.