ARM: tegra: iovmm: Fix spinlock bug if alloc fails
Tuomas Tynkkynen [Fri, 17 Aug 2012 08:37:02 +0000 (11:37 +0300)]
iovmm_split_free_block leaves the domain's spinlock unlocked if a
memory allocation failed. Unfortunately, all the callers of that
function assume that it takes the spinlock. This will then lead to
double unlocking of the spinlock.

Bug 1035105

Change-Id: Ib4379cad76f053586d6a77b8d0dc9f41af01931a
Signed-off-by: Tuomas Tynkkynen <ttynkkynen@nvidia.com>
Reviewed-on: http://git-master/r/124299
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Krishna Reddy <vdumpa@nvidia.com>

arch/arm/mach-tegra/iovmm.c

index 86a92ae..488c6a6 100644 (file)
@@ -255,11 +255,13 @@ static struct tegra_iovmm_block *iovmm_split_free_block(
        struct tegra_iovmm_block *rem;
        struct tegra_iovmm_block *b;
 
+       spin_unlock(&domain->block_lock);
        rem = kmem_cache_zalloc(iovmm_cache, GFP_KERNEL);
+       spin_lock(&domain->block_lock);
+
        if (!rem)
                return NULL;
 
-       spin_lock(&domain->block_lock);
        p = &domain->free_blocks.rb_node;
 
        rem->start  = block->start + size;
@@ -344,7 +346,6 @@ static struct tegra_iovmm_block *iovmm_alloc_block(
        simalign = SIMALIGN(best, align);
        if (DO_SPLIT(simalign)) {
                iovmm_block_splitting = 1;
-               spin_unlock(&domain->block_lock);
 
                /* Split off misalignment */
                b = best;
@@ -365,7 +366,6 @@ static struct tegra_iovmm_block *iovmm_alloc_block(
 
        if (DO_SPLIT((best->start + best->length) - iovmm_end(best))) {
                iovmm_block_splitting = 1;
-               spin_unlock(&domain->block_lock);
 
                /* Split off excess */
                (void)iovmm_split_free_block(domain, best, size + simalign);
@@ -415,7 +415,6 @@ static struct tegra_iovmm_block *iovmm_allocate_vm(
        /* split the mem before iovm_start. */
        if (DO_SPLIT(iovm_start - best->start)) {
                iovmm_block_splitting = 1;
-               spin_unlock(&domain->block_lock);
                best = iovmm_split_free_block(domain, best,
                        (iovm_start - best->start));
        }
@@ -435,7 +434,6 @@ static struct tegra_iovmm_block *iovmm_allocate_vm(
        /* split the mem after iovm_start+size. */
        if (DO_SPLIT(best->start + best->length - iovmm_end(best))) {
                iovmm_block_splitting = 1;
-               spin_unlock(&domain->block_lock);
                (void)iovmm_split_free_block(domain, best,
                        (iovmm_start(best) - best->start + size));
        }