+/**
+ * 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.
+ */
+static inline int
+segment_manager_add_segment_inline (segment_manager_t *sm, uword segment_size,
+ u8 notify_app, u8 flags, u8 need_lock)
+{
+ segment_manager_main_t *smm = &sm_main;
+ segment_manager_props_t *props;
+ app_worker_t *app_wrk;
+ fifo_segment_t *fs;
+ u32 fs_index = ~0;
+ u8 *seg_name;
+ int rv;
+
+ props = segment_manager_properties_get (sm);
+ app_wrk = app_worker_get (sm->app_wrk_index);
+
+ /* 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 (need_lock)
+ 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;
+ /* add overhead to ensure the result segment size is at least
+ * of that requested */
+ segment_size +=
+ sizeof (fifo_segment_header_t) +
+ vlib_thread_main.n_vlib_mains * sizeof (fifo_segment_slice_t) +
+ FIFO_SEGMENT_ALLOC_OVERHEAD;
+
+ if (props->huge_page)
+ {
+ uword hugepage_size = clib_mem_get_default_hugepage_size ();
+ segment_size = round_pow2 (segment_size, hugepage_size);
+ fs->ssvm.huge_page = 1;
+ }
+ else
+ segment_size = round_pow2 (segment_size, clib_mem_get_page_size ());
+
+ seg_name = format (0, "seg-%u-%u-%u%c", app_wrk->app_index,
+ app_wrk->wrk_index, smm->seg_name_counter++, 0);
+
+ fs->ssvm.ssvm_size = segment_size;
+ fs->ssvm.name = seg_name;
+ fs->ssvm.requested_va = 0;
+
+ if ((rv = ssvm_server_init (&fs->ssvm, props->segment_type)))
+ {
+ clib_warning ("svm_master_init ('%v', %u) failed", seg_name,
+ segment_size);
+ 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;
+ fs->fs_index = fs_index;
+ fs->sm_index = segment_manager_index (sm);
+
+ /*
+ * Set watermarks in segment
+ */
+ fs->high_watermark = sm->high_watermark;
+ fs->low_watermark = sm->low_watermark;
+ fs->flags = flags;
+ fs->flags &= ~FIFO_SEGMENT_F_MEM_LIMIT;
+ fs->h->pct_first_alloc = props->pct_first_alloc;
+
+ if (notify_app)
+ {
+ app_worker_t *app_wrk;
+ u64 fs_handle;
+ fs_handle = segment_manager_segment_handle (sm, fs);
+ app_wrk = app_worker_get (sm->app_wrk_index);
+ rv = app_worker_add_segment_notify (app_wrk, fs_handle);
+ if (rv)
+ {
+ fs_index = rv;
+ goto done;
+ }
+ }
+done:
+
+ if (need_lock)
+ clib_rwlock_writer_unlock (&sm->segments_rwlock);
+
+ return fs_index;
+}
+
+int
+segment_manager_add_segment (segment_manager_t *sm, uword segment_size,
+ u8 notify_app)
+{
+ return segment_manager_add_segment_inline (sm, segment_size, notify_app,
+ 0 /* flags */, 0 /* need_lock */);
+}
+
+int
+segment_manager_add_segment2 (segment_manager_t *sm, uword segment_size,
+ u8 flags)
+{
+ return segment_manager_add_segment_inline (sm, segment_size, 0, flags,
+ vlib_num_workers ());
+}
+