diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2007-08-10 08:32:28 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-08-10 08:32:36 -0400 |
commit | c6d0e8014a59b641c0669cf5df151667144f220e (patch) | |
tree | ac16722d835e946e05266ed2208c1cba30c3260d /drivers | |
parent | b01af5ba9105094ba4f1af60da8f7be44321a0c7 (diff) |
[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: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/cio/qdio.c | 92 |
1 files changed, 47 insertions, 45 deletions
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index ed026a1dc324..03347aed2b3e 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c | |||
@@ -81,6 +81,7 @@ static __u32 volatile spare_indicator; | |||
81 | static atomic_t spare_indicator_usecount; | 81 | static atomic_t spare_indicator_usecount; |
82 | #define QDIO_MEMPOOL_SCSSC_ELEMENTS 2 | 82 | #define QDIO_MEMPOOL_SCSSC_ELEMENTS 2 |
83 | static mempool_t *qdio_mempool_scssc; | 83 | static mempool_t *qdio_mempool_scssc; |
84 | static struct kmem_cache *qdio_q_cache; | ||
84 | 85 | ||
85 | static debug_info_t *qdio_dbf_setup; | 86 | static debug_info_t *qdio_dbf_setup; |
86 | static debug_info_t *qdio_dbf_sbal; | 87 | static debug_info_t *qdio_dbf_sbal; |
@@ -1617,23 +1618,21 @@ static void | |||
1617 | qdio_release_irq_memory(struct qdio_irq *irq_ptr) | 1618 | qdio_release_irq_memory(struct qdio_irq *irq_ptr) |
1618 | { | 1619 | { |
1619 | int i; | 1620 | int i; |
1621 | struct qdio_q *q; | ||
1620 | 1622 | ||
1621 | for (i=0;i<QDIO_MAX_QUEUES_PER_IRQ;i++) { | 1623 | for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) { |
1622 | if (!irq_ptr->input_qs[i]) | 1624 | q = irq_ptr->input_qs[i]; |
1623 | goto next; | 1625 | if (q) { |
1624 | 1626 | free_page((unsigned long) q->slib); | |
1625 | kfree(irq_ptr->input_qs[i]->slib); | 1627 | kmem_cache_free(qdio_q_cache, q); |
1626 | kfree(irq_ptr->input_qs[i]); | 1628 | } |
1627 | 1629 | q = irq_ptr->output_qs[i]; | |
1628 | next: | 1630 | if (q) { |
1629 | if (!irq_ptr->output_qs[i]) | 1631 | free_page((unsigned long) q->slib); |
1630 | continue; | 1632 | kmem_cache_free(qdio_q_cache, q); |
1631 | 1633 | } | |
1632 | kfree(irq_ptr->output_qs[i]->slib); | ||
1633 | kfree(irq_ptr->output_qs[i]); | ||
1634 | |||
1635 | } | 1634 | } |
1636 | kfree(irq_ptr->qdr); | 1635 | free_page((unsigned long) irq_ptr->qdr); |
1637 | free_page((unsigned long) irq_ptr); | 1636 | free_page((unsigned long) irq_ptr); |
1638 | } | 1637 | } |
1639 | 1638 | ||
@@ -1680,44 +1679,35 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr, | |||
1680 | { | 1679 | { |
1681 | int i; | 1680 | int i; |
1682 | struct qdio_q *q; | 1681 | struct qdio_q *q; |
1683 | int result=-ENOMEM; | ||
1684 | |||
1685 | for (i=0;i<no_input_qs;i++) { | ||
1686 | q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL); | ||
1687 | 1682 | ||
1688 | if (!q) { | 1683 | for (i = 0; i < no_input_qs; i++) { |
1689 | QDIO_PRINT_ERR("kmalloc of q failed!\n"); | 1684 | q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL); |
1690 | goto out; | 1685 | if (!q) |
1691 | } | 1686 | return -ENOMEM; |
1687 | memset(q, 0, sizeof(*q)); | ||
1692 | 1688 | ||
1693 | q->slib = kmalloc(PAGE_SIZE, GFP_KERNEL); | 1689 | q->slib = (struct slib *) __get_free_page(GFP_KERNEL); |
1694 | if (!q->slib) { | 1690 | if (!q->slib) { |
1695 | QDIO_PRINT_ERR("kmalloc of slib failed!\n"); | 1691 | kmem_cache_free(qdio_q_cache, q); |
1696 | goto out; | 1692 | return -ENOMEM; |
1697 | } | 1693 | } |
1698 | |||
1699 | irq_ptr->input_qs[i]=q; | 1694 | irq_ptr->input_qs[i]=q; |
1700 | } | 1695 | } |
1701 | 1696 | ||
1702 | for (i=0;i<no_output_qs;i++) { | 1697 | for (i = 0; i < no_output_qs; i++) { |
1703 | q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL); | 1698 | q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL); |
1704 | 1699 | if (!q) | |
1705 | if (!q) { | 1700 | return -ENOMEM; |
1706 | goto out; | 1701 | memset(q, 0, sizeof(*q)); |
1707 | } | ||
1708 | 1702 | ||
1709 | q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL); | 1703 | q->slib = (struct slib *) __get_free_page(GFP_KERNEL); |
1710 | if (!q->slib) { | 1704 | if (!q->slib) { |
1711 | QDIO_PRINT_ERR("kmalloc of slib failed!\n"); | 1705 | kmem_cache_free(qdio_q_cache, q); |
1712 | goto out; | 1706 | return -ENOMEM; |
1713 | } | 1707 | } |
1714 | |||
1715 | irq_ptr->output_qs[i]=q; | 1708 | irq_ptr->output_qs[i]=q; |
1716 | } | 1709 | } |
1717 | 1710 | return 0; | |
1718 | result=0; | ||
1719 | out: | ||
1720 | return result; | ||
1721 | } | 1711 | } |
1722 | 1712 | ||
1723 | static void | 1713 | static void |
@@ -2985,17 +2975,17 @@ qdio_allocate(struct qdio_initialize *init_data) | |||
2985 | QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*)); | 2975 | QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*)); |
2986 | 2976 | ||
2987 | if (!irq_ptr) { | 2977 | if (!irq_ptr) { |
2988 | QDIO_PRINT_ERR("kmalloc of irq_ptr failed!\n"); | 2978 | QDIO_PRINT_ERR("allocation of irq_ptr failed!\n"); |
2989 | return -ENOMEM; | 2979 | return -ENOMEM; |
2990 | } | 2980 | } |
2991 | 2981 | ||
2992 | init_MUTEX(&irq_ptr->setting_up_sema); | 2982 | init_MUTEX(&irq_ptr->setting_up_sema); |
2993 | 2983 | ||
2994 | /* QDR must be in DMA area since CCW data address is only 32 bit */ | 2984 | /* QDR must be in DMA area since CCW data address is only 32 bit */ |
2995 | irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA); | 2985 | irq_ptr->qdr = (struct qdr *) __get_free_page(GFP_KERNEL | GFP_DMA); |
2996 | if (!(irq_ptr->qdr)) { | 2986 | if (!(irq_ptr->qdr)) { |
2997 | free_page((unsigned long) irq_ptr); | 2987 | free_page((unsigned long) irq_ptr); |
2998 | QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n"); | 2988 | QDIO_PRINT_ERR("allocation of irq_ptr->qdr failed!\n"); |
2999 | return -ENOMEM; | 2989 | return -ENOMEM; |
3000 | } | 2990 | } |
3001 | QDIO_DBF_TEXT0(0,setup,"qdr:"); | 2991 | QDIO_DBF_TEXT0(0,setup,"qdr:"); |
@@ -3004,6 +2994,7 @@ qdio_allocate(struct qdio_initialize *init_data) | |||
3004 | if (qdio_alloc_qs(irq_ptr, | 2994 | if (qdio_alloc_qs(irq_ptr, |
3005 | init_data->no_input_qs, | 2995 | init_data->no_input_qs, |
3006 | init_data->no_output_qs)) { | 2996 | init_data->no_output_qs)) { |
2997 | QDIO_PRINT_ERR("queue allocation failed!\n"); | ||
3007 | qdio_release_irq_memory(irq_ptr); | 2998 | qdio_release_irq_memory(irq_ptr); |
3008 | return -ENOMEM; | 2999 | return -ENOMEM; |
3009 | } | 3000 | } |
@@ -3895,9 +3886,19 @@ init_QDIO(void) | |||
3895 | if (res) | 3886 | if (res) |
3896 | return res; | 3887 | return res; |
3897 | 3888 | ||
3889 | qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q), | ||
3890 | 256, 0, NULL); | ||
3891 | if (!qdio_q_cache) { | ||
3892 | qdio_release_qdio_memory(); | ||
3893 | return -ENOMEM; | ||
3894 | } | ||
3895 | |||
3898 | res = qdio_register_dbf_views(); | 3896 | res = qdio_register_dbf_views(); |
3899 | if (res) | 3897 | if (res) { |
3898 | kmem_cache_destroy(qdio_q_cache); | ||
3899 | qdio_release_qdio_memory(); | ||
3900 | return res; | 3900 | return res; |
3901 | } | ||
3901 | 3902 | ||
3902 | QDIO_DBF_TEXT0(0,setup,"initQDIO"); | 3903 | QDIO_DBF_TEXT0(0,setup,"initQDIO"); |
3903 | res = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats); | 3904 | res = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats); |
@@ -3929,6 +3930,7 @@ cleanup_QDIO(void) | |||
3929 | qdio_release_qdio_memory(); | 3930 | qdio_release_qdio_memory(); |
3930 | qdio_unregister_dbf_views(); | 3931 | qdio_unregister_dbf_views(); |
3931 | mempool_destroy(qdio_mempool_scssc); | 3932 | mempool_destroy(qdio_mempool_scssc); |
3933 | kmem_cache_destroy(qdio_q_cache); | ||
3932 | bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats); | 3934 | bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats); |
3933 | printk("qdio: %s: module removed\n",version); | 3935 | printk("qdio: %s: module removed\n",version); |
3934 | } | 3936 | } |