Signed-off-by: Bill Fischofer <bill.fischo...@linaro.org>
---
 platform/linux-generic/odp_packet.c | 96 +++++++++++++++++++++++++++++--------
 1 file changed, 77 insertions(+), 19 deletions(-)

diff --git a/platform/linux-generic/odp_packet.c 
b/platform/linux-generic/odp_packet.c
index 9ddc8522..403b21f1 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -1053,6 +1053,13 @@ int odp_packet_extend_head(odp_packet_t *pkt, uint32_t 
len,
                segs = pkt_hdr->buf_hdr.segcount;
 
                if (odp_unlikely((segs + num) > CONFIG_PACKET_MAX_SEGS)) {
+                       /* Corner case: fail request if packet has
+                        * references since we cannot shuffle segments
+                        * since another thread may be accessing them
+                        * concurrently */
+                       if (packet_ref_count(pkt_hdr) > 1)
+                               return -1;
+
                        /* Cannot directly add new segments */
                        odp_packet_hdr_t *new_hdr;
                        int new_segs = 0;
@@ -1130,11 +1137,16 @@ int odp_packet_extend_head(odp_packet_t *pkt, uint32_t 
len,
                push_head(pkt_hdr, len);
        }
 
-       if (data_ptr)
-               *data_ptr = packet_data(pkt_hdr);
+       if (data_ptr || seg_len) {
+               uint32_t seg_ln = 0;
+               void *data = packet_map(pkt_hdr, 0, &seg_ln, NULL);
 
-       if (seg_len)
-               *seg_len = packet_first_seg_len(pkt_hdr);
+               if (data_ptr)
+                       *data_ptr = data;
+
+               if (seg_len)
+                       *seg_len = seg_ln;
+       }
 
        return ret;
 }
@@ -1155,15 +1167,35 @@ void *odp_packet_pull_head(odp_packet_t pkt, uint32_t 
len)
 int odp_packet_trunc_head(odp_packet_t *pkt, uint32_t len,
                          void **data_ptr, uint32_t *seg_len_out)
 {
-       odp_packet_hdr_t *pkt_hdr = packet_hdr(*pkt);
+       odp_packet_hdr_t *pkt_hdr = packet_hdr(*pkt), *nxt_hdr;
        uint32_t seg_len = packet_first_seg_len(pkt_hdr);
+       int ret = 0;
 
-       if (len > pkt_hdr->frame_len)
+       if (len > packet_len(pkt_hdr))
                return -1;
 
-       if (len < seg_len) {
+       ODP_ASSERT(len <= odp_packet_unshared_len(*pkt));
+
+       /* Special processing for references */
+       while (len >= pkt_hdr->frame_len && pkt_hdr->ref_hdr) {
+               ODP_ASSERT(packet_ref_count(pkt_hdr) == 1);
+               nxt_hdr = pkt_hdr->ref_hdr;
+               len -= pkt_hdr->frame_len;
+               len += pkt_hdr->ref_offset +
+                       (nxt_hdr->frame_len - pkt_hdr->ref_len);
+               pkt_hdr->ref_hdr = NULL;
+               packet_free(pkt_hdr);
+               pkt_hdr = nxt_hdr;
+               seg_len = packet_first_seg_len(pkt_hdr);
+               *pkt = packet_handle(pkt_hdr);
+               ret = 1;
+       }
+
+       if (CONFIG_PACKET_MAX_SEGS == 1 ||
+           len < seg_len ||
+           pkt_hdr->buf_hdr.segcount == 1) {
                pull_head(pkt_hdr, len);
-       } else if (CONFIG_PACKET_MAX_SEGS != 1) {
+       } else {
                int num = 0;
                uint32_t pull_len = 0;
 
@@ -1178,23 +1210,29 @@ int odp_packet_trunc_head(odp_packet_t *pkt, uint32_t 
len,
                *pkt    = packet_handle(pkt_hdr);
        }
 
-       if (data_ptr)
-               *data_ptr = packet_data(pkt_hdr);
+       if (data_ptr || seg_len_out) {
+               void *data_head = packet_map(pkt_hdr, 0, &seg_len, NULL);
 
-       if (seg_len_out)
-               *seg_len_out = packet_first_seg_len(pkt_hdr);
+               if (data_ptr)
+                       *data_ptr = data_head;
 
-       return 0;
+               if (seg_len_out)
+                       *seg_len_out = seg_len;
+       }
+
+       return ret;
 }
 
 void *odp_packet_push_tail(odp_packet_t pkt, uint32_t len)
 {
-       odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt);
+       odp_packet_hdr_t *pkt_hdr = packet_last_hdr(pkt, NULL);
        void *old_tail;
 
        if (len > pkt_hdr->tailroom)
                return NULL;
 
+       ODP_ASSERT(packet_ref_count(pkt_hdr) == 1);
+
        old_tail = packet_tail(pkt_hdr);
        push_tail(pkt_hdr, len);
 
@@ -1204,12 +1242,14 @@ void *odp_packet_push_tail(odp_packet_t pkt, uint32_t 
len)
 int odp_packet_extend_tail(odp_packet_t *pkt, uint32_t len,
                           void **data_ptr, uint32_t *seg_len_out)
 {
-       odp_packet_hdr_t *pkt_hdr = packet_hdr(*pkt);
+       odp_packet_hdr_t *pkt_hdr = packet_last_hdr(*pkt, NULL);
        uint32_t frame_len = pkt_hdr->frame_len;
        uint32_t tailroom  = pkt_hdr->tailroom;
        uint32_t tail_off  = frame_len;
        int ret = 0;
 
+       ODP_ASSERT(packet_ref_count(pkt_hdr) == 1);
+
        if (len > tailroom) {
                pool_t *pool = pool_entry_from_hdl(pkt_hdr->buf_hdr.pool_hdl);
                int num;
@@ -1300,6 +1340,7 @@ void *odp_packet_pull_tail(odp_packet_t pkt, uint32_t len)
        if (len > packet_last_seg_len(pkt_hdr))
                return NULL;
 
+       ODP_ASSERT(packet_ref_count(pkt_hdr) == 1);
        pull_tail(pkt_hdr, len);
 
        return packet_tail(pkt_hdr);
@@ -1310,17 +1351,34 @@ int odp_packet_trunc_tail(odp_packet_t *pkt, uint32_t 
len,
 {
        int last;
        uint32_t seg_len;
-       odp_packet_hdr_t *pkt_hdr = packet_hdr(*pkt);
+       uint32_t offset;
+       odp_packet_hdr_t *first_hdr = packet_hdr(*pkt);
+       odp_packet_hdr_t *pkt_hdr, *prev_hdr;
 
-       if (len > pkt_hdr->frame_len)
+       if (len > packet_len(first_hdr))
                return -1;
 
+       pkt_hdr = packet_last_hdr(*pkt, &offset);
+
+       /* Special processing for references */
+       while (len >= pkt_hdr->frame_len - offset && first_hdr->ref_hdr) {
+               len -= (pkt_hdr->frame_len - offset);
+               prev_hdr = packet_prev_hdr(first_hdr, pkt_hdr, &offset);
+               ODP_ASSERT(packet_ref_count(prev_hdr) == 1);
+               prev_hdr->ref_hdr = NULL;
+               packet_free(pkt_hdr);
+               pkt_hdr = prev_hdr;
+       }
+
+       ODP_ASSERT(packet_ref_count(pkt_hdr) == 1);
        last    = packet_last_seg(pkt_hdr);
        seg_len = packet_seg_len(pkt_hdr, last);
 
-       if (len < seg_len) {
+       if (CONFIG_PACKET_MAX_SEGS == 1 ||
+           len < seg_len ||
+           pkt_hdr->buf_hdr.segcount == 1) {
                pull_tail(pkt_hdr, len);
-       } else if (CONFIG_PACKET_MAX_SEGS != 1) {
+       } else {
                int num = 0;
                uint32_t pull_len = 0;
 
-- 
2.12.0.rc1

Reply via email to