• Christoph Hellwig's avatar
    driver code: clarify and fix platform device DMA mask allocation · e3a36eb6
    Christoph Hellwig authored
    This does three inter-related things to clarify the usage of the
    platform device dma_mask field. In the process, fix the bug introduced
    by cdfee562 ("driver core: initialize a default DMA mask for
    platform device") that caused Artem Tashkinov's laptop to not boot with
    newer Fedora kernels.
    
    This does:
    
     - First off, rename the field to "platform_dma_mask" to make it
       greppable.
    
       We have way too many different random fields called "dma_mask" in
       various data structures, where some of them are actual masks, and
       some of them are just pointers to the mask. And the structures all
       have pointers to each other, or embed each other inside themselves,
       and "pdev" sometimes means "platform device" and sometimes it means
       "PCI device".
    
       So to make it clear in the code when you actually use this new field,
       give it a unique name (it really should be something even more unique
       like "platform_device_dma_mask", since it's per platform device, not
       per platform, but that gets old really fast, and this is unique
       enough in context).
    
       To further clarify when the field gets used, initialize it when we
       actually start using it with the default value.
    
     - Then, use this field instead of the random one-off allocation in
       platform_device_register_full() that is now unnecessary since we now
       already have a perfectly fine allocation for it in the platform
       device structure.
    
     - The above then allows us to fix the actual bug, where the error path
       of platform_device_register_full() would unconditionally free the
       platform device DMA allocation with 'kfree()'.
    
       That kfree() was dont regardless of whether the allocation had been
       done earlier with the (now removed) kmalloc, or whether
       setup_pdev_dma_masks() had already been used and the dma_mask pointer
       pointed to the mask that was part of the platform device.
    
    It seems most people never triggered the error path, or only triggered
    it from a call chain that set an explicit pdevinfo->dma_mask value (and
    thus caused the unnecessary allocation that was "cleaned up" in the
    error path) before calling platform_device_register_full().
    
    Robin Murphy points out that in Artem's case the wdat_wdt driver failed
    in platform_device_add(), and that was the one that had called
    platform_device_register_full() with pdevinfo.dma_mask = 0, and would
    have caused that kfree() of pdev.dma_mask corrupting the heap.
    
    A later unrelated kmalloc() then oopsed due to the heap corruption.
    
    Fixes: cdfee562 ("driver core: initialize a default DMA mask for platform device")
    Reported-bisected-and-tested-by: default avatarArtem S. Tashkinov <aros@gmx.com>
    Reviewed-by: default avatarRobin Murphy <robin.murphy@arm.com>
    Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    e3a36eb6
platform.c 33.5 KB