Commit c6d0e801 authored by Heiko Carstens's avatar Heiko Carstens Committed by Martin Schwidefsky

[S390] qdio: make sure data structures are correctly aligned.

The slsb structure contained at the beginning of the qdio_q structure
must start on a 256 byte boundary. To make sure this is the case even
if slab debugging is turned on create an own slab cache for qdio_q
structures.
Besides that don't use the slab allocator to allocate whole pages. Use
the page allocator instead.
Also fix a few memory leaks in error handling code.
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent b01af5ba
...@@ -81,6 +81,7 @@ static __u32 volatile spare_indicator; ...@@ -81,6 +81,7 @@ static __u32 volatile spare_indicator;
static atomic_t spare_indicator_usecount; static atomic_t spare_indicator_usecount;
#define QDIO_MEMPOOL_SCSSC_ELEMENTS 2 #define QDIO_MEMPOOL_SCSSC_ELEMENTS 2
static mempool_t *qdio_mempool_scssc; static mempool_t *qdio_mempool_scssc;
static struct kmem_cache *qdio_q_cache;
static debug_info_t *qdio_dbf_setup; static debug_info_t *qdio_dbf_setup;
static debug_info_t *qdio_dbf_sbal; static debug_info_t *qdio_dbf_sbal;
...@@ -1617,23 +1618,21 @@ static void ...@@ -1617,23 +1618,21 @@ static void
qdio_release_irq_memory(struct qdio_irq *irq_ptr) qdio_release_irq_memory(struct qdio_irq *irq_ptr)
{ {
int i; int i;
struct qdio_q *q;
for (i=0;i<QDIO_MAX_QUEUES_PER_IRQ;i++) { for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) {
if (!irq_ptr->input_qs[i]) q = irq_ptr->input_qs[i];
goto next; if (q) {
free_page((unsigned long) q->slib);
kfree(irq_ptr->input_qs[i]->slib); kmem_cache_free(qdio_q_cache, q);
kfree(irq_ptr->input_qs[i]); }
q = irq_ptr->output_qs[i];
next: if (q) {
if (!irq_ptr->output_qs[i]) free_page((unsigned long) q->slib);
continue; kmem_cache_free(qdio_q_cache, q);
kfree(irq_ptr->output_qs[i]->slib);
kfree(irq_ptr->output_qs[i]);
} }
kfree(irq_ptr->qdr); }
free_page((unsigned long) irq_ptr->qdr);
free_page((unsigned long) irq_ptr); free_page((unsigned long) irq_ptr);
} }
...@@ -1680,44 +1679,35 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr, ...@@ -1680,44 +1679,35 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr,
{ {
int i; int i;
struct qdio_q *q; struct qdio_q *q;
int result=-ENOMEM;
for (i=0;i<no_input_qs;i++) { for (i = 0; i < no_input_qs; i++) {
q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL); q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL);
if (!q)
if (!q) { return -ENOMEM;
QDIO_PRINT_ERR("kmalloc of q failed!\n"); memset(q, 0, sizeof(*q));
goto out;
}
q->slib = kmalloc(PAGE_SIZE, GFP_KERNEL); q->slib = (struct slib *) __get_free_page(GFP_KERNEL);
if (!q->slib) { if (!q->slib) {
QDIO_PRINT_ERR("kmalloc of slib failed!\n"); kmem_cache_free(qdio_q_cache, q);
goto out; return -ENOMEM;
} }
irq_ptr->input_qs[i]=q; irq_ptr->input_qs[i]=q;
} }
for (i=0;i<no_output_qs;i++) { for (i = 0; i < no_output_qs; i++) {
q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL); q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL);
if (!q)
if (!q) { return -ENOMEM;
goto out; memset(q, 0, sizeof(*q));
}
q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL); q->slib = (struct slib *) __get_free_page(GFP_KERNEL);
if (!q->slib) { if (!q->slib) {
QDIO_PRINT_ERR("kmalloc of slib failed!\n"); kmem_cache_free(qdio_q_cache, q);
goto out; return -ENOMEM;
} }
irq_ptr->output_qs[i]=q; irq_ptr->output_qs[i]=q;
} }
return 0;
result=0;
out:
return result;
} }
static void static void
...@@ -2985,17 +2975,17 @@ qdio_allocate(struct qdio_initialize *init_data) ...@@ -2985,17 +2975,17 @@ qdio_allocate(struct qdio_initialize *init_data)
QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*)); QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*));
if (!irq_ptr) { if (!irq_ptr) {
QDIO_PRINT_ERR("kmalloc of irq_ptr failed!\n"); QDIO_PRINT_ERR("allocation of irq_ptr failed!\n");
return -ENOMEM; return -ENOMEM;
} }
init_MUTEX(&irq_ptr->setting_up_sema); init_MUTEX(&irq_ptr->setting_up_sema);
/* QDR must be in DMA area since CCW data address is only 32 bit */ /* QDR must be in DMA area since CCW data address is only 32 bit */
irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA); irq_ptr->qdr = (struct qdr *) __get_free_page(GFP_KERNEL | GFP_DMA);
if (!(irq_ptr->qdr)) { if (!(irq_ptr->qdr)) {
free_page((unsigned long) irq_ptr); free_page((unsigned long) irq_ptr);
QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n"); QDIO_PRINT_ERR("allocation of irq_ptr->qdr failed!\n");
return -ENOMEM; return -ENOMEM;
} }
QDIO_DBF_TEXT0(0,setup,"qdr:"); QDIO_DBF_TEXT0(0,setup,"qdr:");
...@@ -3004,6 +2994,7 @@ qdio_allocate(struct qdio_initialize *init_data) ...@@ -3004,6 +2994,7 @@ qdio_allocate(struct qdio_initialize *init_data)
if (qdio_alloc_qs(irq_ptr, if (qdio_alloc_qs(irq_ptr,
init_data->no_input_qs, init_data->no_input_qs,
init_data->no_output_qs)) { init_data->no_output_qs)) {
QDIO_PRINT_ERR("queue allocation failed!\n");
qdio_release_irq_memory(irq_ptr); qdio_release_irq_memory(irq_ptr);
return -ENOMEM; return -ENOMEM;
} }
...@@ -3895,9 +3886,19 @@ init_QDIO(void) ...@@ -3895,9 +3886,19 @@ init_QDIO(void)
if (res) if (res)
return res; return res;
qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q),
256, 0, NULL);
if (!qdio_q_cache) {
qdio_release_qdio_memory();
return -ENOMEM;
}
res = qdio_register_dbf_views(); res = qdio_register_dbf_views();
if (res) if (res) {
kmem_cache_destroy(qdio_q_cache);
qdio_release_qdio_memory();
return res; return res;
}
QDIO_DBF_TEXT0(0,setup,"initQDIO"); QDIO_DBF_TEXT0(0,setup,"initQDIO");
res = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats); res = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
...@@ -3929,6 +3930,7 @@ cleanup_QDIO(void) ...@@ -3929,6 +3930,7 @@ cleanup_QDIO(void)
qdio_release_qdio_memory(); qdio_release_qdio_memory();
qdio_unregister_dbf_views(); qdio_unregister_dbf_views();
mempool_destroy(qdio_mempool_scssc); mempool_destroy(qdio_mempool_scssc);
kmem_cache_destroy(qdio_q_cache);
bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats); bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
printk("qdio: %s: module removed\n",version); printk("qdio: %s: module removed\n",version);
} }
......
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