s390/qdio: roll-back after queue allocation error
authorJulian Wiedmann <jwi@linux.ibm.com>
Thu, 2 Apr 2020 21:30:41 +0000 (23:30 +0200)
committerVasily Gorbik <gor@linux.ibm.com>
Tue, 28 Apr 2020 11:49:47 +0000 (13:49 +0200)
When qdio_allocate_qs() fails, have it deal with its previous
allocations.
This way qdio_allocate() doesn't need to clean up afterwards.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
drivers/s390/cio/qdio_main.c
drivers/s390/cio/qdio_setup.c

index 579caba8ea93cb970f0f6d3aba846d7aa1c26fdc..09bb69028d67f70a080a0447e4e0c9a619ff6d81 100644 (file)
@@ -1271,7 +1271,6 @@ int qdio_allocate(struct ccw_device *cdev, unsigned int no_input_qs,
        return 0;
 
 err_queues:
-       qdio_free_queues(irq_ptr);
        free_page((unsigned long) irq_ptr->qdr);
 err_qdr:
        free_page(irq_ptr->chsc_page);
index 51dc9a41555a0a56fea90a42a9aeca919f01966f..ebe61cbed443559ae5a3e4713d39082795f368e0 100644 (file)
@@ -135,6 +135,18 @@ output:
        }
 }
 
+static void __qdio_free_queues(struct qdio_q **queues, unsigned int count)
+{
+       struct qdio_q *q;
+       unsigned int i;
+
+       for (i = 0; i < count; i++) {
+               q = queues[i];
+               free_page((unsigned long) q->slib);
+               kmem_cache_free(qdio_q_cache, q);
+       }
+}
+
 static int __qdio_allocate_qs(struct qdio_q **irq_ptr_qs, int nr_queues)
 {
        struct qdio_q *q;
@@ -142,12 +154,15 @@ static int __qdio_allocate_qs(struct qdio_q **irq_ptr_qs, int nr_queues)
 
        for (i = 0; i < nr_queues; i++) {
                q = kmem_cache_zalloc(qdio_q_cache, GFP_KERNEL);
-               if (!q)
+               if (!q) {
+                       __qdio_free_queues(irq_ptr_qs, i);
                        return -ENOMEM;
+               }
 
                q->slib = (struct slib *) __get_free_page(GFP_KERNEL);
                if (!q->slib) {
                        kmem_cache_free(qdio_q_cache, q);
+                       __qdio_free_queues(irq_ptr_qs, i);
                        return -ENOMEM;
                }
                irq_ptr_qs[i] = q;
@@ -162,7 +177,11 @@ int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, int nr_output_qs
        rc = __qdio_allocate_qs(irq_ptr->input_qs, nr_input_qs);
        if (rc)
                return rc;
+
        rc = __qdio_allocate_qs(irq_ptr->output_qs, nr_output_qs);
+       if (rc)
+               __qdio_free_queues(irq_ptr->input_qs, nr_input_qs);
+
        return rc;
 }