From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by dpdk.org (Postfix) with ESMTP id 237825F71 for ; Wed, 7 Mar 2018 17:57:17 +0100 (CET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Mar 2018 08:57:17 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.47,436,1515484800"; d="scan'208";a="35368078" Received: from irvmail001.ir.intel.com ([163.33.26.43]) by fmsmga004.fm.intel.com with ESMTP; 07 Mar 2018 08:57:14 -0800 Received: from sivswdev01.ir.intel.com (sivswdev01.ir.intel.com [10.237.217.45]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id w27GvDp6032431; Wed, 7 Mar 2018 16:57:13 GMT Received: from sivswdev01.ir.intel.com (localhost [127.0.0.1]) by sivswdev01.ir.intel.com with ESMTP id w27GvDuH006832; Wed, 7 Mar 2018 16:57:13 GMT Received: (from aburakov@localhost) by sivswdev01.ir.intel.com with LOCAL id w27GvDSC006828; Wed, 7 Mar 2018 16:57:13 GMT From: Anatoly Burakov To: dev@dpdk.org Cc: keith.wiles@intel.com, jianfeng.tan@intel.com, andras.kovacs@ericsson.com, laszlo.vadkeri@ericsson.com, benjamin.walker@intel.com, bruce.richardson@intel.com, thomas@monjalon.net, konstantin.ananyev@intel.com, kuralamudhan.ramakrishnan@intel.com, louise.m.daly@intel.com, nelio.laranjeiro@6wind.com, yskoh@mellanox.com, pepperjo@japf.ch, jerin.jacob@caviumnetworks.com, hemant.agrawal@nxp.com, olivier.matz@6wind.com Date: Wed, 7 Mar 2018 16:56:57 +0000 Message-Id: <6c7ce08a3490422a2ee2cedad9a008ae258f7900.1520428025.git.anatoly.burakov@intel.com> X-Mailer: git-send-email 1.7.0.7 In-Reply-To: References: In-Reply-To: References: Subject: [dpdk-dev] [PATCH v2 29/41] eal: add support for callbacks on memory hotplug X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 07 Mar 2018 16:57:18 -0000 Each process will have its own callbacks. Callbacks will indicate whether it's allocation and deallocation that's happened, and will also provide start VA address and length of allocated block. Since memory hotplug isn't supported on FreeBSD and in legacy mem mode, it will not be possible to register them in either. Signed-off-by: Anatoly Burakov --- lib/librte_eal/common/eal_common_memalloc.c | 132 ++++++++++++++++++++++++++++ lib/librte_eal/common/eal_common_memory.c | 28 ++++++ lib/librte_eal/common/eal_memalloc.h | 10 +++ lib/librte_eal/common/include/rte_memory.h | 48 ++++++++++ lib/librte_eal/rte_eal_version.map | 2 + 5 files changed, 220 insertions(+) diff --git a/lib/librte_eal/common/eal_common_memalloc.c b/lib/librte_eal/common/eal_common_memalloc.c index 62e8c16..4fb55f2 100644 --- a/lib/librte_eal/common/eal_common_memalloc.c +++ b/lib/librte_eal/common/eal_common_memalloc.c @@ -2,16 +2,46 @@ * Copyright(c) 2017-2018 Intel Corporation */ +#include + +#include #include #include #include #include #include +#include #include "eal_private.h" #include "eal_internal_cfg.h" #include "eal_memalloc.h" +struct mem_event_callback_entry { + TAILQ_ENTRY(mem_event_callback_entry) next; + char name[RTE_MEM_EVENT_CALLBACK_NAME_LEN]; + rte_mem_event_callback_t clb; +}; + +/** Double linked list of actions. */ +TAILQ_HEAD(mem_event_callback_entry_list, mem_event_callback_entry); + +static struct mem_event_callback_entry_list callback_list = + TAILQ_HEAD_INITIALIZER(callback_list); + +static rte_rwlock_t rwlock = RTE_RWLOCK_INITIALIZER; + +static struct mem_event_callback_entry * +find_callback(const char *name) +{ + struct mem_event_callback_entry *r; + + TAILQ_FOREACH(r, &callback_list, next) { + if (!strcmp(r->name, name)) + break; + } + return r; +} + bool eal_memalloc_is_contig(struct rte_memseg_list *msl, void *start, size_t len) @@ -47,3 +77,105 @@ eal_memalloc_is_contig(struct rte_memseg_list *msl, void *start, return true; } + +int +eal_memalloc_callback_register(const char *name, + rte_mem_event_callback_t clb) +{ + struct mem_event_callback_entry *entry; + int ret, len; + if (name == NULL || clb == NULL) { + rte_errno = EINVAL; + return -1; + } + len = strnlen(name, RTE_MEM_EVENT_CALLBACK_NAME_LEN); + if (len == 0) { + rte_errno = EINVAL; + return -1; + } else if (len == RTE_MEM_EVENT_CALLBACK_NAME_LEN) { + rte_errno = ENAMETOOLONG; + return -1; + } + rte_rwlock_write_lock(&rwlock); + + entry = find_callback(name); + if (entry != NULL) { + rte_errno = EEXIST; + ret = -1; + goto unlock; + } + + entry = malloc(sizeof(*entry)); + if (entry == NULL) { + rte_errno = ENOMEM; + ret = -1; + goto unlock; + } + + /* callback successfully created and is valid, add it to the list */ + entry->clb = clb; + snprintf(entry->name, RTE_MEM_EVENT_CALLBACK_NAME_LEN, "%s", name); + TAILQ_INSERT_TAIL(&callback_list, entry, next); + + ret = 0; + + RTE_LOG(DEBUG, EAL, "Mem event callback '%s' registered\n", name); + +unlock: + rte_rwlock_write_unlock(&rwlock); + return ret; +} + +int +eal_memalloc_callback_unregister(const char *name) +{ + struct mem_event_callback_entry *entry; + int ret, len; + + if (name == NULL) { + rte_errno = EINVAL; + return -1; + } + len = strnlen(name, RTE_MEM_EVENT_CALLBACK_NAME_LEN); + if (len == 0) { + rte_errno = EINVAL; + return -1; + } else if (len == RTE_MEM_EVENT_CALLBACK_NAME_LEN) { + rte_errno = ENAMETOOLONG; + return -1; + } + rte_rwlock_write_lock(&rwlock); + + entry = find_callback(name); + if (entry == NULL) { + rte_errno = ENOENT; + ret = -1; + goto unlock; + } + TAILQ_REMOVE(&callback_list, entry, next); + free(entry); + + ret = 0; + + RTE_LOG(DEBUG, EAL, "Mem event callback '%s' unregistered\n", name); + +unlock: + rte_rwlock_write_unlock(&rwlock); + return ret; +} + +void +eal_memalloc_notify(enum rte_mem_event event, const void *start, size_t len) +{ + struct mem_event_callback_entry *entry; + + rte_rwlock_read_lock(&rwlock); + + TAILQ_FOREACH(entry, &callback_list, next) { + RTE_LOG(DEBUG, EAL, "Calling mem event callback %s", + entry->name); + entry->clb(event, start, len); + } + + rte_rwlock_read_unlock(&rwlock); +} diff --git a/lib/librte_eal/common/eal_common_memory.c b/lib/librte_eal/common/eal_common_memory.c index 0a0aa88..2d73cf3 100644 --- a/lib/librte_eal/common/eal_common_memory.c +++ b/lib/librte_eal/common/eal_common_memory.c @@ -466,6 +466,34 @@ rte_eal_get_physmem_size(void) return total_len; } +/* + * Defining here because declared in rte_memory.h, but the actual implementation + * is in eal_common_memalloc.c, like all other memalloc internals. + */ +int +rte_mem_event_register_callback(const char *name, rte_mem_event_callback_t clb) +{ + /* FreeBSD boots with legacy mem enabled by default */ + if (internal_config.legacy_mem) { + RTE_LOG(DEBUG, EAL, "Registering mem event callbacks not supported\n"); + rte_errno = ENOTSUP; + return -1; + } + return eal_memalloc_callback_register(name, clb); +} + +int +rte_mem_event_unregister_callback(const char *name) +{ + /* FreeBSD boots with legacy mem enabled by default */ + if (internal_config.legacy_mem) { + RTE_LOG(DEBUG, EAL, "Registering mem event callbacks not supported\n"); + rte_errno = ENOTSUP; + return -1; + } + return eal_memalloc_callback_unregister(name); +} + /* Dump the physical memory layout on console */ void rte_dump_physmem_layout(FILE *f) diff --git a/lib/librte_eal/common/eal_memalloc.h b/lib/librte_eal/common/eal_memalloc.h index beac296..499cf58 100644 --- a/lib/librte_eal/common/eal_memalloc.h +++ b/lib/librte_eal/common/eal_memalloc.h @@ -28,4 +28,14 @@ eal_memalloc_is_contig(struct rte_memseg_list *msl, void *start, int eal_memalloc_sync_with_primary(void); +int +eal_memalloc_callback_register(const char *name, + rte_mem_event_callback_t clb); + +int +eal_memalloc_callback_unregister(const char *name); + +void +eal_memalloc_notify(enum rte_mem_event event, const void *start, size_t len); + #endif // EAL_MEMALLOC_H diff --git a/lib/librte_eal/common/include/rte_memory.h b/lib/librte_eal/common/include/rte_memory.h index 674d4cb..1c8ffa6 100644 --- a/lib/librte_eal/common/include/rte_memory.h +++ b/lib/librte_eal/common/include/rte_memory.h @@ -200,6 +200,54 @@ unsigned rte_memory_get_nrank(void); */ int rte_eal_using_phys_addrs(void); + +/** + * Enum indicating which kind of memory event has happened. Used by callbacks to + * distinguish between memory allocations and deallocations. + */ +enum rte_mem_event { + RTE_MEM_EVENT_ALLOC = 0, /**< Allocation event. */ + RTE_MEM_EVENT_FREE, /**< Deallocation event. */ +}; +#define RTE_MEM_EVENT_CALLBACK_NAME_LEN 64 +/**< maximum length of callback name */ + +/** + * Function typedef used to register callbacks for memory events. + */ +typedef void (*rte_mem_event_callback_t)(enum rte_mem_event event_type, + const void *addr, size_t len); + +/** + * Function used to register callbacks for memory events. + * + * @param name + * Name associated with specified callback to be added to the list. + * + * @param clb + * Callback function pointer. + * + * @return + * 0 on successful callback register + * -1 on unsuccessful callback register, with rte_errno value indicating + * reason for failure. + */ +int rte_mem_event_register_callback(const char *name, + rte_mem_event_callback_t clb); + +/** + * Function used to unregister callbacks for memory events. + * + * @param name + * Name associated with specified callback to be removed from the list. + * + * @return + * 0 on successful callback unregister + * -1 on unsuccessful callback unregister, with rte_errno value indicating + * reason for failure. + */ +int rte_mem_event_unregister_callback(const char *name); + #ifdef __cplusplus } #endif diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map index 4c2e959..b2a2d37 100644 --- a/lib/librte_eal/rte_eal_version.map +++ b/lib/librte_eal/rte_eal_version.map @@ -214,6 +214,8 @@ DPDK_18.05 { global: rte_num_sockets; + rte_mem_event_callback_register; + rte_mem_event_callback_unregister; rte_mem_virt2memseg; rte_mem_virt2memseg_list; rte_malloc_dump_heaps; -- 2.7.4