lkml.org 
[lkml]   [2022]   [Jul]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH net-next 1/4] bitmap: add converting from/to 64-bit arrays of explicit byteorder
    Date
    Unlike bitmaps, which are purely host-endian and host-type, arrays
    of bits can have not only explicit type, but explicit Endianness
    as well. They can come from the userspace, network, hardware etc.
    Add ability to pass explicitly-byteordered arrays of u64s to
    bitmap_{from,to}_arr64() by extending the already existing external
    functions and adding a couple static inlines, just to not change
    the prototypes of the already existing ones. Users of the existing
    API which previously were being optimized to a simple copy are not
    affected, since the externals are being called only when byteswap
    is needed.

    Signed-off-by: Alexander Lobakin <alexandr.lobakin@intel.com>
    ---
    include/linux/bitmap.h | 58 ++++++++++++++++++++++++++----
    lib/bitmap.c | 82 ++++++++++++++++++++++++++++++++----------
    2 files changed, 115 insertions(+), 25 deletions(-)

    diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
    index 035d4ac66641..95408d6e0f94 100644
    --- a/include/linux/bitmap.h
    +++ b/include/linux/bitmap.h
    @@ -72,8 +72,10 @@ struct device;
    * bitmap_allocate_region(bitmap, pos, order) Allocate specified bit region
    * bitmap_from_arr32(dst, buf, nbits) Copy nbits from u32[] buf to dst
    * bitmap_from_arr64(dst, buf, nbits) Copy nbits from u64[] buf to dst
    + * bitmap_from_arr64_type(dst, buf, nbits, type) Copy nbits from {u,be,le}64[]
    * bitmap_to_arr32(buf, src, nbits) Copy nbits from buf to u32[] dst
    * bitmap_to_arr64(buf, src, nbits) Copy nbits from buf to u64[] dst
    + * bitmap_to_arr64_type(buf, src, nbits, type) Copy nbits to {u,be,le}64[] dst
    * bitmap_get_value8(map, start) Get 8bit value from map at start
    * bitmap_set_value8(map, value, start) Set 8bit value to map at start
    *
    @@ -299,22 +301,64 @@ void bitmap_to_arr32(u32 *buf, const unsigned long *bitmap,
    (const unsigned long *) (bitmap), (nbits))
    #endif

    +enum {
    + BITMAP_ARR_U64 = 0U,
    +#ifdef __BIG_ENDIAN
    + BITMAP_ARR_BE64 = BITMAP_ARR_U64,
    + BITMAP_ARR_LE64,
    +#else
    + BITMAP_ARR_LE64 = BITMAP_ARR_U64,
    + BITMAP_ARR_BE64,
    +#endif
    + __BITMAP_ARR_TYPE_NUM,
    +};
    +
    +void __bitmap_from_arr64_type(unsigned long *bitmap, const void *buf,
    + unsigned int nbits, u32 type);
    +void __bitmap_to_arr64_type(void *arr, const unsigned long *buf,
    + unsigned int nbits, u32 type);
    +
    /*
    * On 64-bit systems bitmaps are represented as u64 arrays internally. On LE32
    * machines the order of hi and lo parts of numbers match the bitmap structure.
    * In both cases conversion is not needed when copying data from/to arrays of
    * u64.
    */
    -#if (BITS_PER_LONG == 32) && defined(__BIG_ENDIAN)
    -void bitmap_from_arr64(unsigned long *bitmap, const u64 *buf, unsigned int nbits);
    -void bitmap_to_arr64(u64 *buf, const unsigned long *bitmap, unsigned int nbits);
    +#ifdef __BIG_ENDIAN
    +#define bitmap_is_arr64_native(type) \
    + (__builtin_constant_p(type) && (type) == BITMAP_ARR_U64 && \
    + BITS_PER_LONG == 64)
    #else
    -#define bitmap_from_arr64(bitmap, buf, nbits) \
    - bitmap_copy_clear_tail((unsigned long *)(bitmap), (const unsigned long *)(buf), (nbits))
    -#define bitmap_to_arr64(buf, bitmap, nbits) \
    - bitmap_copy_clear_tail((unsigned long *)(buf), (const unsigned long *)(bitmap), (nbits))
    +#define bitmap_is_arr64_native(type) \
    + (__builtin_constant_p(type) && (type) == BITMAP_ARR_U64)
    #endif

    +static __always_inline void bitmap_from_arr64_type(unsigned long *bitmap,
    + const void *buf,
    + unsigned int nbits,
    + u32 type)
    +{
    + if (bitmap_is_arr64_native(type))
    + bitmap_copy_clear_tail(bitmap, buf, nbits);
    + else
    + __bitmap_from_arr64_type(bitmap, buf, nbits, type);
    +}
    +
    +static __always_inline void bitmap_to_arr64_type(void *buf,
    + const unsigned long *bitmap,
    + unsigned int nbits, u32 type)
    +{
    + if (bitmap_is_arr64_native(type))
    + bitmap_copy_clear_tail(buf, bitmap, nbits);
    + else
    + __bitmap_to_arr64_type(buf, bitmap, nbits, type);
    +}
    +
    +#define bitmap_from_arr64(bitmap, buf, nbits) \
    + bitmap_from_arr64_type((bitmap), (buf), (nbits), BITMAP_ARR_U64)
    +#define bitmap_to_arr64(buf, bitmap, nbits) \
    + bitmap_to_arr64_type((buf), (bitmap), (nbits), BITMAP_ARR_U64)
    +
    static inline bool bitmap_and(unsigned long *dst, const unsigned long *src1,
    const unsigned long *src2, unsigned int nbits)
    {
    diff --git a/lib/bitmap.c b/lib/bitmap.c
    index 2b67cd657692..e660077f2099 100644
    --- a/lib/bitmap.c
    +++ b/lib/bitmap.c
    @@ -1513,23 +1513,46 @@ void bitmap_to_arr32(u32 *buf, const unsigned long *bitmap, unsigned int nbits)
    EXPORT_SYMBOL(bitmap_to_arr32);
    #endif

    -#if (BITS_PER_LONG == 32) && defined(__BIG_ENDIAN)
    /**
    - * bitmap_from_arr64 - copy the contents of u64 array of bits to bitmap
    + * __bitmap_from_arr64_type - copy the contents of u64 array of bits to bitmap
    * @bitmap: array of unsigned longs, the destination bitmap
    - * @buf: array of u64 (in host byte order), the source bitmap
    + * @buf: array of u64/__be64/__le64, the source bitmap
    * @nbits: number of bits in @bitmap
    + * @type: type of the array (%BITMAP_ARR_*64)
    */
    -void bitmap_from_arr64(unsigned long *bitmap, const u64 *buf, unsigned int nbits)
    +void __bitmap_from_arr64_type(unsigned long *bitmap, const void *buf,
    + unsigned int nbits, u32 type)
    {
    + const union {
    + __be64 be;
    + __le64 le;
    + u64 u;
    + } *src = buf;
    int n;

    for (n = nbits; n > 0; n -= 64) {
    - u64 val = *buf++;
    + u64 val;
    +
    + switch (type) {
    +#ifdef __LITTLE_ENDIAN
    + case BITMAP_ARR_BE64:
    + val = be64_to_cpu((src++)->be);
    + break;
    +#else
    + case BITMAP_ARR_LE64:
    + val = le64_to_cpu((src++)->le);
    + break;
    +#endif
    + default:
    + val = (src++)->u;
    + break;
    + }

    *bitmap++ = val;
    +#if BITS_PER_LONG == 32
    if (n > 32)
    *bitmap++ = val >> 32;
    +#endif
    }

    /*
    @@ -1542,28 +1565,51 @@ void bitmap_from_arr64(unsigned long *bitmap, const u64 *buf, unsigned int nbits
    if (nbits % BITS_PER_LONG)
    bitmap[-1] &= BITMAP_LAST_WORD_MASK(nbits);
    }
    -EXPORT_SYMBOL(bitmap_from_arr64);
    +EXPORT_SYMBOL(__bitmap_from_arr64_type);

    /**
    - * bitmap_to_arr64 - copy the contents of bitmap to a u64 array of bits
    - * @buf: array of u64 (in host byte order), the dest bitmap
    + * __bitmap_to_arr64_type - copy the contents of bitmap to a u64 array of bits
    + * @buf: array of u64/__be64/__le64, the dest bitmap
    * @bitmap: array of unsigned longs, the source bitmap
    * @nbits: number of bits in @bitmap
    + * @type: type of the array (%BITMAP_ARR_*64)
    */
    -void bitmap_to_arr64(u64 *buf, const unsigned long *bitmap, unsigned int nbits)
    +void __bitmap_to_arr64_type(void *buf, const unsigned long *bitmap,
    + unsigned int nbits, u32 type)
    {
    const unsigned long *end = bitmap + BITS_TO_LONGS(nbits);
    + union {
    + __be64 be;
    + __le64 le;
    + u64 u;
    + } *dst = buf;

    while (bitmap < end) {
    - *buf = *bitmap++;
    + u64 val = *bitmap++;
    +
    +#if BITS_PER_LONG == 32
    if (bitmap < end)
    - *buf |= (u64)(*bitmap++) << 32;
    - buf++;
    - }
    + val |= (u64)(*bitmap++) << 32;
    +#endif

    - /* Clear tail bits in the last element of array beyond nbits. */
    - if (nbits % 64)
    - buf[-1] &= GENMASK_ULL((nbits - 1) % 64, 0);
    -}
    -EXPORT_SYMBOL(bitmap_to_arr64);
    + /* Clear tail bits in the last element of array beyond nbits. */
    + if (bitmap == end && (nbits % 64))
    + val &= GENMASK_ULL((nbits - 1) % 64, 0);
    +
    + switch (type) {
    +#ifdef __LITTLE_ENDIAN
    + case BITMAP_ARR_BE64:
    + (dst++)->be = cpu_to_be64(val);
    + break;
    +#else
    + case BITMAP_ARR_LE64:
    + (dst++)->le = cpu_to_le64(val);
    + break;
    #endif
    + default:
    + (dst++)->u = val;
    + break;
    + }
    + }
    +}
    +EXPORT_SYMBOL(__bitmap_to_arr64_type);
    --
    2.36.1
    \
     
     \ /
      Last update: 2022-07-21 18:03    [W:2.979 / U:0.120 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site