/* * Copyright (c) 2017-2019 Intel Corporation, Inc. All rights reserved. * Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef _OFI_MR_H_ #define _OFI_MR_H_ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include struct ofi_mr_info { struct iovec iov; }; #define OFI_MR_BASIC_MAP (FI_MR_ALLOCATED | FI_MR_PROV_KEY | FI_MR_VIRT_ADDR) /* FI_LOCAL_MR is valid in pre-libfaric-1.5 and can be valid in * post-libfabric-1.5 */ static inline int ofi_mr_local(const struct fi_info *info) { if (!info) return 0; if (!info->domain_attr) goto check_local_mr; if (info->domain_attr->mr_mode & FI_MR_LOCAL) return 1; if (info->domain_attr->mr_mode & ~(FI_MR_BASIC | FI_MR_SCALABLE)) return 0; check_local_mr: return (info->mode & FI_LOCAL_MR) ? 1 : 0; } #define OFI_MR_MODE_RMA_TARGET (FI_MR_RAW | FI_MR_VIRT_ADDR | \ FI_MR_PROV_KEY | FI_MR_RMA_EVENT) /* If the app sets FI_MR_LOCAL, we ignore FI_LOCAL_MR. So, if the * app doesn't set FI_MR_LOCAL, we need to check for FI_LOCAL_MR. * The provider is assumed only to set FI_MR_LOCAL correctly. */ static inline uint64_t ofi_mr_get_prov_mode(uint32_t version, const struct fi_info *user_info, const struct fi_info *prov_info) { if (FI_VERSION_LT(version, FI_VERSION(1, 5)) || (user_info->domain_attr && !(user_info->domain_attr->mr_mode & FI_MR_LOCAL))) { return (prov_info->domain_attr->mr_mode & FI_MR_LOCAL) ? prov_info->mode | FI_LOCAL_MR : prov_info->mode; } else { return prov_info->mode; } } /* Single lock used by all memory monitors and MR caches. */ extern pthread_mutex_t mm_lock; /* * Memory notifier - Report memory mapping changes to address ranges */ struct ofi_mr_cache; struct ofi_mem_monitor { struct dlist_entry list; void (*init)(struct ofi_mem_monitor *monitor); void (*cleanup)(struct ofi_mem_monitor *monitor); int (*subscribe)(struct ofi_mem_monitor *notifier, const void *addr, size_t len); void (*unsubscribe)(struct ofi_mem_monitor *notifier, const void *addr, size_t len); }; void ofi_monitor_init(struct ofi_mem_monitor *monitor); void ofi_monitor_cleanup(struct ofi_mem_monitor *monitor); void ofi_monitors_init(void); void ofi_monitors_cleanup(void); int ofi_monitor_add_cache(struct ofi_mem_monitor *monitor, struct ofi_mr_cache *cache); void ofi_monitor_del_cache(struct ofi_mr_cache *cache); void ofi_monitor_notify(struct ofi_mem_monitor *monitor, const void *addr, size_t len); int ofi_monitor_subscribe(struct ofi_mem_monitor *monitor, const void *addr, size_t len); void ofi_monitor_unsubscribe(struct ofi_mem_monitor *monitor, const void *addr, size_t len); extern struct ofi_mem_monitor *default_monitor; /* * Userfault fd memory monitor */ struct ofi_uffd { struct ofi_mem_monitor monitor; pthread_t thread; int fd; }; int ofi_uffd_start(void); void ofi_uffd_stop(void); extern struct ofi_mem_monitor *uffd_monitor; /* * Memory intercept call memory monitor */ struct ofi_memhooks { struct ofi_mem_monitor monitor; struct dlist_entry intercept_list; }; int ofi_memhooks_start(void); void ofi_memhooks_stop(void); extern struct ofi_mem_monitor *memhooks_monitor; /* * Used to store registered memory regions into a lookup map. This * is used by the ofi_mr_xxx calls below, and may be accessed by a * provider when processing incoming RMA operations to verify that * a region has been registered for the specified operation. */ struct ofi_mr_map { const struct fi_provider *prov; struct ofi_rbmap *rbtree; uint64_t key; int mode; }; int ofi_mr_map_init(const struct fi_provider *in_prov, int mode, struct ofi_mr_map *map); void ofi_mr_map_close(struct ofi_mr_map *map); int ofi_mr_map_insert(struct ofi_mr_map *map, const struct fi_mr_attr *attr, uint64_t *key, void *context); int ofi_mr_map_remove(struct ofi_mr_map *map, uint64_t key); void *ofi_mr_map_get(struct ofi_mr_map *map, uint64_t key); int ofi_mr_map_verify(struct ofi_mr_map *map, uintptr_t *io_addr, size_t len, uint64_t key, uint64_t access, void **context); /* * These calls may be used be providers to implement software memory * registration. */ struct ofi_mr { struct fid_mr mr_fid; struct util_domain *domain; uint64_t key; uint64_t flags; }; int ofi_mr_close(struct fid *fid); int ofi_mr_regattr(struct fid *fid, const struct fi_mr_attr *attr, uint64_t flags, struct fid_mr **mr_fid); int ofi_mr_regv(struct fid *fid, const struct iovec *iov, size_t count, uint64_t access, uint64_t offset, uint64_t requested_key, uint64_t flags, struct fid_mr **mr_fid, void *context); int ofi_mr_reg(struct fid *fid, const void *buf, size_t len, uint64_t access, uint64_t offset, uint64_t requested_key, uint64_t flags, struct fid_mr **mr_fid, void *context); int ofi_mr_verify(struct ofi_mr_map *map, ssize_t len, uintptr_t *addr, uint64_t key, uint64_t access); /* * Memory registration cache */ struct ofi_mr_cache_params { size_t max_cnt; size_t max_size; char * monitor; }; extern struct ofi_mr_cache_params cache_params; struct ofi_mr_entry { struct ofi_mr_info info; void *storage_context; unsigned int subscribed:1; int use_cnt; struct dlist_entry list_entry; uint8_t data[]; }; enum ofi_mr_storage_type { OFI_MR_STORAGE_DEFAULT = 0, OFI_MR_STORAGE_RBT, OFI_MR_STORAGE_USER, }; struct ofi_mr_storage { enum ofi_mr_storage_type type; void *storage; struct ofi_mr_entry * (*find)(struct ofi_mr_storage *storage, const struct ofi_mr_info *key); struct ofi_mr_entry * (*overlap)(struct ofi_mr_storage *storage, const struct iovec *key); int (*insert)(struct ofi_mr_storage *storage, struct ofi_mr_info *key, struct ofi_mr_entry *entry); int (*erase)(struct ofi_mr_storage *storage, struct ofi_mr_entry *entry); void (*destroy)(struct ofi_mr_storage *storage); }; struct ofi_mr_cache { struct util_domain *domain; struct ofi_mem_monitor *monitor; struct dlist_entry notify_entry; size_t entry_data_size; struct ofi_mr_storage storage; struct dlist_entry lru_list; struct dlist_entry flush_list; pthread_mutex_t lock; size_t cached_cnt; size_t cached_size; size_t uncached_cnt; size_t uncached_size; size_t search_cnt; size_t delete_cnt; size_t hit_cnt; size_t notify_cnt; struct ofi_bufpool *entry_pool; int (*add_region)(struct ofi_mr_cache *cache, struct ofi_mr_entry *entry); void (*delete_region)(struct ofi_mr_cache *cache, struct ofi_mr_entry *entry); }; int ofi_mr_cache_init(struct util_domain *domain, struct ofi_mem_monitor *monitor, struct ofi_mr_cache *cache); void ofi_mr_cache_cleanup(struct ofi_mr_cache *cache); void ofi_mr_cache_notify(struct ofi_mr_cache *cache, const void *addr, size_t len); bool ofi_mr_cache_flush(struct ofi_mr_cache *cache, bool flush_lru); int ofi_mr_cache_search(struct ofi_mr_cache *cache, const struct fi_mr_attr *attr, struct ofi_mr_entry **entry); /** * Given an attr (with an iov range), if the iov range is already registered, * return the corresponding ofi_mr_entry. Otherwise, return NULL. * The caller must call ofi_mr_cache_delete on the entry before cleanup if * the returned entry is not NULL. * * @param[in] cache The cache the entry belongs to * @param[in] attr Information about the region to search * * @returns entry The registered entry corresponding to the * region described in attr * @returns NULL The region described in attr is not registered * with the cache. */ struct ofi_mr_entry *ofi_mr_cache_find(struct ofi_mr_cache *cache, const struct fi_mr_attr *attr); int ofi_mr_cache_reg(struct ofi_mr_cache *cache, const struct fi_mr_attr *attr, struct ofi_mr_entry **entry); void ofi_mr_cache_delete(struct ofi_mr_cache *cache, struct ofi_mr_entry *entry); #endif /* _OFI_MR_H_ */