Skip to content
  • Arnd Bergmann's avatar
    ALSA: add new 32-bit layout for snd_pcm_mmap_status/control · 80fe7430
    Arnd Bergmann authored
    
    
    The snd_pcm_mmap_status and snd_pcm_mmap_control interfaces are one of the
    trickiest areas to get right when moving to 64-bit time_t in user space.
    
    The snd_pcm_mmap_status structure layout is incompatible with user space
    that uses a 64-bit time_t, so we need a new layout for it. Since the
    SNDRV_PCM_IOCTL_SYNC_PTR ioctl combines it with snd_pcm_mmap_control
    into snd_pcm_sync_ptr, we need to change those two as well.
    
    Both structures are also exported via an mmap() operation on certain
    architectures, and this suffers from incompatibility between 32-bit
    and 64-bit user space. As we have to change both structures anyway,
    this is a good opportunity to fix the mmap() problem as well, so let's
    standardize on the existing 64-bit layout of the structure where possible.
    
    The downside is that we lose mmap() support for existing 32-bit x86 and
    powerpc applications, adding that would introduce very noticeable runtime
    overhead and complexity. My assumption here is that not too many people
    will miss the removed feature, given that:
    
    - Almost all x86 and powerpc users these days are on 64-bit kernels,
    the majority of today's 32-bit users are on architectures that never
    supported mmap (ARM, MIPS, ...).
    - It never worked in compat mode (it was intentionally disabled there)
    - The application already needs to work with a fallback to
    SNDRV_PCM_IOCTL_SYNC_PTR, which will keep working with both the old
    and new structure layout.
    
    Both the ioctl() and mmap() based interfaces are changed at the same
    time, as they are based on the same structures. Unlike other interfaces,
    we change the uapi header to export both the traditional structure and
    a version that is portable between 32-bit and 64-bit user space code
    and that corresponds to the existing 64-bit layout. We further check the
    __USE_TIME_BITS64 macro that will be defined by future C library versions
    whenever we use the new time_t definition, so any existing user space
    source code will not see any changes until it gets rebuilt against a new
    C library. However, the new structures are all visible in addition to the
    old ones, allowing applications to explicitly request the new structures.
    
    In order to detect the difference between the old snd_pcm_mmap_status and
    the new __snd_pcm_mmap_status64 structure from the ioctl command number,
    we rely on one quirk in the structure definition: snd_pcm_mmap_status
    must be aligned to alignof(time_t), which leads the compiler to insert
    four bytes of padding in struct snd_pcm_sync_ptr after 'flags' and a
    corresponding change in the size of snd_pcm_sync_ptr itself. On x86-32
    (and only there), the compiler doesn't use 64-bit alignment in structure,
    so I'm adding an explicit pad in the structure that has no effect on the
    existing 64-bit architectures but ensures that the layout matches for x86.
    
    The snd_pcm_uframes_t type compatibility requires another hack: we can't
    easily make that 64 bit wide, so I leave the type as 'unsigned long',
    but add padding before and after it, to ensure that the data is properly
    aligned to the respective 64-bit field in the in-kernel structure.
    
    For the SNDRV_PCM_MMAP_OFFSET_STATUS/CONTROL constants that are used
    as the virtual file offset in the mmap() function, we also have to
    introduce new constants that depend on hte __USE_TIME_BITS64 macro:
    The existing macros are renamed to SNDRV_PCM_MMAP_OFFSET_STATUS_OLD
    and SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD, they continue to work fine on
    64-bit architectures, but stop working on native 32-bit user space.
    The replacement _NEW constants are now used by default for user space
    built with __USE_TIME_BITS64, those now work on all new kernels for x86,
    ppc and alpha (32 and 64 bit, native and compat). It might be a good idea
    for a future alsa-lib to support both the _OLD and _NEW macros and use
    the corresponding structures directly. Unmodified alsa-lib source code
    will retain the current behavior, so it will no longer be able to use
    mmap() for the status/control structures on 32-bit systems, until either
    the C library gets updated to 64-bit time_t or alsa-lib gets updated to
    support both mmap() layouts.
    
    Co-developed-with: Baolin Wang <baolin.wang@linaro.org>
    Signed-off-by: default avatarBaolin Wang <baolin.wang@linaro.org>
    Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
    80fe7430