199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2018 Intel Corporation 399a2dd95SBruce Richardson */ 499a2dd95SBruce Richardson 572b452c5SDmitry Kozlyuk #include <stdlib.h> 699a2dd95SBruce Richardson #include <string.h> 72744cb6eSThomas Monjalon #include <pthread.h> 899a2dd95SBruce Richardson #include <sys/time.h> 999a2dd95SBruce Richardson 1099a2dd95SBruce Richardson #include <rte_errno.h> 1199a2dd95SBruce Richardson #include <rte_string_fns.h> 1299a2dd95SBruce Richardson 1399a2dd95SBruce Richardson #include "eal_memalloc.h" 1499a2dd95SBruce Richardson #include "eal_memcfg.h" 1599a2dd95SBruce Richardson #include "eal_private.h" 1699a2dd95SBruce Richardson 1799a2dd95SBruce Richardson #include "malloc_elem.h" 1899a2dd95SBruce Richardson #include "malloc_mp.h" 1999a2dd95SBruce Richardson 2099a2dd95SBruce Richardson #define MP_ACTION_SYNC "mp_malloc_sync" 2199a2dd95SBruce Richardson /**< request sent by primary process to notify of changes in memory map */ 2299a2dd95SBruce Richardson #define MP_ACTION_ROLLBACK "mp_malloc_rollback" 2399a2dd95SBruce Richardson /**< request sent by primary process to notify of changes in memory map. this is 2499a2dd95SBruce Richardson * essentially a regular sync request, but we cannot send sync requests while 2599a2dd95SBruce Richardson * another one is in progress, and we might have to - therefore, we do this as 2699a2dd95SBruce Richardson * a separate callback. 2799a2dd95SBruce Richardson */ 2899a2dd95SBruce Richardson #define MP_ACTION_REQUEST "mp_malloc_request" 2999a2dd95SBruce Richardson /**< request sent by secondary process to ask for allocation/deallocation */ 3099a2dd95SBruce Richardson #define MP_ACTION_RESPONSE "mp_malloc_response" 3199a2dd95SBruce Richardson /**< response sent to secondary process to indicate result of request */ 3299a2dd95SBruce Richardson 3399a2dd95SBruce Richardson /* forward declarations */ 3499a2dd95SBruce Richardson static int 3599a2dd95SBruce Richardson handle_sync_response(const struct rte_mp_msg *request, 3699a2dd95SBruce Richardson const struct rte_mp_reply *reply); 3799a2dd95SBruce Richardson static int 3899a2dd95SBruce Richardson handle_rollback_response(const struct rte_mp_msg *request, 3999a2dd95SBruce Richardson const struct rte_mp_reply *reply); 4099a2dd95SBruce Richardson 4199a2dd95SBruce Richardson #define MP_TIMEOUT_S 5 /**< 5 seconds timeouts */ 4299a2dd95SBruce Richardson 4399a2dd95SBruce Richardson /* when we're allocating, we need to store some state to ensure that we can 4499a2dd95SBruce Richardson * roll back later 4599a2dd95SBruce Richardson */ 4699a2dd95SBruce Richardson struct primary_alloc_req_state { 4799a2dd95SBruce Richardson struct malloc_heap *heap; 4899a2dd95SBruce Richardson struct rte_memseg **ms; 4999a2dd95SBruce Richardson int ms_len; 5099a2dd95SBruce Richardson struct malloc_elem *elem; 5199a2dd95SBruce Richardson void *map_addr; 5299a2dd95SBruce Richardson size_t map_len; 5399a2dd95SBruce Richardson }; 5499a2dd95SBruce Richardson 5599a2dd95SBruce Richardson enum req_state { 5699a2dd95SBruce Richardson REQ_STATE_INACTIVE = 0, 5799a2dd95SBruce Richardson REQ_STATE_ACTIVE, 5899a2dd95SBruce Richardson REQ_STATE_COMPLETE 5999a2dd95SBruce Richardson }; 6099a2dd95SBruce Richardson 6199a2dd95SBruce Richardson struct mp_request { 6299a2dd95SBruce Richardson TAILQ_ENTRY(mp_request) next; 6399a2dd95SBruce Richardson struct malloc_mp_req user_req; /**< contents of request */ 6499a2dd95SBruce Richardson pthread_cond_t cond; /**< variable we use to time out on this request */ 6599a2dd95SBruce Richardson enum req_state state; /**< indicate status of this request */ 6699a2dd95SBruce Richardson struct primary_alloc_req_state alloc_state; 6799a2dd95SBruce Richardson }; 6899a2dd95SBruce Richardson 6999a2dd95SBruce Richardson /* 7099a2dd95SBruce Richardson * We could've used just a single request, but it may be possible for 7199a2dd95SBruce Richardson * secondaries to timeout earlier than the primary, and send a new request while 7299a2dd95SBruce Richardson * primary is still expecting replies to the old one. Therefore, each new 7399a2dd95SBruce Richardson * request will get assigned a new ID, which is how we will distinguish between 7499a2dd95SBruce Richardson * expected and unexpected messages. 7599a2dd95SBruce Richardson */ 7699a2dd95SBruce Richardson TAILQ_HEAD(mp_request_list, mp_request); 7799a2dd95SBruce Richardson static struct { 7899a2dd95SBruce Richardson struct mp_request_list list; 7999a2dd95SBruce Richardson pthread_mutex_t lock; 8099a2dd95SBruce Richardson } mp_request_list = { 8199a2dd95SBruce Richardson .list = TAILQ_HEAD_INITIALIZER(mp_request_list.list), 8299a2dd95SBruce Richardson .lock = PTHREAD_MUTEX_INITIALIZER 8399a2dd95SBruce Richardson }; 8499a2dd95SBruce Richardson 8599a2dd95SBruce Richardson /** 8699a2dd95SBruce Richardson * General workflow is the following: 8799a2dd95SBruce Richardson * 8899a2dd95SBruce Richardson * Allocation: 8999a2dd95SBruce Richardson * S: send request to primary 9099a2dd95SBruce Richardson * P: attempt to allocate memory 9199a2dd95SBruce Richardson * if failed, sendmsg failure 9299a2dd95SBruce Richardson * if success, send sync request 9399a2dd95SBruce Richardson * S: if received msg of failure, quit 9499a2dd95SBruce Richardson * if received sync request, synchronize memory map and reply with result 9599a2dd95SBruce Richardson * P: if received sync request result 9699a2dd95SBruce Richardson * if success, sendmsg success 9799a2dd95SBruce Richardson * if failure, roll back allocation and send a rollback request 9899a2dd95SBruce Richardson * S: if received msg of success, quit 9999a2dd95SBruce Richardson * if received rollback request, synchronize memory map and reply with result 10099a2dd95SBruce Richardson * P: if received sync request result 10199a2dd95SBruce Richardson * sendmsg sync request result 10299a2dd95SBruce Richardson * S: if received msg, quit 10399a2dd95SBruce Richardson * 10499a2dd95SBruce Richardson * Aside from timeouts, there are three points where we can quit: 10599a2dd95SBruce Richardson * - if allocation failed straight away 10699a2dd95SBruce Richardson * - if allocation and sync request succeeded 10799a2dd95SBruce Richardson * - if allocation succeeded, sync request failed, allocation rolled back and 10899a2dd95SBruce Richardson * rollback request received (irrespective of whether it succeeded or failed) 10999a2dd95SBruce Richardson * 11099a2dd95SBruce Richardson * Deallocation: 11199a2dd95SBruce Richardson * S: send request to primary 11299a2dd95SBruce Richardson * P: attempt to deallocate memory 11399a2dd95SBruce Richardson * if failed, sendmsg failure 11499a2dd95SBruce Richardson * if success, send sync request 11599a2dd95SBruce Richardson * S: if received msg of failure, quit 11699a2dd95SBruce Richardson * if received sync request, synchronize memory map and reply with result 11799a2dd95SBruce Richardson * P: if received sync request result 11899a2dd95SBruce Richardson * sendmsg sync request result 11999a2dd95SBruce Richardson * S: if received msg, quit 12099a2dd95SBruce Richardson * 12199a2dd95SBruce Richardson * There is no "rollback" from deallocation, as it's safe to have some memory 12299a2dd95SBruce Richardson * mapped in some processes - it's absent from the heap, so it won't get used. 12399a2dd95SBruce Richardson */ 12499a2dd95SBruce Richardson 12599a2dd95SBruce Richardson static struct mp_request * 12699a2dd95SBruce Richardson find_request_by_id(uint64_t id) 12799a2dd95SBruce Richardson { 12899a2dd95SBruce Richardson struct mp_request *req; 12999a2dd95SBruce Richardson TAILQ_FOREACH(req, &mp_request_list.list, next) { 13099a2dd95SBruce Richardson if (req->user_req.id == id) 13199a2dd95SBruce Richardson break; 13299a2dd95SBruce Richardson } 13399a2dd95SBruce Richardson return req; 13499a2dd95SBruce Richardson } 13599a2dd95SBruce Richardson 13699a2dd95SBruce Richardson /* this ID is, like, totally guaranteed to be absolutely unique. pinky swear. */ 13799a2dd95SBruce Richardson static uint64_t 13899a2dd95SBruce Richardson get_unique_id(void) 13999a2dd95SBruce Richardson { 14099a2dd95SBruce Richardson uint64_t id; 14199a2dd95SBruce Richardson do { 14299a2dd95SBruce Richardson id = rte_rand(); 14399a2dd95SBruce Richardson } while (find_request_by_id(id) != NULL); 14499a2dd95SBruce Richardson return id; 14599a2dd95SBruce Richardson } 14699a2dd95SBruce Richardson 14799a2dd95SBruce Richardson /* secondary will respond to sync requests thusly */ 14899a2dd95SBruce Richardson static int 14999a2dd95SBruce Richardson handle_sync(const struct rte_mp_msg *msg, const void *peer) 15099a2dd95SBruce Richardson { 15199a2dd95SBruce Richardson struct rte_mp_msg reply; 15299a2dd95SBruce Richardson const struct malloc_mp_req *req = 15399a2dd95SBruce Richardson (const struct malloc_mp_req *)msg->param; 15499a2dd95SBruce Richardson struct malloc_mp_req *resp = 15599a2dd95SBruce Richardson (struct malloc_mp_req *)reply.param; 15699a2dd95SBruce Richardson int ret; 15799a2dd95SBruce Richardson 15899a2dd95SBruce Richardson if (req->t != REQ_TYPE_SYNC) { 159ae67895bSDavid Marchand EAL_LOG(ERR, "Unexpected request from primary"); 16099a2dd95SBruce Richardson return -1; 16199a2dd95SBruce Richardson } 16299a2dd95SBruce Richardson 16399a2dd95SBruce Richardson memset(&reply, 0, sizeof(reply)); 16499a2dd95SBruce Richardson 16599a2dd95SBruce Richardson reply.num_fds = 0; 16699a2dd95SBruce Richardson strlcpy(reply.name, msg->name, sizeof(reply.name)); 16799a2dd95SBruce Richardson reply.len_param = sizeof(*resp); 16899a2dd95SBruce Richardson 16999a2dd95SBruce Richardson ret = eal_memalloc_sync_with_primary(); 17099a2dd95SBruce Richardson 17199a2dd95SBruce Richardson resp->t = REQ_TYPE_SYNC; 17299a2dd95SBruce Richardson resp->id = req->id; 17399a2dd95SBruce Richardson resp->result = ret == 0 ? REQ_RESULT_SUCCESS : REQ_RESULT_FAIL; 17499a2dd95SBruce Richardson 17576b49dcbSChengwen Feng return rte_mp_reply(&reply, peer); 17699a2dd95SBruce Richardson } 17799a2dd95SBruce Richardson 17899a2dd95SBruce Richardson static int 17999a2dd95SBruce Richardson handle_free_request(const struct malloc_mp_req *m) 18099a2dd95SBruce Richardson { 18199a2dd95SBruce Richardson const struct rte_memseg_list *msl; 18299a2dd95SBruce Richardson void *start, *end; 18399a2dd95SBruce Richardson size_t len; 18499a2dd95SBruce Richardson 18599a2dd95SBruce Richardson len = m->free_req.len; 18699a2dd95SBruce Richardson start = m->free_req.addr; 18799a2dd95SBruce Richardson end = RTE_PTR_ADD(start, len - 1); 18899a2dd95SBruce Richardson 18999a2dd95SBruce Richardson /* check if the requested memory actually exists */ 19099a2dd95SBruce Richardson msl = rte_mem_virt2memseg_list(start); 19199a2dd95SBruce Richardson if (msl == NULL) { 192ae67895bSDavid Marchand EAL_LOG(ERR, "Requested to free unknown memory"); 19399a2dd95SBruce Richardson return -1; 19499a2dd95SBruce Richardson } 19599a2dd95SBruce Richardson 19699a2dd95SBruce Richardson /* check if end is within the same memory region */ 19799a2dd95SBruce Richardson if (rte_mem_virt2memseg_list(end) != msl) { 198ae67895bSDavid Marchand EAL_LOG(ERR, "Requested to free memory spanning multiple regions"); 19999a2dd95SBruce Richardson return -1; 20099a2dd95SBruce Richardson } 20199a2dd95SBruce Richardson 20299a2dd95SBruce Richardson /* we're supposed to only free memory that's not external */ 20399a2dd95SBruce Richardson if (msl->external) { 204ae67895bSDavid Marchand EAL_LOG(ERR, "Requested to free external memory"); 20599a2dd95SBruce Richardson return -1; 20699a2dd95SBruce Richardson } 20799a2dd95SBruce Richardson 20899a2dd95SBruce Richardson /* now that we've validated the request, announce it */ 20999a2dd95SBruce Richardson eal_memalloc_mem_event_notify(RTE_MEM_EVENT_FREE, 21099a2dd95SBruce Richardson m->free_req.addr, m->free_req.len); 21199a2dd95SBruce Richardson 21299a2dd95SBruce Richardson /* now, do the actual freeing */ 21399a2dd95SBruce Richardson return malloc_heap_free_pages(m->free_req.addr, m->free_req.len); 21499a2dd95SBruce Richardson } 21599a2dd95SBruce Richardson 21699a2dd95SBruce Richardson static int 21799a2dd95SBruce Richardson handle_alloc_request(const struct malloc_mp_req *m, 21899a2dd95SBruce Richardson struct mp_request *req) 21999a2dd95SBruce Richardson { 22099a2dd95SBruce Richardson struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 22199a2dd95SBruce Richardson const struct malloc_req_alloc *ar = &m->alloc_req; 22299a2dd95SBruce Richardson struct malloc_heap *heap; 22399a2dd95SBruce Richardson struct malloc_elem *elem; 22499a2dd95SBruce Richardson struct rte_memseg **ms; 22599a2dd95SBruce Richardson size_t alloc_sz; 22699a2dd95SBruce Richardson int n_segs; 22799a2dd95SBruce Richardson void *map_addr; 22899a2dd95SBruce Richardson 22999a2dd95SBruce Richardson /* this is checked by the API, but we need to prevent divide by zero */ 23099a2dd95SBruce Richardson if (ar->page_sz == 0 || !rte_is_power_of_2(ar->page_sz)) { 231ae67895bSDavid Marchand EAL_LOG(ERR, "Attempting to allocate with invalid page size"); 23299a2dd95SBruce Richardson return -1; 23399a2dd95SBruce Richardson } 23499a2dd95SBruce Richardson 23599a2dd95SBruce Richardson /* heap idx is index into the heap array, not socket ID */ 23699a2dd95SBruce Richardson if (ar->malloc_heap_idx >= RTE_MAX_HEAPS) { 237ae67895bSDavid Marchand EAL_LOG(ERR, "Attempting to allocate from invalid heap"); 23899a2dd95SBruce Richardson return -1; 23999a2dd95SBruce Richardson } 24099a2dd95SBruce Richardson 24199a2dd95SBruce Richardson heap = &mcfg->malloc_heaps[ar->malloc_heap_idx]; 24299a2dd95SBruce Richardson 24399a2dd95SBruce Richardson /* 24499a2dd95SBruce Richardson * for allocations, we must only use internal heaps, but since the 24599a2dd95SBruce Richardson * rte_malloc_heap_socket_is_external() is thread-safe and we're already 24699a2dd95SBruce Richardson * read-locked, we'll have to take advantage of the fact that internal 24799a2dd95SBruce Richardson * socket ID's are always lower than RTE_MAX_NUMA_NODES. 24899a2dd95SBruce Richardson */ 24999a2dd95SBruce Richardson if (heap->socket_id >= RTE_MAX_NUMA_NODES) { 250ae67895bSDavid Marchand EAL_LOG(ERR, "Attempting to allocate from external heap"); 25199a2dd95SBruce Richardson return -1; 25299a2dd95SBruce Richardson } 25399a2dd95SBruce Richardson 254f92b9ebeSFidaullah Noonari alloc_sz = RTE_ALIGN_CEIL(RTE_ALIGN_CEIL(ar->elt_size, ar->align) + 255ce2f7d47SFidaullah Noonari MALLOC_ELEM_OVERHEAD, ar->page_sz); 25699a2dd95SBruce Richardson n_segs = alloc_sz / ar->page_sz; 25799a2dd95SBruce Richardson 25899a2dd95SBruce Richardson /* we can't know in advance how many pages we'll need, so we malloc */ 25999a2dd95SBruce Richardson ms = malloc(sizeof(*ms) * n_segs); 26099a2dd95SBruce Richardson if (ms == NULL) { 261ae67895bSDavid Marchand EAL_LOG(ERR, "Couldn't allocate memory for request state"); 26299a2dd95SBruce Richardson return -1; 26399a2dd95SBruce Richardson } 26499a2dd95SBruce Richardson memset(ms, 0, sizeof(*ms) * n_segs); 26599a2dd95SBruce Richardson 26699a2dd95SBruce Richardson elem = alloc_pages_on_heap(heap, ar->page_sz, ar->elt_size, ar->socket, 26799a2dd95SBruce Richardson ar->flags, ar->align, ar->bound, ar->contig, ms, 26899a2dd95SBruce Richardson n_segs); 26999a2dd95SBruce Richardson 27099a2dd95SBruce Richardson if (elem == NULL) 27199a2dd95SBruce Richardson goto fail; 27299a2dd95SBruce Richardson 27399a2dd95SBruce Richardson map_addr = ms[0]->addr; 27499a2dd95SBruce Richardson 27599a2dd95SBruce Richardson eal_memalloc_mem_event_notify(RTE_MEM_EVENT_ALLOC, map_addr, alloc_sz); 27699a2dd95SBruce Richardson 27799a2dd95SBruce Richardson /* we have succeeded in allocating memory, but we still need to sync 27899a2dd95SBruce Richardson * with other processes. however, since DPDK IPC is single-threaded, we 27999a2dd95SBruce Richardson * send an asynchronous request and exit this callback. 28099a2dd95SBruce Richardson */ 28199a2dd95SBruce Richardson 28299a2dd95SBruce Richardson req->alloc_state.ms = ms; 28399a2dd95SBruce Richardson req->alloc_state.ms_len = n_segs; 28499a2dd95SBruce Richardson req->alloc_state.map_addr = map_addr; 28599a2dd95SBruce Richardson req->alloc_state.map_len = alloc_sz; 28699a2dd95SBruce Richardson req->alloc_state.elem = elem; 28799a2dd95SBruce Richardson req->alloc_state.heap = heap; 28899a2dd95SBruce Richardson 28999a2dd95SBruce Richardson return 0; 29099a2dd95SBruce Richardson fail: 29199a2dd95SBruce Richardson free(ms); 29299a2dd95SBruce Richardson return -1; 29399a2dd95SBruce Richardson } 29499a2dd95SBruce Richardson 29599a2dd95SBruce Richardson /* first stage of primary handling requests from secondary */ 29699a2dd95SBruce Richardson static int 29799a2dd95SBruce Richardson handle_request(const struct rte_mp_msg *msg, const void *peer __rte_unused) 29899a2dd95SBruce Richardson { 29999a2dd95SBruce Richardson const struct malloc_mp_req *m = 30099a2dd95SBruce Richardson (const struct malloc_mp_req *)msg->param; 30199a2dd95SBruce Richardson struct mp_request *entry; 30299a2dd95SBruce Richardson int ret; 30399a2dd95SBruce Richardson 30499a2dd95SBruce Richardson /* lock access to request */ 30599a2dd95SBruce Richardson pthread_mutex_lock(&mp_request_list.lock); 30699a2dd95SBruce Richardson 30799a2dd95SBruce Richardson /* make sure it's not a dupe */ 30899a2dd95SBruce Richardson entry = find_request_by_id(m->id); 30999a2dd95SBruce Richardson if (entry != NULL) { 310ae67895bSDavid Marchand EAL_LOG(ERR, "Duplicate request id"); 31199a2dd95SBruce Richardson goto fail; 31299a2dd95SBruce Richardson } 31399a2dd95SBruce Richardson 31499a2dd95SBruce Richardson entry = malloc(sizeof(*entry)); 31599a2dd95SBruce Richardson if (entry == NULL) { 316ae67895bSDavid Marchand EAL_LOG(ERR, "Unable to allocate memory for request"); 31799a2dd95SBruce Richardson goto fail; 31899a2dd95SBruce Richardson } 31999a2dd95SBruce Richardson 32099a2dd95SBruce Richardson /* erase all data */ 32199a2dd95SBruce Richardson memset(entry, 0, sizeof(*entry)); 32299a2dd95SBruce Richardson 32399a2dd95SBruce Richardson if (m->t == REQ_TYPE_ALLOC) { 32499a2dd95SBruce Richardson ret = handle_alloc_request(m, entry); 32599a2dd95SBruce Richardson } else if (m->t == REQ_TYPE_FREE) { 32699a2dd95SBruce Richardson ret = handle_free_request(m); 32799a2dd95SBruce Richardson } else { 328ae67895bSDavid Marchand EAL_LOG(ERR, "Unexpected request from secondary"); 32999a2dd95SBruce Richardson goto fail; 33099a2dd95SBruce Richardson } 33199a2dd95SBruce Richardson 33299a2dd95SBruce Richardson if (ret != 0) { 33399a2dd95SBruce Richardson struct rte_mp_msg resp_msg; 33499a2dd95SBruce Richardson struct malloc_mp_req *resp = 33599a2dd95SBruce Richardson (struct malloc_mp_req *)resp_msg.param; 33699a2dd95SBruce Richardson 33799a2dd95SBruce Richardson /* send failure message straight away */ 33899a2dd95SBruce Richardson resp_msg.num_fds = 0; 33999a2dd95SBruce Richardson resp_msg.len_param = sizeof(*resp); 34099a2dd95SBruce Richardson strlcpy(resp_msg.name, MP_ACTION_RESPONSE, 34199a2dd95SBruce Richardson sizeof(resp_msg.name)); 34299a2dd95SBruce Richardson 34399a2dd95SBruce Richardson resp->t = m->t; 34499a2dd95SBruce Richardson resp->result = REQ_RESULT_FAIL; 34599a2dd95SBruce Richardson resp->id = m->id; 34699a2dd95SBruce Richardson 34799a2dd95SBruce Richardson if (rte_mp_sendmsg(&resp_msg)) { 348ae67895bSDavid Marchand EAL_LOG(ERR, "Couldn't send response"); 34999a2dd95SBruce Richardson goto fail; 35099a2dd95SBruce Richardson } 35199a2dd95SBruce Richardson /* we did not modify the request */ 35299a2dd95SBruce Richardson free(entry); 35399a2dd95SBruce Richardson } else { 35499a2dd95SBruce Richardson struct rte_mp_msg sr_msg; 35599a2dd95SBruce Richardson struct malloc_mp_req *sr = 35699a2dd95SBruce Richardson (struct malloc_mp_req *)sr_msg.param; 35799a2dd95SBruce Richardson struct timespec ts; 35899a2dd95SBruce Richardson 35999a2dd95SBruce Richardson memset(&sr_msg, 0, sizeof(sr_msg)); 36099a2dd95SBruce Richardson 36199a2dd95SBruce Richardson /* we can do something, so send sync request asynchronously */ 36299a2dd95SBruce Richardson sr_msg.num_fds = 0; 36399a2dd95SBruce Richardson sr_msg.len_param = sizeof(*sr); 36499a2dd95SBruce Richardson strlcpy(sr_msg.name, MP_ACTION_SYNC, sizeof(sr_msg.name)); 36599a2dd95SBruce Richardson 36699a2dd95SBruce Richardson ts.tv_nsec = 0; 36799a2dd95SBruce Richardson ts.tv_sec = MP_TIMEOUT_S; 36899a2dd95SBruce Richardson 36999a2dd95SBruce Richardson /* sync requests carry no data */ 37099a2dd95SBruce Richardson sr->t = REQ_TYPE_SYNC; 37199a2dd95SBruce Richardson sr->id = m->id; 37299a2dd95SBruce Richardson 37399a2dd95SBruce Richardson /* there may be stray timeout still waiting */ 37499a2dd95SBruce Richardson do { 37599a2dd95SBruce Richardson ret = rte_mp_request_async(&sr_msg, &ts, 37699a2dd95SBruce Richardson handle_sync_response); 37799a2dd95SBruce Richardson } while (ret != 0 && rte_errno == EEXIST); 37899a2dd95SBruce Richardson if (ret != 0) { 379ae67895bSDavid Marchand EAL_LOG(ERR, "Couldn't send sync request"); 38099a2dd95SBruce Richardson if (m->t == REQ_TYPE_ALLOC) 38199a2dd95SBruce Richardson free(entry->alloc_state.ms); 38299a2dd95SBruce Richardson goto fail; 38399a2dd95SBruce Richardson } 38499a2dd95SBruce Richardson 38599a2dd95SBruce Richardson /* mark request as in progress */ 38699a2dd95SBruce Richardson memcpy(&entry->user_req, m, sizeof(*m)); 38799a2dd95SBruce Richardson entry->state = REQ_STATE_ACTIVE; 38899a2dd95SBruce Richardson 38999a2dd95SBruce Richardson TAILQ_INSERT_TAIL(&mp_request_list.list, entry, next); 39099a2dd95SBruce Richardson } 39199a2dd95SBruce Richardson pthread_mutex_unlock(&mp_request_list.lock); 39299a2dd95SBruce Richardson return 0; 39399a2dd95SBruce Richardson fail: 39499a2dd95SBruce Richardson pthread_mutex_unlock(&mp_request_list.lock); 39599a2dd95SBruce Richardson free(entry); 39699a2dd95SBruce Richardson return -1; 39799a2dd95SBruce Richardson } 39899a2dd95SBruce Richardson 39999a2dd95SBruce Richardson /* callback for asynchronous sync requests for primary. this will either do a 40099a2dd95SBruce Richardson * sendmsg with results, or trigger rollback request. 40199a2dd95SBruce Richardson */ 40299a2dd95SBruce Richardson static int 40399a2dd95SBruce Richardson handle_sync_response(const struct rte_mp_msg *request, 40499a2dd95SBruce Richardson const struct rte_mp_reply *reply) 40599a2dd95SBruce Richardson { 40699a2dd95SBruce Richardson enum malloc_req_result result; 40799a2dd95SBruce Richardson struct mp_request *entry; 40899a2dd95SBruce Richardson const struct malloc_mp_req *mpreq = 40999a2dd95SBruce Richardson (const struct malloc_mp_req *)request->param; 41099a2dd95SBruce Richardson int i; 41199a2dd95SBruce Richardson 41299a2dd95SBruce Richardson /* lock the request */ 41399a2dd95SBruce Richardson pthread_mutex_lock(&mp_request_list.lock); 41499a2dd95SBruce Richardson 41599a2dd95SBruce Richardson entry = find_request_by_id(mpreq->id); 41699a2dd95SBruce Richardson if (entry == NULL) { 417ae67895bSDavid Marchand EAL_LOG(ERR, "Wrong request ID"); 41899a2dd95SBruce Richardson goto fail; 41999a2dd95SBruce Richardson } 42099a2dd95SBruce Richardson 42199a2dd95SBruce Richardson result = REQ_RESULT_SUCCESS; 42299a2dd95SBruce Richardson 42399a2dd95SBruce Richardson if (reply->nb_received != reply->nb_sent) 42499a2dd95SBruce Richardson result = REQ_RESULT_FAIL; 42599a2dd95SBruce Richardson 42699a2dd95SBruce Richardson for (i = 0; i < reply->nb_received; i++) { 42799a2dd95SBruce Richardson struct malloc_mp_req *resp = 42899a2dd95SBruce Richardson (struct malloc_mp_req *)reply->msgs[i].param; 42999a2dd95SBruce Richardson 43099a2dd95SBruce Richardson if (resp->t != REQ_TYPE_SYNC) { 431ae67895bSDavid Marchand EAL_LOG(ERR, "Unexpected response to sync request"); 43299a2dd95SBruce Richardson result = REQ_RESULT_FAIL; 43399a2dd95SBruce Richardson break; 43499a2dd95SBruce Richardson } 43599a2dd95SBruce Richardson if (resp->id != entry->user_req.id) { 436ae67895bSDavid Marchand EAL_LOG(ERR, "Response to wrong sync request"); 43799a2dd95SBruce Richardson result = REQ_RESULT_FAIL; 43899a2dd95SBruce Richardson break; 43999a2dd95SBruce Richardson } 44099a2dd95SBruce Richardson if (resp->result == REQ_RESULT_FAIL) { 44199a2dd95SBruce Richardson result = REQ_RESULT_FAIL; 44299a2dd95SBruce Richardson break; 44399a2dd95SBruce Richardson } 44499a2dd95SBruce Richardson } 44599a2dd95SBruce Richardson 44699a2dd95SBruce Richardson if (entry->user_req.t == REQ_TYPE_FREE) { 44799a2dd95SBruce Richardson struct rte_mp_msg msg; 44899a2dd95SBruce Richardson struct malloc_mp_req *resp = (struct malloc_mp_req *)msg.param; 44999a2dd95SBruce Richardson 45099a2dd95SBruce Richardson memset(&msg, 0, sizeof(msg)); 45199a2dd95SBruce Richardson 45299a2dd95SBruce Richardson /* this is a free request, just sendmsg result */ 45399a2dd95SBruce Richardson resp->t = REQ_TYPE_FREE; 45499a2dd95SBruce Richardson resp->result = result; 45599a2dd95SBruce Richardson resp->id = entry->user_req.id; 45699a2dd95SBruce Richardson msg.num_fds = 0; 45799a2dd95SBruce Richardson msg.len_param = sizeof(*resp); 45899a2dd95SBruce Richardson strlcpy(msg.name, MP_ACTION_RESPONSE, sizeof(msg.name)); 45999a2dd95SBruce Richardson 46099a2dd95SBruce Richardson if (rte_mp_sendmsg(&msg)) 461ae67895bSDavid Marchand EAL_LOG(ERR, "Could not send message to secondary process"); 46299a2dd95SBruce Richardson 46399a2dd95SBruce Richardson TAILQ_REMOVE(&mp_request_list.list, entry, next); 46499a2dd95SBruce Richardson free(entry); 46599a2dd95SBruce Richardson } else if (entry->user_req.t == REQ_TYPE_ALLOC && 46699a2dd95SBruce Richardson result == REQ_RESULT_SUCCESS) { 46799a2dd95SBruce Richardson struct malloc_heap *heap = entry->alloc_state.heap; 46899a2dd95SBruce Richardson struct rte_mp_msg msg; 46999a2dd95SBruce Richardson struct malloc_mp_req *resp = 47099a2dd95SBruce Richardson (struct malloc_mp_req *)msg.param; 47199a2dd95SBruce Richardson 47299a2dd95SBruce Richardson memset(&msg, 0, sizeof(msg)); 47399a2dd95SBruce Richardson 47499a2dd95SBruce Richardson heap->total_size += entry->alloc_state.map_len; 47599a2dd95SBruce Richardson 47699a2dd95SBruce Richardson /* result is success, so just notify secondary about this */ 47799a2dd95SBruce Richardson resp->t = REQ_TYPE_ALLOC; 47899a2dd95SBruce Richardson resp->result = result; 47999a2dd95SBruce Richardson resp->id = entry->user_req.id; 48099a2dd95SBruce Richardson msg.num_fds = 0; 48199a2dd95SBruce Richardson msg.len_param = sizeof(*resp); 48299a2dd95SBruce Richardson strlcpy(msg.name, MP_ACTION_RESPONSE, sizeof(msg.name)); 48399a2dd95SBruce Richardson 48499a2dd95SBruce Richardson if (rte_mp_sendmsg(&msg)) 485ae67895bSDavid Marchand EAL_LOG(ERR, "Could not send message to secondary process"); 48699a2dd95SBruce Richardson 48799a2dd95SBruce Richardson TAILQ_REMOVE(&mp_request_list.list, entry, next); 48899a2dd95SBruce Richardson free(entry->alloc_state.ms); 48999a2dd95SBruce Richardson free(entry); 49099a2dd95SBruce Richardson } else if (entry->user_req.t == REQ_TYPE_ALLOC && 49199a2dd95SBruce Richardson result == REQ_RESULT_FAIL) { 49299a2dd95SBruce Richardson struct rte_mp_msg rb_msg; 49399a2dd95SBruce Richardson struct malloc_mp_req *rb = 49499a2dd95SBruce Richardson (struct malloc_mp_req *)rb_msg.param; 49599a2dd95SBruce Richardson struct timespec ts; 49699a2dd95SBruce Richardson struct primary_alloc_req_state *state = 49799a2dd95SBruce Richardson &entry->alloc_state; 49899a2dd95SBruce Richardson int ret; 49999a2dd95SBruce Richardson 50099a2dd95SBruce Richardson memset(&rb_msg, 0, sizeof(rb_msg)); 50199a2dd95SBruce Richardson 50299a2dd95SBruce Richardson /* we've failed to sync, so do a rollback */ 50399a2dd95SBruce Richardson eal_memalloc_mem_event_notify(RTE_MEM_EVENT_FREE, 50499a2dd95SBruce Richardson state->map_addr, state->map_len); 50599a2dd95SBruce Richardson 50699a2dd95SBruce Richardson rollback_expand_heap(state->ms, state->ms_len, state->elem, 50799a2dd95SBruce Richardson state->map_addr, state->map_len); 50899a2dd95SBruce Richardson 50999a2dd95SBruce Richardson /* send rollback request */ 51099a2dd95SBruce Richardson rb_msg.num_fds = 0; 51199a2dd95SBruce Richardson rb_msg.len_param = sizeof(*rb); 51299a2dd95SBruce Richardson strlcpy(rb_msg.name, MP_ACTION_ROLLBACK, sizeof(rb_msg.name)); 51399a2dd95SBruce Richardson 51499a2dd95SBruce Richardson ts.tv_nsec = 0; 51599a2dd95SBruce Richardson ts.tv_sec = MP_TIMEOUT_S; 51699a2dd95SBruce Richardson 51799a2dd95SBruce Richardson /* sync requests carry no data */ 51899a2dd95SBruce Richardson rb->t = REQ_TYPE_SYNC; 51999a2dd95SBruce Richardson rb->id = entry->user_req.id; 52099a2dd95SBruce Richardson 52199a2dd95SBruce Richardson /* there may be stray timeout still waiting */ 52299a2dd95SBruce Richardson do { 52399a2dd95SBruce Richardson ret = rte_mp_request_async(&rb_msg, &ts, 52499a2dd95SBruce Richardson handle_rollback_response); 52599a2dd95SBruce Richardson } while (ret != 0 && rte_errno == EEXIST); 52699a2dd95SBruce Richardson if (ret != 0) { 527ae67895bSDavid Marchand EAL_LOG(ERR, "Could not send rollback request to secondary process"); 52899a2dd95SBruce Richardson 52999a2dd95SBruce Richardson /* we couldn't send rollback request, but that's OK - 53099a2dd95SBruce Richardson * secondary will time out, and memory has been removed 53199a2dd95SBruce Richardson * from heap anyway. 53299a2dd95SBruce Richardson */ 53399a2dd95SBruce Richardson TAILQ_REMOVE(&mp_request_list.list, entry, next); 53499a2dd95SBruce Richardson free(state->ms); 53599a2dd95SBruce Richardson free(entry); 53699a2dd95SBruce Richardson goto fail; 53799a2dd95SBruce Richardson } 53899a2dd95SBruce Richardson } else { 539ae67895bSDavid Marchand EAL_LOG(ERR, " to sync request of unknown type"); 54099a2dd95SBruce Richardson goto fail; 54199a2dd95SBruce Richardson } 54299a2dd95SBruce Richardson 54399a2dd95SBruce Richardson pthread_mutex_unlock(&mp_request_list.lock); 54499a2dd95SBruce Richardson return 0; 54599a2dd95SBruce Richardson fail: 54699a2dd95SBruce Richardson pthread_mutex_unlock(&mp_request_list.lock); 54799a2dd95SBruce Richardson return -1; 54899a2dd95SBruce Richardson } 54999a2dd95SBruce Richardson 55099a2dd95SBruce Richardson static int 55199a2dd95SBruce Richardson handle_rollback_response(const struct rte_mp_msg *request, 55299a2dd95SBruce Richardson const struct rte_mp_reply *reply __rte_unused) 55399a2dd95SBruce Richardson { 55499a2dd95SBruce Richardson struct rte_mp_msg msg; 55599a2dd95SBruce Richardson struct malloc_mp_req *resp = (struct malloc_mp_req *)msg.param; 55699a2dd95SBruce Richardson const struct malloc_mp_req *mpreq = 55799a2dd95SBruce Richardson (const struct malloc_mp_req *)request->param; 55899a2dd95SBruce Richardson struct mp_request *entry; 55999a2dd95SBruce Richardson 56099a2dd95SBruce Richardson /* lock the request */ 56199a2dd95SBruce Richardson pthread_mutex_lock(&mp_request_list.lock); 56299a2dd95SBruce Richardson 56399a2dd95SBruce Richardson memset(&msg, 0, sizeof(msg)); 56499a2dd95SBruce Richardson 56599a2dd95SBruce Richardson entry = find_request_by_id(mpreq->id); 56699a2dd95SBruce Richardson if (entry == NULL) { 567ae67895bSDavid Marchand EAL_LOG(ERR, "Wrong request ID"); 56899a2dd95SBruce Richardson goto fail; 56999a2dd95SBruce Richardson } 57099a2dd95SBruce Richardson 57199a2dd95SBruce Richardson if (entry->user_req.t != REQ_TYPE_ALLOC) { 572ae67895bSDavid Marchand EAL_LOG(ERR, "Unexpected active request"); 57399a2dd95SBruce Richardson goto fail; 57499a2dd95SBruce Richardson } 57599a2dd95SBruce Richardson 57699a2dd95SBruce Richardson /* we don't care if rollback succeeded, request still failed */ 57799a2dd95SBruce Richardson resp->t = REQ_TYPE_ALLOC; 57899a2dd95SBruce Richardson resp->result = REQ_RESULT_FAIL; 57999a2dd95SBruce Richardson resp->id = mpreq->id; 58099a2dd95SBruce Richardson msg.num_fds = 0; 58199a2dd95SBruce Richardson msg.len_param = sizeof(*resp); 58299a2dd95SBruce Richardson strlcpy(msg.name, MP_ACTION_RESPONSE, sizeof(msg.name)); 58399a2dd95SBruce Richardson 58499a2dd95SBruce Richardson if (rte_mp_sendmsg(&msg)) 585ae67895bSDavid Marchand EAL_LOG(ERR, "Could not send message to secondary process"); 58699a2dd95SBruce Richardson 58799a2dd95SBruce Richardson /* clean up */ 58899a2dd95SBruce Richardson TAILQ_REMOVE(&mp_request_list.list, entry, next); 58999a2dd95SBruce Richardson free(entry->alloc_state.ms); 59099a2dd95SBruce Richardson free(entry); 59199a2dd95SBruce Richardson 59299a2dd95SBruce Richardson pthread_mutex_unlock(&mp_request_list.lock); 59399a2dd95SBruce Richardson return 0; 59499a2dd95SBruce Richardson fail: 59599a2dd95SBruce Richardson pthread_mutex_unlock(&mp_request_list.lock); 59699a2dd95SBruce Richardson return -1; 59799a2dd95SBruce Richardson } 59899a2dd95SBruce Richardson 59999a2dd95SBruce Richardson /* final stage of the request from secondary */ 60099a2dd95SBruce Richardson static int 60199a2dd95SBruce Richardson handle_response(const struct rte_mp_msg *msg, const void *peer __rte_unused) 60299a2dd95SBruce Richardson { 60399a2dd95SBruce Richardson const struct malloc_mp_req *m = 60499a2dd95SBruce Richardson (const struct malloc_mp_req *)msg->param; 60599a2dd95SBruce Richardson struct mp_request *entry; 60699a2dd95SBruce Richardson 60799a2dd95SBruce Richardson pthread_mutex_lock(&mp_request_list.lock); 60899a2dd95SBruce Richardson 60999a2dd95SBruce Richardson entry = find_request_by_id(m->id); 61099a2dd95SBruce Richardson if (entry != NULL) { 61199a2dd95SBruce Richardson /* update request status */ 61299a2dd95SBruce Richardson entry->user_req.result = m->result; 61399a2dd95SBruce Richardson 61499a2dd95SBruce Richardson entry->state = REQ_STATE_COMPLETE; 61599a2dd95SBruce Richardson 61699a2dd95SBruce Richardson /* trigger thread wakeup */ 61799a2dd95SBruce Richardson pthread_cond_signal(&entry->cond); 61899a2dd95SBruce Richardson } 61999a2dd95SBruce Richardson 62099a2dd95SBruce Richardson pthread_mutex_unlock(&mp_request_list.lock); 62199a2dd95SBruce Richardson 62299a2dd95SBruce Richardson return 0; 62399a2dd95SBruce Richardson } 62499a2dd95SBruce Richardson 62599a2dd95SBruce Richardson /* synchronously request memory map sync, this is only called whenever primary 62699a2dd95SBruce Richardson * process initiates the allocation. 62799a2dd95SBruce Richardson */ 62899a2dd95SBruce Richardson int 62999a2dd95SBruce Richardson request_sync(void) 63099a2dd95SBruce Richardson { 63199a2dd95SBruce Richardson struct rte_mp_msg msg; 63299a2dd95SBruce Richardson struct rte_mp_reply reply; 63399a2dd95SBruce Richardson struct malloc_mp_req *req = (struct malloc_mp_req *)msg.param; 63499a2dd95SBruce Richardson struct timespec ts; 63599a2dd95SBruce Richardson int i, ret = -1; 63699a2dd95SBruce Richardson 63799a2dd95SBruce Richardson memset(&msg, 0, sizeof(msg)); 63899a2dd95SBruce Richardson memset(&reply, 0, sizeof(reply)); 63999a2dd95SBruce Richardson 64099a2dd95SBruce Richardson /* no need to create tailq entries as this is entirely synchronous */ 64199a2dd95SBruce Richardson 64299a2dd95SBruce Richardson msg.num_fds = 0; 64399a2dd95SBruce Richardson msg.len_param = sizeof(*req); 64499a2dd95SBruce Richardson strlcpy(msg.name, MP_ACTION_SYNC, sizeof(msg.name)); 64599a2dd95SBruce Richardson 64699a2dd95SBruce Richardson /* sync request carries no data */ 64799a2dd95SBruce Richardson req->t = REQ_TYPE_SYNC; 64899a2dd95SBruce Richardson req->id = get_unique_id(); 64999a2dd95SBruce Richardson 65099a2dd95SBruce Richardson ts.tv_nsec = 0; 65199a2dd95SBruce Richardson ts.tv_sec = MP_TIMEOUT_S; 65299a2dd95SBruce Richardson 65399a2dd95SBruce Richardson /* there may be stray timeout still waiting */ 65499a2dd95SBruce Richardson do { 65599a2dd95SBruce Richardson ret = rte_mp_request_sync(&msg, &reply, &ts); 65699a2dd95SBruce Richardson } while (ret != 0 && rte_errno == EEXIST); 65799a2dd95SBruce Richardson if (ret != 0) { 65899a2dd95SBruce Richardson /* if IPC is unsupported, behave as if the call succeeded */ 65999a2dd95SBruce Richardson if (rte_errno != ENOTSUP) 660ae67895bSDavid Marchand EAL_LOG(ERR, "Could not send sync request to secondary process"); 66199a2dd95SBruce Richardson else 66299a2dd95SBruce Richardson ret = 0; 66399a2dd95SBruce Richardson goto out; 66499a2dd95SBruce Richardson } 66599a2dd95SBruce Richardson 66699a2dd95SBruce Richardson if (reply.nb_received != reply.nb_sent) { 667ae67895bSDavid Marchand EAL_LOG(ERR, "Not all secondaries have responded"); 66899a2dd95SBruce Richardson goto out; 66999a2dd95SBruce Richardson } 67099a2dd95SBruce Richardson 67199a2dd95SBruce Richardson for (i = 0; i < reply.nb_received; i++) { 67299a2dd95SBruce Richardson struct malloc_mp_req *resp = 67399a2dd95SBruce Richardson (struct malloc_mp_req *)reply.msgs[i].param; 67499a2dd95SBruce Richardson if (resp->t != REQ_TYPE_SYNC) { 675ae67895bSDavid Marchand EAL_LOG(ERR, "Unexpected response from secondary"); 67699a2dd95SBruce Richardson goto out; 67799a2dd95SBruce Richardson } 67899a2dd95SBruce Richardson if (resp->id != req->id) { 679ae67895bSDavid Marchand EAL_LOG(ERR, "Wrong request ID"); 68099a2dd95SBruce Richardson goto out; 68199a2dd95SBruce Richardson } 68299a2dd95SBruce Richardson if (resp->result != REQ_RESULT_SUCCESS) { 683ae67895bSDavid Marchand EAL_LOG(ERR, "Secondary process failed to synchronize"); 68499a2dd95SBruce Richardson goto out; 68599a2dd95SBruce Richardson } 68699a2dd95SBruce Richardson } 68799a2dd95SBruce Richardson 68899a2dd95SBruce Richardson ret = 0; 68999a2dd95SBruce Richardson out: 69099a2dd95SBruce Richardson free(reply.msgs); 69199a2dd95SBruce Richardson return ret; 69299a2dd95SBruce Richardson } 69399a2dd95SBruce Richardson 69499a2dd95SBruce Richardson /* this is a synchronous wrapper around a bunch of asynchronous requests to 69599a2dd95SBruce Richardson * primary process. this will initiate a request and wait until responses come. 69699a2dd95SBruce Richardson */ 69799a2dd95SBruce Richardson int 69899a2dd95SBruce Richardson request_to_primary(struct malloc_mp_req *user_req) 69999a2dd95SBruce Richardson { 70099a2dd95SBruce Richardson struct rte_mp_msg msg; 70199a2dd95SBruce Richardson struct malloc_mp_req *msg_req = (struct malloc_mp_req *)msg.param; 70299a2dd95SBruce Richardson struct mp_request *entry; 70399a2dd95SBruce Richardson struct timespec ts; 70499a2dd95SBruce Richardson struct timeval now; 70599a2dd95SBruce Richardson int ret; 70699a2dd95SBruce Richardson 70799a2dd95SBruce Richardson memset(&msg, 0, sizeof(msg)); 70899a2dd95SBruce Richardson memset(&ts, 0, sizeof(ts)); 70999a2dd95SBruce Richardson 71099a2dd95SBruce Richardson pthread_mutex_lock(&mp_request_list.lock); 71199a2dd95SBruce Richardson 71299a2dd95SBruce Richardson entry = malloc(sizeof(*entry)); 71399a2dd95SBruce Richardson if (entry == NULL) { 714ae67895bSDavid Marchand EAL_LOG(ERR, "Cannot allocate memory for request"); 71599a2dd95SBruce Richardson goto fail; 71699a2dd95SBruce Richardson } 71799a2dd95SBruce Richardson 71899a2dd95SBruce Richardson memset(entry, 0, sizeof(*entry)); 71999a2dd95SBruce Richardson 72099a2dd95SBruce Richardson if (gettimeofday(&now, NULL) < 0) { 721ae67895bSDavid Marchand EAL_LOG(ERR, "Cannot get current time"); 72299a2dd95SBruce Richardson goto fail; 72399a2dd95SBruce Richardson } 72499a2dd95SBruce Richardson 72599a2dd95SBruce Richardson ts.tv_nsec = (now.tv_usec * 1000) % 1000000000; 72699a2dd95SBruce Richardson ts.tv_sec = now.tv_sec + MP_TIMEOUT_S + 72799a2dd95SBruce Richardson (now.tv_usec * 1000) / 1000000000; 72899a2dd95SBruce Richardson 72999a2dd95SBruce Richardson /* initialize the request */ 73099a2dd95SBruce Richardson pthread_cond_init(&entry->cond, NULL); 73199a2dd95SBruce Richardson 73299a2dd95SBruce Richardson msg.num_fds = 0; 73399a2dd95SBruce Richardson msg.len_param = sizeof(*msg_req); 73499a2dd95SBruce Richardson strlcpy(msg.name, MP_ACTION_REQUEST, sizeof(msg.name)); 73599a2dd95SBruce Richardson 73699a2dd95SBruce Richardson /* (attempt to) get a unique id */ 73799a2dd95SBruce Richardson user_req->id = get_unique_id(); 73899a2dd95SBruce Richardson 73999a2dd95SBruce Richardson /* copy contents of user request into the message */ 74099a2dd95SBruce Richardson memcpy(msg_req, user_req, sizeof(*msg_req)); 74199a2dd95SBruce Richardson 74299a2dd95SBruce Richardson if (rte_mp_sendmsg(&msg)) { 743ae67895bSDavid Marchand EAL_LOG(ERR, "Cannot send message to primary"); 74499a2dd95SBruce Richardson goto fail; 74599a2dd95SBruce Richardson } 74699a2dd95SBruce Richardson 74799a2dd95SBruce Richardson /* copy contents of user request into active request */ 74899a2dd95SBruce Richardson memcpy(&entry->user_req, user_req, sizeof(*user_req)); 74999a2dd95SBruce Richardson 75099a2dd95SBruce Richardson /* mark request as in progress */ 75199a2dd95SBruce Richardson entry->state = REQ_STATE_ACTIVE; 75299a2dd95SBruce Richardson 75399a2dd95SBruce Richardson TAILQ_INSERT_TAIL(&mp_request_list.list, entry, next); 75499a2dd95SBruce Richardson 75599a2dd95SBruce Richardson /* finally, wait on timeout */ 75699a2dd95SBruce Richardson do { 75799a2dd95SBruce Richardson ret = pthread_cond_timedwait(&entry->cond, 75899a2dd95SBruce Richardson &mp_request_list.lock, &ts); 759*429219adSAnatoly Burakov } while ((ret != 0 && ret != ETIMEDOUT) && 760*429219adSAnatoly Burakov entry->state == REQ_STATE_ACTIVE); 76199a2dd95SBruce Richardson 76299a2dd95SBruce Richardson if (entry->state != REQ_STATE_COMPLETE) { 763ae67895bSDavid Marchand EAL_LOG(ERR, "Request timed out"); 76499a2dd95SBruce Richardson ret = -1; 76599a2dd95SBruce Richardson } else { 76699a2dd95SBruce Richardson ret = 0; 76799a2dd95SBruce Richardson user_req->result = entry->user_req.result; 76899a2dd95SBruce Richardson } 76999a2dd95SBruce Richardson TAILQ_REMOVE(&mp_request_list.list, entry, next); 77099a2dd95SBruce Richardson free(entry); 77199a2dd95SBruce Richardson 77299a2dd95SBruce Richardson pthread_mutex_unlock(&mp_request_list.lock); 77399a2dd95SBruce Richardson return ret; 77499a2dd95SBruce Richardson fail: 77599a2dd95SBruce Richardson pthread_mutex_unlock(&mp_request_list.lock); 77699a2dd95SBruce Richardson free(entry); 77799a2dd95SBruce Richardson return -1; 77899a2dd95SBruce Richardson } 77999a2dd95SBruce Richardson 78099a2dd95SBruce Richardson int 78199a2dd95SBruce Richardson register_mp_requests(void) 78299a2dd95SBruce Richardson { 78399a2dd95SBruce Richardson if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 78499a2dd95SBruce Richardson /* it's OK for primary to not support IPC */ 78599a2dd95SBruce Richardson if (rte_mp_action_register(MP_ACTION_REQUEST, handle_request) && 78699a2dd95SBruce Richardson rte_errno != ENOTSUP) { 787ae67895bSDavid Marchand EAL_LOG(ERR, "Couldn't register '%s' action", 78899a2dd95SBruce Richardson MP_ACTION_REQUEST); 78999a2dd95SBruce Richardson return -1; 79099a2dd95SBruce Richardson } 79199a2dd95SBruce Richardson } else { 79299a2dd95SBruce Richardson if (rte_mp_action_register(MP_ACTION_SYNC, handle_sync)) { 793ae67895bSDavid Marchand EAL_LOG(ERR, "Couldn't register '%s' action", 79499a2dd95SBruce Richardson MP_ACTION_SYNC); 79599a2dd95SBruce Richardson return -1; 79699a2dd95SBruce Richardson } 79799a2dd95SBruce Richardson if (rte_mp_action_register(MP_ACTION_ROLLBACK, handle_sync)) { 798ae67895bSDavid Marchand EAL_LOG(ERR, "Couldn't register '%s' action", 79999a2dd95SBruce Richardson MP_ACTION_SYNC); 80099a2dd95SBruce Richardson return -1; 80199a2dd95SBruce Richardson } 80299a2dd95SBruce Richardson if (rte_mp_action_register(MP_ACTION_RESPONSE, 80399a2dd95SBruce Richardson handle_response)) { 804ae67895bSDavid Marchand EAL_LOG(ERR, "Couldn't register '%s' action", 80599a2dd95SBruce Richardson MP_ACTION_RESPONSE); 80699a2dd95SBruce Richardson return -1; 80799a2dd95SBruce Richardson } 80899a2dd95SBruce Richardson } 80999a2dd95SBruce Richardson return 0; 81099a2dd95SBruce Richardson } 811a0cc7be2SStephen Hemminger 812a0cc7be2SStephen Hemminger void 813a0cc7be2SStephen Hemminger unregister_mp_requests(void) 814a0cc7be2SStephen Hemminger { 815a0cc7be2SStephen Hemminger if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 816a0cc7be2SStephen Hemminger rte_mp_action_unregister(MP_ACTION_REQUEST); 817a0cc7be2SStephen Hemminger } else { 818a0cc7be2SStephen Hemminger rte_mp_action_unregister(MP_ACTION_SYNC); 819a0cc7be2SStephen Hemminger rte_mp_action_unregister(MP_ACTION_ROLLBACK); 820a0cc7be2SStephen Hemminger rte_mp_action_unregister(MP_ACTION_RESPONSE); 821a0cc7be2SStephen Hemminger } 822a0cc7be2SStephen Hemminger } 823