diff options
author | roel kluin <roel.kluin@gmail.com> | 2009-09-20 03:11:28 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-09-22 17:00:12 -0400 |
commit | 5d5baa92664e66f63b75abc51fbcd0b96d81f5d8 (patch) | |
tree | 3252e79137a936d4dfaa9b0f97b7389d99288364 | |
parent | 74a61ebf653c6abe459f228eb40e9f24f7ef1fb7 (diff) |
atm: dereference of he_dev->rbps_virt in he_init_group()
he_dev->rbps_virt or he_dev->rbpl_virt allocation may fail, s
them. Make sure that he_init_group() cleans up after errors.
Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/atm/he.c | 59 |
1 files changed, 50 insertions, 9 deletions
diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 2de64065aa1b..29e66d603d3c 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c | |||
@@ -790,11 +790,15 @@ he_init_group(struct he_dev *he_dev, int group) | |||
790 | he_dev->rbps_base = pci_alloc_consistent(he_dev->pci_dev, | 790 | he_dev->rbps_base = pci_alloc_consistent(he_dev->pci_dev, |
791 | CONFIG_RBPS_SIZE * sizeof(struct he_rbp), &he_dev->rbps_phys); | 791 | CONFIG_RBPS_SIZE * sizeof(struct he_rbp), &he_dev->rbps_phys); |
792 | if (he_dev->rbps_base == NULL) { | 792 | if (he_dev->rbps_base == NULL) { |
793 | hprintk("failed to alloc rbps\n"); | 793 | hprintk("failed to alloc rbps_base\n"); |
794 | return -ENOMEM; | 794 | goto out_destroy_rbps_pool; |
795 | } | 795 | } |
796 | memset(he_dev->rbps_base, 0, CONFIG_RBPS_SIZE * sizeof(struct he_rbp)); | 796 | memset(he_dev->rbps_base, 0, CONFIG_RBPS_SIZE * sizeof(struct he_rbp)); |
797 | he_dev->rbps_virt = kmalloc(CONFIG_RBPS_SIZE * sizeof(struct he_virt), GFP_KERNEL); | 797 | he_dev->rbps_virt = kmalloc(CONFIG_RBPS_SIZE * sizeof(struct he_virt), GFP_KERNEL); |
798 | if (he_dev->rbps_virt == NULL) { | ||
799 | hprintk("failed to alloc rbps_virt\n"); | ||
800 | goto out_free_rbps_base; | ||
801 | } | ||
798 | 802 | ||
799 | for (i = 0; i < CONFIG_RBPS_SIZE; ++i) { | 803 | for (i = 0; i < CONFIG_RBPS_SIZE; ++i) { |
800 | dma_addr_t dma_handle; | 804 | dma_addr_t dma_handle; |
@@ -802,7 +806,7 @@ he_init_group(struct he_dev *he_dev, int group) | |||
802 | 806 | ||
803 | cpuaddr = pci_pool_alloc(he_dev->rbps_pool, GFP_KERNEL|GFP_DMA, &dma_handle); | 807 | cpuaddr = pci_pool_alloc(he_dev->rbps_pool, GFP_KERNEL|GFP_DMA, &dma_handle); |
804 | if (cpuaddr == NULL) | 808 | if (cpuaddr == NULL) |
805 | return -ENOMEM; | 809 | goto out_free_rbps_virt; |
806 | 810 | ||
807 | he_dev->rbps_virt[i].virt = cpuaddr; | 811 | he_dev->rbps_virt[i].virt = cpuaddr; |
808 | he_dev->rbps_base[i].status = RBP_LOANED | RBP_SMALLBUF | (i << RBP_INDEX_OFF); | 812 | he_dev->rbps_base[i].status = RBP_LOANED | RBP_SMALLBUF | (i << RBP_INDEX_OFF); |
@@ -827,17 +831,21 @@ he_init_group(struct he_dev *he_dev, int group) | |||
827 | CONFIG_RBPL_BUFSIZE, 8, 0); | 831 | CONFIG_RBPL_BUFSIZE, 8, 0); |
828 | if (he_dev->rbpl_pool == NULL) { | 832 | if (he_dev->rbpl_pool == NULL) { |
829 | hprintk("unable to create rbpl pool\n"); | 833 | hprintk("unable to create rbpl pool\n"); |
830 | return -ENOMEM; | 834 | goto out_free_rbps_virt; |
831 | } | 835 | } |
832 | 836 | ||
833 | he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev, | 837 | he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev, |
834 | CONFIG_RBPL_SIZE * sizeof(struct he_rbp), &he_dev->rbpl_phys); | 838 | CONFIG_RBPL_SIZE * sizeof(struct he_rbp), &he_dev->rbpl_phys); |
835 | if (he_dev->rbpl_base == NULL) { | 839 | if (he_dev->rbpl_base == NULL) { |
836 | hprintk("failed to alloc rbpl\n"); | 840 | hprintk("failed to alloc rbpl_base\n"); |
837 | return -ENOMEM; | 841 | goto out_destroy_rbpl_pool; |
838 | } | 842 | } |
839 | memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp)); | 843 | memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp)); |
840 | he_dev->rbpl_virt = kmalloc(CONFIG_RBPL_SIZE * sizeof(struct he_virt), GFP_KERNEL); | 844 | he_dev->rbpl_virt = kmalloc(CONFIG_RBPL_SIZE * sizeof(struct he_virt), GFP_KERNEL); |
845 | if (he_dev->rbpl_virt == NULL) { | ||
846 | hprintk("failed to alloc rbpl_virt\n"); | ||
847 | goto out_free_rbpl_base; | ||
848 | } | ||
841 | 849 | ||
842 | for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { | 850 | for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { |
843 | dma_addr_t dma_handle; | 851 | dma_addr_t dma_handle; |
@@ -845,7 +853,7 @@ he_init_group(struct he_dev *he_dev, int group) | |||
845 | 853 | ||
846 | cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &dma_handle); | 854 | cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &dma_handle); |
847 | if (cpuaddr == NULL) | 855 | if (cpuaddr == NULL) |
848 | return -ENOMEM; | 856 | goto out_free_rbpl_virt; |
849 | 857 | ||
850 | he_dev->rbpl_virt[i].virt = cpuaddr; | 858 | he_dev->rbpl_virt[i].virt = cpuaddr; |
851 | he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF); | 859 | he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF); |
@@ -870,7 +878,7 @@ he_init_group(struct he_dev *he_dev, int group) | |||
870 | CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), &he_dev->rbrq_phys); | 878 | CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), &he_dev->rbrq_phys); |
871 | if (he_dev->rbrq_base == NULL) { | 879 | if (he_dev->rbrq_base == NULL) { |
872 | hprintk("failed to allocate rbrq\n"); | 880 | hprintk("failed to allocate rbrq\n"); |
873 | return -ENOMEM; | 881 | goto out_free_rbpl_virt; |
874 | } | 882 | } |
875 | memset(he_dev->rbrq_base, 0, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq)); | 883 | memset(he_dev->rbrq_base, 0, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq)); |
876 | 884 | ||
@@ -894,7 +902,7 @@ he_init_group(struct he_dev *he_dev, int group) | |||
894 | CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), &he_dev->tbrq_phys); | 902 | CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), &he_dev->tbrq_phys); |
895 | if (he_dev->tbrq_base == NULL) { | 903 | if (he_dev->tbrq_base == NULL) { |
896 | hprintk("failed to allocate tbrq\n"); | 904 | hprintk("failed to allocate tbrq\n"); |
897 | return -ENOMEM; | 905 | goto out_free_rbpq_base; |
898 | } | 906 | } |
899 | memset(he_dev->tbrq_base, 0, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq)); | 907 | memset(he_dev->tbrq_base, 0, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq)); |
900 | 908 | ||
@@ -906,6 +914,39 @@ he_init_group(struct he_dev *he_dev, int group) | |||
906 | he_writel(he_dev, CONFIG_TBRQ_THRESH, G0_TBRQ_THRESH + (group * 16)); | 914 | he_writel(he_dev, CONFIG_TBRQ_THRESH, G0_TBRQ_THRESH + (group * 16)); |
907 | 915 | ||
908 | return 0; | 916 | return 0; |
917 | |||
918 | out_free_rbpq_base: | ||
919 | pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * | ||
920 | sizeof(struct he_rbrq), he_dev->rbrq_base, | ||
921 | he_dev->rbrq_phys); | ||
922 | i = CONFIG_RBPL_SIZE; | ||
923 | out_free_rbpl_virt: | ||
924 | while (--i) | ||
925 | pci_pool_free(he_dev->rbps_pool, he_dev->rbpl_virt[i].virt, | ||
926 | he_dev->rbps_base[i].phys); | ||
927 | kfree(he_dev->rbpl_virt); | ||
928 | |||
929 | out_free_rbpl_base: | ||
930 | pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE * | ||
931 | sizeof(struct he_rbp), he_dev->rbpl_base, | ||
932 | he_dev->rbpl_phys); | ||
933 | out_destroy_rbpl_pool: | ||
934 | pci_pool_destroy(he_dev->rbpl_pool); | ||
935 | |||
936 | i = CONFIG_RBPL_SIZE; | ||
937 | out_free_rbps_virt: | ||
938 | while (--i) | ||
939 | pci_pool_free(he_dev->rbpl_pool, he_dev->rbps_virt[i].virt, | ||
940 | he_dev->rbpl_base[i].phys); | ||
941 | kfree(he_dev->rbps_virt); | ||
942 | |||
943 | out_free_rbps_base: | ||
944 | pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE * | ||
945 | sizeof(struct he_rbp), he_dev->rbps_base, | ||
946 | he_dev->rbps_phys); | ||
947 | out_destroy_rbps_pool: | ||
948 | pci_pool_destroy(he_dev->rbps_pool); | ||
949 | return -ENOMEM; | ||
909 | } | 950 | } |
910 | 951 | ||
911 | static int __devinit | 952 | static int __devinit |