nouveau/bios: Fix tracking of BIOS image data
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 2 Apr 2012 03:38:19 +0000 (13:38 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 2 Apr 2012 10:06:33 +0000 (11:06 +0100)
The code tries various methods for retreiving the BIOS data. However
it doesn't clear the bios->data pointer between the iterations.

In some cases, the shadow() method will fail and not update bios->data
at all, which will cause us to "score" the old data and incorrectly
attribute that score to the new method. This can cause double frees
later when disposing of the unused data.

Additionally, we were not freeing the data for methods that fail the
score test (we only freed when a "best" is superseeded, not when the
new method has a lower score than the exising "best"). Fix that as well.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Ben Skeggs <bskeggs@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/nouveau/nouveau_bios.c

index 80963d05b54aad27ebe0e1f3325fc9c923221daf..1947d6139a38e4cb7234fe090ec2456c7a3ac8d3 100644 (file)
@@ -273,6 +273,7 @@ bios_shadow(struct drm_device *dev)
                mthd->score = score_vbios(bios, mthd->rw);
                mthd->size = bios->length;
                mthd->data = bios->data;
                mthd->score = score_vbios(bios, mthd->rw);
                mthd->size = bios->length;
                mthd->data = bios->data;
+               bios->data = NULL;
        } while (mthd->score != 3 && (++mthd)->shadow);
 
        mthd = shadow_methods;
        } while (mthd->score != 3 && (++mthd)->shadow);
 
        mthd = shadow_methods;
@@ -281,7 +282,8 @@ bios_shadow(struct drm_device *dev)
                if (mthd->score > best->score) {
                        kfree(best->data);
                        best = mthd;
                if (mthd->score > best->score) {
                        kfree(best->data);
                        best = mthd;
-               }
+               } else
+                       kfree(mthd->data);
        } while ((++mthd)->shadow);
 
        if (best->score) {
        } while ((++mthd)->shadow);
 
        if (best->score) {