+/**
+ * Adds segment to segment manager's pool
+ *
+ * If needed a writer's lock is acquired before allocating a new segment
+ * to avoid affecting any of the segments pool readers.
+ */
+int
+segment_manager_add_segment (segment_manager_t * sm, uword segment_size)
+{
+ uword baseva = (uword) ~ 0ULL, alloc_size, page_size;
+ u32 rnd_margin = 128 << 10, fs_index = ~0;
+ segment_manager_main_t *smm = &sm_main;
+ segment_manager_props_t *props;
+ fifo_segment_t *fs;
+ u8 *seg_name;
+ int rv;
+
+ props = segment_manager_properties_get (sm);
+
+ /* Not configured for addition of new segments and not first */
+ if (!props->add_segment && !segment_size)
+ {
+ clib_warning ("cannot allocate new segment");
+ return VNET_API_ERROR_INVALID_VALUE;
+ }
+
+ /*
+ * Allocate fifo segment and grab lock if needed
+ */
+ if (vlib_num_workers ())
+ clib_rwlock_writer_lock (&sm->segments_rwlock);
+
+ pool_get_zero (sm->segments, fs);
+
+ /*
+ * Allocate ssvm segment
+ */
+ segment_size = segment_size ? segment_size : props->add_segment_size;
+ page_size = clib_mem_get_page_size ();
+ /* Protect against segment size u32 wrap */
+ segment_size = clib_max (segment_size + page_size - 1, segment_size);
+ segment_size = segment_size & ~(page_size - 1);
+
+ if (props->segment_type != SSVM_SEGMENT_PRIVATE)
+ {
+ seg_name = format (0, "%d-%d%c", getpid (), smm->seg_name_counter++, 0);
+ alloc_size = (uword) segment_size + rnd_margin;
+ baseva = clib_valloc_alloc (&smm->va_allocator, alloc_size, 0);
+ if (!baseva)
+ {
+ clib_warning ("out of space for segments");
+ pool_put (sm->segments, fs);
+ goto done;
+ }
+ }
+ else
+ seg_name = format (0, "%s%c", "process-private", 0);
+
+ fs->ssvm.ssvm_size = segment_size;
+ fs->ssvm.name = seg_name;
+ fs->ssvm.requested_va = baseva;
+
+ if ((rv = ssvm_master_init (&fs->ssvm, props->segment_type)))
+ {
+ clib_warning ("svm_master_init ('%v', %u) failed", seg_name,
+ segment_size);
+
+ if (props->segment_type != SSVM_SEGMENT_PRIVATE)
+ clib_valloc_free (&smm->va_allocator, baseva);
+ pool_put (sm->segments, fs);
+ goto done;
+ }
+
+ /*
+ * Initialize fifo segment
+ */
+ fs->n_slices = props->n_slices;
+ fifo_segment_init (fs);
+
+ /*
+ * Save segment index before dropping lock, if any held
+ */
+ fs_index = fs - sm->segments;
+
+ /*
+ * Set watermarks in segment
+ */
+ fs->h->high_watermark = sm->high_watermark;
+ fs->h->low_watermark = sm->low_watermark;
+ fs->h->pct_first_alloc = props->pct_first_alloc;
+ fs->h->flags &= ~FIFO_SEGMENT_F_MEM_LIMIT;
+
+done:
+
+ if (vlib_num_workers ())
+ clib_rwlock_writer_unlock (&sm->segments_rwlock);
+
+ return fs_index;
+}
+