s390/cio: fix measurement characteristics memleak

Measurement characteristics are allocated during channel path
registration but not freed during deregistration. Fix this by
embedding these characteristics inside struct channel_path.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Sebastian Ott 2016-01-25 10:30:27 +01:00 committed by Martin Schwidefsky
parent d8f51227f3
commit 0d9bfe9123
3 changed files with 6 additions and 18 deletions

View File

@ -139,11 +139,11 @@ static ssize_t chp_measurement_chars_read(struct file *filp,
device = container_of(kobj, struct device, kobj); device = container_of(kobj, struct device, kobj);
chp = to_channelpath(device); chp = to_channelpath(device);
if (!chp->cmg_chars) if (chp->cmg == -1)
return 0; return 0;
return memory_read_from_buffer(buf, count, &off, return memory_read_from_buffer(buf, count, &off, &chp->cmg_chars,
chp->cmg_chars, sizeof(struct cmg_chars)); sizeof(chp->cmg_chars));
} }
static struct bin_attribute chp_measurement_chars_attr = { static struct bin_attribute chp_measurement_chars_attr = {

View File

@ -48,7 +48,7 @@ struct channel_path {
/* Channel-measurement related stuff: */ /* Channel-measurement related stuff: */
int cmg; int cmg;
int shared; int shared;
void *cmg_chars; struct cmg_chars cmg_chars;
}; };
/* Return channel_path struct for given chpid. */ /* Return channel_path struct for given chpid. */

View File

@ -967,22 +967,19 @@ static void
chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
struct cmg_chars *chars) struct cmg_chars *chars)
{ {
struct cmg_chars *cmg_chars;
int i, mask; int i, mask;
cmg_chars = chp->cmg_chars;
for (i = 0; i < NR_MEASUREMENT_CHARS; i++) { for (i = 0; i < NR_MEASUREMENT_CHARS; i++) {
mask = 0x80 >> (i + 3); mask = 0x80 >> (i + 3);
if (cmcv & mask) if (cmcv & mask)
cmg_chars->values[i] = chars->values[i]; chp->cmg_chars.values[i] = chars->values[i];
else else
cmg_chars->values[i] = 0; chp->cmg_chars.values[i] = 0;
} }
} }
int chsc_get_channel_measurement_chars(struct channel_path *chp) int chsc_get_channel_measurement_chars(struct channel_path *chp)
{ {
struct cmg_chars *cmg_chars;
int ccode, ret; int ccode, ret;
struct { struct {
@ -1006,11 +1003,6 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
u32 data[NR_MEASUREMENT_CHARS]; u32 data[NR_MEASUREMENT_CHARS];
} __attribute__ ((packed)) *scmc_area; } __attribute__ ((packed)) *scmc_area;
chp->cmg_chars = NULL;
cmg_chars = kmalloc(sizeof(*cmg_chars), GFP_KERNEL);
if (!cmg_chars)
return -ENOMEM;
spin_lock_irq(&chsc_page_lock); spin_lock_irq(&chsc_page_lock);
memset(chsc_page, 0, PAGE_SIZE); memset(chsc_page, 0, PAGE_SIZE);
scmc_area = chsc_page; scmc_area = chsc_page;
@ -1042,14 +1034,10 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
/* No cmg-dependent data. */ /* No cmg-dependent data. */
goto out; goto out;
} }
chp->cmg_chars = cmg_chars;
chsc_initialize_cmg_chars(chp, scmc_area->cmcv, chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
(struct cmg_chars *) &scmc_area->data); (struct cmg_chars *) &scmc_area->data);
out: out:
spin_unlock_irq(&chsc_page_lock); spin_unlock_irq(&chsc_page_lock);
if (!chp->cmg_chars)
kfree(cmg_chars);
return ret; return ret;
} }