svm: check if fifo free list index is valid on alloc
[vpp.git] / src / svm / fifo_segment.c
index eb240b0..06b7f06 100644 (file)
@@ -615,6 +615,9 @@ fs_try_alloc_fifo (fifo_segment_header_t * fsh, fifo_segment_slice_t * fss,
   min_size = clib_max ((fsh->pct_first_alloc * data_bytes) / 100, 4096);
   fl_index = fs_freelist_for_size (min_size);
 
+  if (fl_index >= vec_len (fss->free_chunks))
+    return 0;
+
   clib_spinlock_lock (&fss->chunk_lock);
 
   if (fss->free_fifos && fss->free_chunks[fl_index])
@@ -657,7 +660,7 @@ fs_try_alloc_fifo (fifo_segment_header_t * fsh, fifo_segment_slice_t * fss,
       ssvm_pop_heap (oldheap);
       if (f)
        {
-         fss->num_chunks[fl_index] += 1;
+         clib_atomic_fetch_add_rel (&fss->num_chunks[fl_index], 1);
          fsh_free_bytes_sub (fsh, fifo_sz);
          goto done;
        }
@@ -691,6 +694,7 @@ fsh_alloc_chunk (fifo_segment_header_t * fsh, u32 slice_index, u32 chunk_size)
 
   clib_spinlock_lock (&fss->chunk_lock);
 
+  ASSERT (vec_len (fss->free_chunks) > fl_index);
   c = fss->free_chunks[fl_index];
 
   if (c)
@@ -717,7 +721,7 @@ fsh_alloc_chunk (fifo_segment_header_t * fsh, u32 slice_index, u32 chunk_size)
 
          if (c)
            {
-             fss->num_chunks[fl_index] += 1;
+             clib_atomic_fetch_add_rel (&fss->num_chunks[fl_index], 1);
              fsh_free_bytes_sub (fsh, chunk_size + sizeof (*c));
              goto done;
            }
@@ -796,6 +800,31 @@ fsh_collect_chunks (fifo_segment_header_t * fsh, u32 slice_index,
   fsh_slice_collect_chunks (fsh, fss, c);
 }
 
+static inline void
+fss_fifo_add_active_list (fifo_segment_slice_t * fss, svm_fifo_t * f)
+{
+  if (fss->fifos)
+    {
+      fss->fifos->prev = f;
+      f->next = fss->fifos;
+    }
+  fss->fifos = f;
+}
+
+static inline void
+fss_fifo_del_active_list (fifo_segment_slice_t * fss, svm_fifo_t * f)
+{
+  if (f->flags & SVM_FIFO_F_LL_TRACKED)
+    {
+      if (f->prev)
+       f->prev->next = f->next;
+      else
+       fss->fifos = f->next;
+      if (f->next)
+       f->next->prev = f->prev;
+    }
+}
+
 /**
  * Allocate fifo in fifo segment
  */
@@ -809,6 +838,9 @@ fifo_segment_alloc_fifo_w_slice (fifo_segment_t * fs, u32 slice_index,
 
   ASSERT (slice_index < fs->n_slices);
 
+  if (PREDICT_FALSE (data_bytes > 1 << fsh->max_log2_chunk_size))
+    return 0;
+
   fss = fsh_slice_get (fsh, slice_index);
   f = fs_try_alloc_fifo (fsh, fss, data_bytes);
   if (!f)
@@ -824,12 +856,7 @@ fifo_segment_alloc_fifo_w_slice (fifo_segment_t * fs, u32 slice_index,
    * only one. */
   if (ftype == FIFO_SEGMENT_RX_FIFO)
     {
-      if (fss->fifos)
-       {
-         fss->fifos->prev = f;
-         f->next = fss->fifos;
-       }
-      fss->fifos = f;
+      fss_fifo_add_active_list (fss, f);
       f->flags |= SVM_FIFO_F_LL_TRACKED;
 
       svm_fifo_init_ooo_lookup (f, 0 /* ooo enq */ );
@@ -865,12 +892,7 @@ fifo_segment_free_fifo (fifo_segment_t * fs, svm_fifo_t * f)
   /* Remove from active list. Only rx fifos are tracked */
   if (f->flags & SVM_FIFO_F_LL_TRACKED)
     {
-      if (f->prev)
-       f->prev->next = f->next;
-      else
-       fss->fifos = f->next;
-      if (f->next)
-       f->next->prev = f->prev;
+      fss_fifo_del_active_list (fss, f);
       f->flags &= ~SVM_FIFO_F_LL_TRACKED;
     }
 
@@ -900,6 +922,52 @@ fifo_segment_free_fifo (fifo_segment_t * fs, svm_fifo_t * f)
   fsh_active_fifos_update (fsh, -1);
 }
 
+void
+fifo_segment_detach_fifo (fifo_segment_t * fs, svm_fifo_t * f)
+{
+  fifo_segment_slice_t *fss;
+  svm_fifo_chunk_t *c;
+  u32 fl_index;
+
+  ASSERT (f->refcnt == 1);
+
+  fss = fsh_slice_get (fs->h, f->slice_index);
+  fss->virtual_mem -= svm_fifo_size (f);
+  if (f->flags & SVM_FIFO_F_LL_TRACKED)
+    fss_fifo_del_active_list (fss, f);
+
+  c = f->start_chunk;
+  while (c)
+    {
+      fl_index = fs_freelist_for_size (c->length);
+      clib_atomic_fetch_sub_rel (&fss->num_chunks[fl_index], 1);
+      c = c->next;
+    }
+}
+
+void
+fifo_segment_attach_fifo (fifo_segment_t * fs, svm_fifo_t * f,
+                         u32 slice_index)
+{
+  fifo_segment_slice_t *fss;
+  svm_fifo_chunk_t *c;
+  u32 fl_index;
+
+  f->slice_index = slice_index;
+  fss = fsh_slice_get (fs->h, f->slice_index);
+  fss->virtual_mem += svm_fifo_size (f);
+  if (f->flags & SVM_FIFO_F_LL_TRACKED)
+    fss_fifo_add_active_list (fss, f);
+
+  c = f->start_chunk;
+  while (c)
+    {
+      fl_index = fs_freelist_for_size (c->length);
+      clib_atomic_fetch_add_rel (&fss->num_chunks[fl_index], 1);
+      c = c->next;
+    }
+}
+
 int
 fifo_segment_prealloc_fifo_hdrs (fifo_segment_t * fs, u32 slice_index,
                                 u32 batch_size)