numam-dpdk/lib/librte_kni/rte_kni_fifo.h
Yangchao Zhou 5eb1708ec1 kni: fix kernel crash with multi-segments
va2pa depends on the physical address and virtual address offset of
current mbuf. It may get the wrong physical address of next mbuf which
allocated in another hugepage segment.

In rte_mempool_populate_default(), trying to allocate whole block of
contiguous memory could be failed. Then, it would reserve memory in
several memzones that have different physical address and virtual address
offsets. The rte_mempool_populate_default() is used by
rte_pktmbuf_pool_create().

Fixes: 8451269e6d ("kni: remove continuous memory restriction")
Cc: stable@dpdk.org

Signed-off-by: Yangchao Zhou <zhouyates@gmail.com>
Acked-by: Ferruh Yigit <ferruh.yigit@intel.com>
2019-07-15 22:48:20 +02:00

118 lines
3.0 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2014 Intel Corporation
*/
/**
* @internal when c11 memory model enabled use c11 atomic memory barrier.
* when under non c11 memory model use rte_smp_* memory barrier.
*
* @param src
* Pointer to the source data.
* @param dst
* Pointer to the destination data.
* @param value
* Data value.
*/
#ifdef RTE_USE_C11_MEM_MODEL
#define __KNI_LOAD_ACQUIRE(src) ({ \
__atomic_load_n((src), __ATOMIC_ACQUIRE); \
})
#define __KNI_STORE_RELEASE(dst, value) do { \
__atomic_store_n((dst), value, __ATOMIC_RELEASE); \
} while(0)
#else
#define __KNI_LOAD_ACQUIRE(src) ({ \
typeof (*(src)) val = *(src); \
rte_smp_rmb(); \
val; \
})
#define __KNI_STORE_RELEASE(dst, value) do { \
*(dst) = value; \
rte_smp_wmb(); \
} while(0)
#endif
/**
* Initializes the kni fifo structure
*/
static void
kni_fifo_init(struct rte_kni_fifo *fifo, unsigned size)
{
/* Ensure size is power of 2 */
if (size & (size - 1))
rte_panic("KNI fifo size must be power of 2\n");
fifo->write = 0;
fifo->read = 0;
fifo->len = size;
fifo->elem_size = sizeof(void *);
}
/**
* Adds num elements into the fifo. Return the number actually written
*/
static inline unsigned
kni_fifo_put(struct rte_kni_fifo *fifo, void **data, unsigned num)
{
unsigned i = 0;
unsigned fifo_write = fifo->write;
unsigned new_write = fifo_write;
unsigned fifo_read = __KNI_LOAD_ACQUIRE(&fifo->read);
for (i = 0; i < num; i++) {
new_write = (new_write + 1) & (fifo->len - 1);
if (new_write == fifo_read)
break;
fifo->buffer[fifo_write] = data[i];
fifo_write = new_write;
}
__KNI_STORE_RELEASE(&fifo->write, fifo_write);
return i;
}
/**
* Get up to num elements from the fifo. Return the number actually read
*/
static inline unsigned
kni_fifo_get(struct rte_kni_fifo *fifo, void **data, unsigned num)
{
unsigned i = 0;
unsigned new_read = fifo->read;
unsigned fifo_write = __KNI_LOAD_ACQUIRE(&fifo->write);
for (i = 0; i < num; i++) {
if (new_read == fifo_write)
break;
data[i] = fifo->buffer[new_read];
new_read = (new_read + 1) & (fifo->len - 1);
}
__KNI_STORE_RELEASE(&fifo->read, new_read);
return i;
}
/**
* Get the num of elements in the fifo
*/
static inline uint32_t
kni_fifo_count(struct rte_kni_fifo *fifo)
{
unsigned fifo_write = __KNI_LOAD_ACQUIRE(&fifo->write);
unsigned fifo_read = __KNI_LOAD_ACQUIRE(&fifo->read);
return (fifo->len + fifo_write - fifo_read) & (fifo->len - 1);
}
/**
* Get the num of available elements in the fifo
*/
static inline uint32_t
kni_fifo_free_count(struct rte_kni_fifo *fifo)
{
uint32_t fifo_write = __KNI_LOAD_ACQUIRE(&fifo->write);
uint32_t fifo_read = __KNI_LOAD_ACQUIRE(&fifo->read);
return (fifo_read - fifo_write - 1) & (fifo->len - 1);
}