aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2016-01-25 04:30:27 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2016-01-26 06:47:23 -0500
commit0d9bfe9123cfde59bf5c2e375b59d2a7d5061c4c (patch)
treedabfd7b8bd41bfd5b75fd332aafb03122fa0df78
parentd8f51227f33fbb34e1e54e315175268f54e573e7 (diff)
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>
-rw-r--r--drivers/s390/cio/chp.c6
-rw-r--r--drivers/s390/cio/chp.h2
-rw-r--r--drivers/s390/cio/chsc.c16
3 files changed, 6 insertions, 18 deletions
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index c692dfebd0ba..3d2b6c48c18e 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -139,11 +139,11 @@ static ssize_t chp_measurement_chars_read(struct file *filp,
139 139
140 device = container_of(kobj, struct device, kobj); 140 device = container_of(kobj, struct device, kobj);
141 chp = to_channelpath(device); 141 chp = to_channelpath(device);
142 if (!chp->cmg_chars) 142 if (chp->cmg == -1)
143 return 0; 143 return 0;
144 144
145 return memory_read_from_buffer(buf, count, &off, 145 return memory_read_from_buffer(buf, count, &off, &chp->cmg_chars,
146 chp->cmg_chars, sizeof(struct cmg_chars)); 146 sizeof(chp->cmg_chars));
147} 147}
148 148
149static struct bin_attribute chp_measurement_chars_attr = { 149static struct bin_attribute chp_measurement_chars_attr = {
diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h
index 4efd5b867cc3..af0232290dc4 100644
--- a/drivers/s390/cio/chp.h
+++ b/drivers/s390/cio/chp.h
@@ -48,7 +48,7 @@ struct channel_path {
48 /* Channel-measurement related stuff: */ 48 /* Channel-measurement related stuff: */
49 int cmg; 49 int cmg;
50 int shared; 50 int shared;
51 void *cmg_chars; 51 struct cmg_chars cmg_chars;
52}; 52};
53 53
54/* Return channel_path struct for given chpid. */ 54/* Return channel_path struct for given chpid. */
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index a831d18596a5..5df0efee54db 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -967,22 +967,19 @@ static void
967chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, 967chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
968 struct cmg_chars *chars) 968 struct cmg_chars *chars)
969{ 969{
970 struct cmg_chars *cmg_chars;
971 int i, mask; 970 int i, mask;
972 971
973 cmg_chars = chp->cmg_chars;
974 for (i = 0; i < NR_MEASUREMENT_CHARS; i++) { 972 for (i = 0; i < NR_MEASUREMENT_CHARS; i++) {
975 mask = 0x80 >> (i + 3); 973 mask = 0x80 >> (i + 3);
976 if (cmcv & mask) 974 if (cmcv & mask)
977 cmg_chars->values[i] = chars->values[i]; 975 chp->cmg_chars.values[i] = chars->values[i];
978 else 976 else
979 cmg_chars->values[i] = 0; 977 chp->cmg_chars.values[i] = 0;
980 } 978 }
981} 979}
982 980
983int chsc_get_channel_measurement_chars(struct channel_path *chp) 981int chsc_get_channel_measurement_chars(struct channel_path *chp)
984{ 982{
985 struct cmg_chars *cmg_chars;
986 int ccode, ret; 983 int ccode, ret;
987 984
988 struct { 985 struct {
@@ -1006,11 +1003,6 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
1006 u32 data[NR_MEASUREMENT_CHARS]; 1003 u32 data[NR_MEASUREMENT_CHARS];
1007 } __attribute__ ((packed)) *scmc_area; 1004 } __attribute__ ((packed)) *scmc_area;
1008 1005
1009 chp->cmg_chars = NULL;
1010 cmg_chars = kmalloc(sizeof(*cmg_chars), GFP_KERNEL);
1011 if (!cmg_chars)
1012 return -ENOMEM;
1013
1014 spin_lock_irq(&chsc_page_lock); 1006 spin_lock_irq(&chsc_page_lock);
1015 memset(chsc_page, 0, PAGE_SIZE); 1007 memset(chsc_page, 0, PAGE_SIZE);
1016 scmc_area = chsc_page; 1008 scmc_area = chsc_page;
@@ -1042,14 +1034,10 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
1042 /* No cmg-dependent data. */ 1034 /* No cmg-dependent data. */
1043 goto out; 1035 goto out;
1044 } 1036 }
1045 chp->cmg_chars = cmg_chars;
1046 chsc_initialize_cmg_chars(chp, scmc_area->cmcv, 1037 chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
1047 (struct cmg_chars *) &scmc_area->data); 1038 (struct cmg_chars *) &scmc_area->data);
1048out: 1039out:
1049 spin_unlock_irq(&chsc_page_lock); 1040 spin_unlock_irq(&chsc_page_lock);
1050 if (!chp->cmg_chars)
1051 kfree(cmg_chars);
1052
1053 return ret; 1041 return ret;
1054} 1042}
1055 1043