Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7debc970 authored by Li Zhong's avatar Li Zhong Committed by Michael Ellerman
Browse files

powerpc/perf/hv-24x7: Fail 24x7 initcall if create_events_from_catalog() fails



As Michael pointed out, create_events_from_catalog() fails when we
either have:
 - a kernel bug
 - some sort of hypervisor misconfiguration
 - ENOMEM

In all the above cases, we can also fail 24x7 initcall.

For hypervisor errors, EIO is used so there is something reported
in dmesg.

Signed-off-by: default avatarLi Zhong <zhong@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent ad30cb99
Loading
Loading
Loading
Loading
+29 −8
Original line number Original line Diff line number Diff line
@@ -647,7 +647,7 @@ static ssize_t catalog_event_len_validate(struct hv_24x7_event_data *event,


#define MAX_4K (SIZE_MAX / 4096)
#define MAX_4K (SIZE_MAX / 4096)


static void create_events_from_catalog(struct attribute ***events_,
static int create_events_from_catalog(struct attribute ***events_,
		struct attribute ***event_descs_,
		struct attribute ***event_descs_,
		struct attribute ***event_long_descs_)
		struct attribute ***event_long_descs_)
{
{
@@ -665,19 +665,25 @@ static void create_events_from_catalog(struct attribute ***events_,
	void *event_data, *end;
	void *event_data, *end;
	struct hv_24x7_event_data *event;
	struct hv_24x7_event_data *event;
	struct rb_root ev_uniq = RB_ROOT;
	struct rb_root ev_uniq = RB_ROOT;
	int ret = 0;


	if (!page)
	if (!page) {
		ret = -ENOMEM;
		goto e_out;
		goto e_out;
	}


	hret = h_get_24x7_catalog_page(page, 0, 0);
	hret = h_get_24x7_catalog_page(page, 0, 0);
	if (hret)
	if (hret) {
		ret = -EIO;
		goto e_free;
		goto e_free;
	}


	catalog_version_num = be64_to_cpu(page_0->version);
	catalog_version_num = be64_to_cpu(page_0->version);
	catalog_page_len = be32_to_cpu(page_0->length);
	catalog_page_len = be32_to_cpu(page_0->length);


	if (MAX_4K < catalog_page_len) {
	if (MAX_4K < catalog_page_len) {
		pr_err("invalid page count: %zu\n", catalog_page_len);
		pr_err("invalid page count: %zu\n", catalog_page_len);
		ret = -EIO;
		goto e_free;
		goto e_free;
	}
	}


@@ -696,6 +702,7 @@ static void create_events_from_catalog(struct attribute ***events_,
			|| (MAX_4K - event_data_offs < event_data_len)) {
			|| (MAX_4K - event_data_offs < event_data_len)) {
		pr_err("invalid event data offs %zu and/or len %zu\n",
		pr_err("invalid event data offs %zu and/or len %zu\n",
				event_data_offs, event_data_len);
				event_data_offs, event_data_len);
		ret = -EIO;
		goto e_free;
		goto e_free;
	}
	}


@@ -704,12 +711,14 @@ static void create_events_from_catalog(struct attribute ***events_,
				event_data_offs,
				event_data_offs,
				event_data_offs + event_data_len,
				event_data_offs + event_data_len,
				catalog_page_len);
				catalog_page_len);
		ret = -EIO;
		goto e_free;
		goto e_free;
	}
	}


	if (SIZE_MAX / MAX_EVENTS_PER_EVENT_DATA - 1 < event_entry_count) {
	if (SIZE_MAX / MAX_EVENTS_PER_EVENT_DATA - 1 < event_entry_count) {
		pr_err("event_entry_count %zu is invalid\n",
		pr_err("event_entry_count %zu is invalid\n",
				event_entry_count);
				event_entry_count);
		ret = -EIO;
		goto e_free;
		goto e_free;
	}
	}


@@ -722,6 +731,7 @@ static void create_events_from_catalog(struct attribute ***events_,
	event_data = vmalloc(event_data_bytes);
	event_data = vmalloc(event_data_bytes);
	if (!event_data) {
	if (!event_data) {
		pr_err("could not allocate event data\n");
		pr_err("could not allocate event data\n");
		ret = -ENOMEM;
		goto e_free;
		goto e_free;
	}
	}


@@ -741,6 +751,7 @@ static void create_events_from_catalog(struct attribute ***events_,
		if (hret) {
		if (hret) {
			pr_err("failed to get event data in page %zu\n",
			pr_err("failed to get event data in page %zu\n",
					i + event_data_offs);
					i + event_data_offs);
			ret = -EIO;
			goto e_event_data;
			goto e_event_data;
		}
		}
	}
	}
@@ -788,18 +799,24 @@ static void create_events_from_catalog(struct attribute ***events_,
				event_idx_last, event_entry_count, junk_events);
				event_idx_last, event_entry_count, junk_events);


	events = kmalloc_array(attr_max + 1, sizeof(*events), GFP_KERNEL);
	events = kmalloc_array(attr_max + 1, sizeof(*events), GFP_KERNEL);
	if (!events)
	if (!events) {
		ret = -ENOMEM;
		goto e_event_data;
		goto e_event_data;
	}


	event_descs = kmalloc_array(event_idx + 1, sizeof(*event_descs),
	event_descs = kmalloc_array(event_idx + 1, sizeof(*event_descs),
				GFP_KERNEL);
				GFP_KERNEL);
	if (!event_descs)
	if (!event_descs) {
		ret = -ENOMEM;
		goto e_event_attrs;
		goto e_event_attrs;
	}


	event_long_descs = kmalloc_array(event_idx + 1,
	event_long_descs = kmalloc_array(event_idx + 1,
			sizeof(*event_long_descs), GFP_KERNEL);
			sizeof(*event_long_descs), GFP_KERNEL);
	if (!event_long_descs)
	if (!event_long_descs) {
		ret = -ENOMEM;
		goto e_event_descs;
		goto e_event_descs;
	}


	/* Iterate over the catalog filling in the attribute vector */
	/* Iterate over the catalog filling in the attribute vector */
	for (junk_events = 0, event_attr_ct = 0, desc_ct = 0, long_desc_ct = 0,
	for (junk_events = 0, event_attr_ct = 0, desc_ct = 0, long_desc_ct = 0,
@@ -853,7 +870,7 @@ static void create_events_from_catalog(struct attribute ***events_,
	*events_ = events;
	*events_ = events;
	*event_descs_ = event_descs;
	*event_descs_ = event_descs;
	*event_long_descs_ = event_long_descs;
	*event_long_descs_ = event_long_descs;
	return;
	return 0;


e_event_descs:
e_event_descs:
	kfree(event_descs);
	kfree(event_descs);
@@ -867,6 +884,7 @@ e_out:
	*events_ = NULL;
	*events_ = NULL;
	*event_descs_ = NULL;
	*event_descs_ = NULL;
	*event_long_descs_ = NULL;
	*event_long_descs_ = NULL;
	return ret;
}
}


static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
@@ -1275,10 +1293,13 @@ static int hv_24x7_init(void)
	/* sampling not supported */
	/* sampling not supported */
	h_24x7_pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
	h_24x7_pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;


	create_events_from_catalog(&event_group.attrs,
	r = create_events_from_catalog(&event_group.attrs,
				   &event_desc_group.attrs,
				   &event_desc_group.attrs,
				   &event_long_desc_group.attrs);
				   &event_long_desc_group.attrs);


	if (r)
		return r;

	r = perf_pmu_register(&h_24x7_pmu, h_24x7_pmu.name, -1);
	r = perf_pmu_register(&h_24x7_pmu, h_24x7_pmu.name, -1);
	if (r)
	if (r)
		return r;
		return r;