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

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
...@@ -647,7 +647,7 @@ static ssize_t catalog_event_len_validate(struct hv_24x7_event_data *event, ...@@ -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_, ...@@ -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_, ...@@ -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_, ...@@ -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_, ...@@ -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_, ...@@ -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_, ...@@ -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_, ...@@ -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 @@ static void create_events_from_catalog(struct attribute ***events_, ...@@ -867,6 +884,7 @@ static void create_events_from_catalog(struct attribute ***events_,
*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) ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment