qcacmn: Account for frags attached to chained nbufs in frag_list

Page fragments can be attached to the chained nbufs present in the
frag_list of the parent nbuf. Update the debug entries for such fragments
in different scenarios.

Change-Id: Ib114ec43dcb6cbcd707552bcca19f1ac0d3c2a22
CRs-Fixed: 2791903
This commit is contained in:
Harsh Kumar Bijlani
2020-10-02 11:51:41 +05:30
committed by snandini
parent ef806a62d2
commit e3907fda5d
3 changed files with 184 additions and 33 deletions

View File

@@ -3900,6 +3900,22 @@ void qdf_net_buf_debug_acquire_frag(qdf_nbuf_t buf, const char *func,
void qdf_net_buf_debug_release_frag(qdf_nbuf_t buf, const char *func, void qdf_net_buf_debug_release_frag(qdf_nbuf_t buf, const char *func,
uint32_t line); uint32_t line);
/**
* qdf_nbuf_frag_count_inc() - Increment global frag counter
* @buf: qdf_nbuf_t
*
* Return: none
*/
void qdf_nbuf_frag_count_inc(qdf_nbuf_t buf);
/**
* qdf_nbuf_frag_count_dec() - Decrement global frag counter
* @buf: qdf_nbuf_t
*
* Return: none
*/
void qdf_nbuf_frag_count_dec(qdf_nbuf_t buf);
#else /* NBUF_FRAG_MEMORY_DEBUG */ #else /* NBUF_FRAG_MEMORY_DEBUG */
/** /**
@@ -3954,6 +3970,15 @@ static inline void qdf_net_buf_debug_release_frag(qdf_nbuf_t buf,
uint32_t line) uint32_t line)
{ {
} }
static inline void qdf_nbuf_frag_count_inc(qdf_nbuf_t buf)
{
}
static inline void qdf_nbuf_frag_count_dec(qdf_nbuf_t buf)
{
}
#endif /* NBUF_FRAG_MEMORY_DEBUG */ #endif /* NBUF_FRAG_MEMORY_DEBUG */
#ifdef MEMORY_DEBUG #ifdef MEMORY_DEBUG

View File

@@ -772,6 +772,20 @@ __qdf_nbuf_alloc(__qdf_device_t osdev, size_t size, int reserve, int align,
__qdf_nbuf_t __qdf_nbuf_alloc_no_recycler(size_t size, int reserve, int align, __qdf_nbuf_t __qdf_nbuf_alloc_no_recycler(size_t size, int reserve, int align,
const char *func, uint32_t line); const char *func, uint32_t line);
/**
* __qdf_nbuf_clone() - clone the nbuf (copy is readonly)
* @skb: Pointer to network buffer
*
* if GFP_ATOMIC is overkill then we can check whether its
* called from interrupt context and then do it or else in
* normal case use GFP_KERNEL
*
* example use "in_irq() || irqs_disabled()"
*
* Return: cloned skb
*/
__qdf_nbuf_t __qdf_nbuf_clone(__qdf_nbuf_t nbuf);
void __qdf_nbuf_free(struct sk_buff *skb); void __qdf_nbuf_free(struct sk_buff *skb);
QDF_STATUS __qdf_nbuf_map(__qdf_device_t osdev, QDF_STATUS __qdf_nbuf_map(__qdf_device_t osdev,
struct sk_buff *skb, qdf_dma_dir_t dir); struct sk_buff *skb, qdf_dma_dir_t dir);
@@ -1039,30 +1053,6 @@ static inline size_t __qdf_nbuf_get_nr_frags(struct sk_buff *skb)
*/ */
#define __qdf_nbuf_pool_delete(osdev) #define __qdf_nbuf_pool_delete(osdev)
/**
* __qdf_nbuf_clone() - clone the nbuf (copy is readonly)
* @skb: Pointer to network buffer
*
* if GFP_ATOMIC is overkill then we can check whether its
* called from interrupt context and then do it or else in
* normal case use GFP_KERNEL
*
* example use "in_irq() || irqs_disabled()"
*
* Return: cloned skb
*/
static inline struct sk_buff *__qdf_nbuf_clone(struct sk_buff *skb)
{
struct sk_buff *skb_new = NULL;
skb_new = skb_clone(skb, GFP_ATOMIC);
if (skb_new) {
__qdf_frag_count_inc(__qdf_nbuf_get_nr_frags(skb_new));
__qdf_nbuf_count_inc(skb_new);
}
return skb_new;
}
/** /**
* __qdf_nbuf_copy() - returns a private copy of the skb * __qdf_nbuf_copy() - returns a private copy of the skb
* @skb: Pointer to network buffer * @skb: Pointer to network buffer
@@ -1078,7 +1068,6 @@ static inline struct sk_buff *__qdf_nbuf_copy(struct sk_buff *skb)
skb_new = skb_copy(skb, GFP_ATOMIC); skb_new = skb_copy(skb, GFP_ATOMIC);
if (skb_new) { if (skb_new) {
__qdf_frag_count_inc(__qdf_nbuf_get_nr_frags(skb_new));
__qdf_nbuf_count_inc(skb_new); __qdf_nbuf_count_inc(skb_new);
} }
return skb_new; return skb_new;

View File

@@ -445,6 +445,64 @@ void __qdf_nbuf_count_dec(__qdf_nbuf_t nbuf)
qdf_export_symbol(__qdf_nbuf_count_dec); qdf_export_symbol(__qdf_nbuf_count_dec);
#endif #endif
#ifdef NBUF_FRAG_MEMORY_DEBUG
void qdf_nbuf_frag_count_inc(qdf_nbuf_t nbuf)
{
qdf_nbuf_t ext_list;
uint32_t num_nr_frags;
uint32_t total_num_nr_frags;
num_nr_frags = qdf_nbuf_get_nr_frags(nbuf);
qdf_assert_always(num_nr_frags <= QDF_NBUF_MAX_FRAGS);
total_num_nr_frags = num_nr_frags;
/* Take into account the frags attached to frag_list */
ext_list = qdf_nbuf_get_ext_list(nbuf);
while (ext_list) {
num_nr_frags = qdf_nbuf_get_nr_frags(ext_list);
qdf_assert_always(num_nr_frags <= QDF_NBUF_MAX_FRAGS);
total_num_nr_frags += num_nr_frags;
ext_list = qdf_nbuf_queue_next(ext_list);
}
qdf_frag_count_inc(total_num_nr_frags);
}
qdf_export_symbol(qdf_nbuf_frag_count_inc);
void qdf_nbuf_frag_count_dec(qdf_nbuf_t nbuf)
{
qdf_nbuf_t ext_list;
uint32_t num_nr_frags;
uint32_t total_num_nr_frags;
if (qdf_nbuf_get_users(nbuf) > 1)
return;
num_nr_frags = qdf_nbuf_get_nr_frags(nbuf);
qdf_assert_always(num_nr_frags <= QDF_NBUF_MAX_FRAGS);
total_num_nr_frags = num_nr_frags;
/* Take into account the frags attached to frag_list */
ext_list = qdf_nbuf_get_ext_list(nbuf);
while (ext_list) {
if (qdf_nbuf_get_users(ext_list) == 1) {
num_nr_frags = qdf_nbuf_get_nr_frags(ext_list);
qdf_assert_always(num_nr_frags <= QDF_NBUF_MAX_FRAGS);
total_num_nr_frags += num_nr_frags;
}
ext_list = qdf_nbuf_queue_next(ext_list);
}
qdf_frag_count_dec(total_num_nr_frags);
}
qdf_export_symbol(qdf_nbuf_frag_count_dec);
#endif
#if defined(CONFIG_WIFI_EMULATION_WIFI_3_0) && defined(BUILD_X86) && \ #if defined(CONFIG_WIFI_EMULATION_WIFI_3_0) && defined(BUILD_X86) && \
!defined(QCA_WIFI_QCN9000) !defined(QCA_WIFI_QCN9000)
struct sk_buff *__qdf_nbuf_alloc(qdf_device_t osdev, size_t size, int reserve, struct sk_buff *__qdf_nbuf_alloc(qdf_device_t osdev, size_t size, int reserve,
@@ -636,13 +694,7 @@ void __qdf_nbuf_free(struct sk_buff *skb)
if (pld_nbuf_pre_alloc_free(skb)) if (pld_nbuf_pre_alloc_free(skb))
return; return;
/** qdf_nbuf_frag_count_dec(skb);
* Decrement global frag counter only when last user of nbuf
* does free so as to avoid decrementing count on every free
* expect the last one in case where nbuf has multiple users
*/
if (qdf_nbuf_get_users(skb) == 1)
qdf_frag_count_dec(qdf_nbuf_get_nr_frags(skb));
qdf_nbuf_count_dec(skb); qdf_nbuf_count_dec(skb);
qdf_mem_skb_dec(skb->truesize); qdf_mem_skb_dec(skb->truesize);
@@ -654,6 +706,20 @@ void __qdf_nbuf_free(struct sk_buff *skb)
qdf_export_symbol(__qdf_nbuf_free); qdf_export_symbol(__qdf_nbuf_free);
__qdf_nbuf_t __qdf_nbuf_clone(__qdf_nbuf_t skb)
{
qdf_nbuf_t skb_new = NULL;
skb_new = skb_clone(skb, GFP_ATOMIC);
if (skb_new) {
qdf_nbuf_frag_count_inc(skb_new);
qdf_nbuf_count_inc(skb_new);
}
return skb_new;
}
qdf_export_symbol(__qdf_nbuf_clone);
#ifdef NBUF_MEMORY_DEBUG #ifdef NBUF_MEMORY_DEBUG
enum qdf_nbuf_event_type { enum qdf_nbuf_event_type {
QDF_NBUF_ALLOC, QDF_NBUF_ALLOC,
@@ -2885,11 +2951,24 @@ void qdf_nbuf_free_debug(qdf_nbuf_t nbuf, const char *func, uint32_t line)
idx++; idx++;
} }
/* Take care to delete the debug entries for frag_list */ /**
* Take care to update the debug entries for frag_list and also
* for the frags attached to frag_list
*/
ext_list = qdf_nbuf_get_ext_list(nbuf); ext_list = qdf_nbuf_get_ext_list(nbuf);
while (ext_list) { while (ext_list) {
if (qdf_nbuf_get_users(ext_list) == 1) { if (qdf_nbuf_get_users(ext_list) == 1) {
qdf_nbuf_panic_on_free_if_mapped(ext_list, func, line); qdf_nbuf_panic_on_free_if_mapped(ext_list, func, line);
idx = 0;
num_nr_frags = qdf_nbuf_get_nr_frags(ext_list);
qdf_assert_always(num_nr_frags <= QDF_NBUF_MAX_FRAGS);
while (idx < num_nr_frags) {
p_frag = qdf_nbuf_get_frag_addr(ext_list, idx);
if (qdf_likely(p_frag))
qdf_frag_debug_refcount_dec(p_frag,
func, line);
idx++;
}
qdf_net_buf_debug_delete_node(ext_list); qdf_net_buf_debug_delete_node(ext_list);
} }
@@ -2905,6 +2984,7 @@ qdf_nbuf_t qdf_nbuf_clone_debug(qdf_nbuf_t buf, const char *func, uint32_t line)
{ {
uint32_t num_nr_frags; uint32_t num_nr_frags;
uint32_t idx = 0; uint32_t idx = 0;
qdf_nbuf_t ext_list;
qdf_frag_t p_frag; qdf_frag_t p_frag;
qdf_nbuf_t cloned_buf = __qdf_nbuf_clone(buf); qdf_nbuf_t cloned_buf = __qdf_nbuf_clone(buf);
@@ -2927,6 +3007,23 @@ qdf_nbuf_t qdf_nbuf_clone_debug(qdf_nbuf_t buf, const char *func, uint32_t line)
idx++; idx++;
} }
/* Take care to update debug entries for frags attached to frag_list */
ext_list = qdf_nbuf_get_ext_list(cloned_buf);
while (ext_list) {
idx = 0;
num_nr_frags = qdf_nbuf_get_nr_frags(ext_list);
qdf_assert_always(num_nr_frags <= QDF_NBUF_MAX_FRAGS);
while (idx < num_nr_frags) {
p_frag = qdf_nbuf_get_frag_addr(ext_list, idx);
if (qdf_likely(p_frag))
qdf_frag_debug_refcount_inc(p_frag, func, line);
idx++;
}
ext_list = qdf_nbuf_queue_next(ext_list);
}
/* Store SKB in internal QDF tracking table */ /* Store SKB in internal QDF tracking table */
qdf_net_buf_debug_add_node(cloned_buf, 0, func, line); qdf_net_buf_debug_add_node(cloned_buf, 0, func, line);
qdf_nbuf_history_add(cloned_buf, func, line, QDF_NBUF_ALLOC_CLONE); qdf_nbuf_history_add(cloned_buf, func, line, QDF_NBUF_ALLOC_CLONE);
@@ -4878,6 +4975,7 @@ void qdf_net_buf_debug_acquire_frag(qdf_nbuf_t buf, const char *func,
{ {
uint32_t num_nr_frags; uint32_t num_nr_frags;
uint32_t idx = 0; uint32_t idx = 0;
qdf_nbuf_t ext_list;
qdf_frag_t p_frag; qdf_frag_t p_frag;
if (qdf_unlikely(!buf)) if (qdf_unlikely(!buf))
@@ -4894,6 +4992,26 @@ void qdf_net_buf_debug_acquire_frag(qdf_nbuf_t buf, const char *func,
qdf_frag_debug_refcount_inc(p_frag, func, line); qdf_frag_debug_refcount_inc(p_frag, func, line);
idx++; idx++;
} }
/**
* Take care to update the refcount in the debug entries for the
* frags attached to frag_list
*/
ext_list = qdf_nbuf_get_ext_list(buf);
while (ext_list) {
idx = 0;
num_nr_frags = qdf_nbuf_get_nr_frags(ext_list);
qdf_assert_always(num_nr_frags <= QDF_NBUF_MAX_FRAGS);
while (idx < num_nr_frags) {
p_frag = qdf_nbuf_get_frag_addr(ext_list, idx);
if (qdf_likely(p_frag))
qdf_frag_debug_refcount_inc(p_frag, func, line);
idx++;
}
ext_list = qdf_nbuf_queue_next(ext_list);
}
} }
qdf_export_symbol(qdf_net_buf_debug_acquire_frag); qdf_export_symbol(qdf_net_buf_debug_acquire_frag);
@@ -4902,6 +5020,7 @@ void qdf_net_buf_debug_release_frag(qdf_nbuf_t buf, const char *func,
uint32_t line) uint32_t line)
{ {
uint32_t num_nr_frags; uint32_t num_nr_frags;
qdf_nbuf_t ext_list;
uint32_t idx = 0; uint32_t idx = 0;
qdf_frag_t p_frag; qdf_frag_t p_frag;
@@ -4928,6 +5047,24 @@ void qdf_net_buf_debug_release_frag(qdf_nbuf_t buf, const char *func,
qdf_frag_debug_refcount_dec(p_frag, func, line); qdf_frag_debug_refcount_dec(p_frag, func, line);
idx++; idx++;
} }
/* Take care to update debug entries for frags attached to frag_list */
ext_list = qdf_nbuf_get_ext_list(buf);
while (ext_list) {
if (qdf_nbuf_get_users(ext_list) == 1) {
idx = 0;
num_nr_frags = qdf_nbuf_get_nr_frags(ext_list);
qdf_assert_always(num_nr_frags <= QDF_NBUF_MAX_FRAGS);
while (idx < num_nr_frags) {
p_frag = qdf_nbuf_get_frag_addr(ext_list, idx);
if (qdf_likely(p_frag))
qdf_frag_debug_refcount_dec(p_frag,
func, line);
idx++;
}
}
ext_list = qdf_nbuf_queue_next(ext_list);
}
} }
qdf_export_symbol(qdf_net_buf_debug_release_frag); qdf_export_symbol(qdf_net_buf_debug_release_frag);