diff --git a/net/ucx/Makefile b/net/ucx/Makefile index 2ee03bb259e5..59ef00cb8662 100644 --- a/net/ucx/Makefile +++ b/net/ucx/Makefile @@ -1,72 +1,73 @@ -PORTNAME= ucx -DISTVERSION= 1.20.1 -PORTREVISION= 1 -CATEGORIES= net -MASTER_SITES= https://github.com/openucx/ucx/releases/download/v${DISTVERSION}/ +PORTNAME= ucx +DISTVERSION= 1.20.1 +PORTREVISION= 2 +CATEGORIES= net +MASTER_SITES= https://github.com/openucx/ucx/releases/download/v${DISTVERSION}/ -MAINTAINER= rikka.goering@outlook.de -COMMENT= Unified Communication X framework (UCX) -WWW= https://openucx.org/ +MAINTAINER= rikka.goering@outlook.de +COMMENT= Unified Communication X framework (UCX) +WWW= https://openucx.org/ -LICENSE= BSD3CLAUSE -LICENSE_FILE= ${WRKSRC}/LICENSE +LICENSE= BSD3CLAUSE +LICENSE_FILE= ${WRKSRC}/LICENSE ONLY_FOR_ARCHS= aarch64 amd64 powerpc64le ONLY_FOR_ARCHS_REASON= uses arch-specific CPU backends; armv7 is not supported upstream and does not build on FreeBSD -BUILD_DEPENDS= ${LOCALBASE}/share/aclocal/ax_c_float_words_bigendian.m4:devel/autoconf-archive +BUILD_DEPENDS= bash:shells/bash \ + ${LOCALBASE}/share/aclocal/ax_c_float_words_bigendian.m4:devel/autoconf-archive -USES= autoreconf dos2unix gmake libtool pkgconfig -USE_LDCONFIG= yes +USES= autoreconf dos2unix gmake libtool pkgconfig +USE_LDCONFIG= yes -GNU_CONFIGURE= yes -CONFIGURE_ARGS= --disable-doxygen-doc \ - --enable-compiler-opt=0 \ - --enable-gtest \ - --enable-mt \ - --with-go=no -CONFIGURE_ENV= GIT=/usr/bin/false -INSTALL_TARGET= install-strip -TEST_ENV+= LD_LIBRARY_PATH=${STAGEDIR}${PREFIX}/lib -CFLAGS+= -Wno-error -CXXFLAGS+= -Wno-error -LDFLAGS+= -lexecinfo -lprocstat -lutil +GNU_CONFIGURE= yes +CONFIGURE_SHELL= ${LOCALBASE}/bin/bash +CONFIGURE_ARGS= --disable-doxygen-doc \ + --enable-compiler-opt=0 \ + --enable-gtest \ + --enable-mt \ + --with-go=no +CONFIGURE_ENV= GIT=/usr/bin/false +INSTALL_TARGET= install-strip +TEST_ENV+= LD_LIBRARY_PATH=${STAGEDIR}${PREFIX}/lib +TESTING_UNSAFE= yes +LDFLAGS+= -lexecinfo -lprocstat -lutil -PORTDOCS= * -PORTEXAMPLES= * +PORTDOCS= * +PORTEXAMPLES= * OPTIONS_DEFINE= DOCS EXAMPLES FUSE IBVERBS IODEMO PERFTEST UMAD OPTIONS_DEFAULT= FUSE IODEMO PERFTEST OPTIONS_SUB= yes IBVERBS_DESC= Enable InfiniBand/RDMA (verbs) transport IODEMO_DESC= Install io_demo test application PERFTEST_DESC= Install ucx_perftest benchmarks UMAD_DESC= Build/install perftest MAD plugin (umad) FUSE_LIB_DEPENDS= libfuse3.so:filesystems/fusefs-libs3 FUSE_CONFIGURE_ON= --with-fuse3=${LOCALBASE} FUSE_CONFIGURE_OFF= --with-fuse3=no IBVERBS_CONFIGURE_ON= --with-verbs=${LOCALBASE} IBVERBS_CONFIGURE_OFF= --with-verbs=no UMAD_IMPLIES= IBVERBS PERFTEST UMAD_CONFIGURE_ON= --with-mad=${LOCALBASE} UMAD_CONFIGURE_OFF= --with-mad=no post-patch: ${REINPLACE_CMD} 's|^examplesdir = $$(pkgdatadir)/examples$$|examplesdir = ${EXAMPLESDIR}|' \ ${WRKSRC}/examples/Makefile.am ${REINPLACE_CMD} 's|/run/user|/var/run/user|' \ ${WRKSRC}/src/ucs/vfs/sock/vfs_sock.h post-install: ${MV} ${STAGEDIR}${ETCDIR}/ucx.conf ${STAGEDIR}${ETCDIR}/ucx.conf.sample do-test: cd ${WRKSRC}/test/gtest && \ ${SETENV} ${TEST_ENV} ${MAKE_CMD} && \ - ${SETENV} ${TEST_ENV} ./gtest --gtest_filter=-malloc_hook*:sysv/*:test_rcache*:test_rcache_pfn*:test_vfs_sock*:test_datatype.hlist_for_each_extract_if:tcp/test_uct_pending.pending_fairness*:tcp/test_uct_peer_failure.purge_failed_peer*:tcp/test_uct_pending.pending_purge*:tcp/test_uct_iface.is_reachable*:tcp/test_uct_perf*:tcp/test_uct_loopback*:tcp/test_uct_tcp.listener_flood_connect_and_send_large*:tcp/test_uct_tcp.listener_flood_connect_and_send_small*:tcp/test_uct_tcp.check_addr_len*:shm*/*:mm_tcp/*:ib_shm/*:ud_tcp/*:all/*:*/test_ucp_loopback*:tcp/test_ucp_perf*:*/test_ucp_proto_mock_self.rkey_ptr*:test_config.test_config_file:test_config.test_config_file_parse_files:signal/*:*/test_async.many_timers*:*/test_ucp_peer_failure_keepalive*:self/test_ucp_wakeup.signal*:tcp/test_ucp_wakeup.signal*:tcp/test_proto_reset.am_eager_multi_bcopy*:tcp/test_uct_sockaddr.err_handle*:tcp/test_ucp_sockaddr_protocols_diff_net_devices*:tcp/test_ucp_sockaddr_iface_activate*:*/test_ucp_atomic*:*/test_ucp_mmap*:*/test_ucp_tag_match_rndv_align*:*/test_ucp_tag_probe*:tcp/test_ucp_sockaddr.*close_during_rndv*:tcp/test_ucp_sockaddr_protocols_err*::*test_ucp_wireup_1sided.stress_connect* + ${SETENV} ${TEST_ENV} ./gtest --gtest_filter=-malloc_hook*:sysv/*:test_rcache*:test_rcache_pfn*:test_vfs_sock*:test_datatype.hlist_for_each_extract_if:tcp/test_uct_pending.pending_fairness*:tcp/test_uct_peer_failure.purge_failed_peer*:tcp/test_uct_pending.pending_purge*:tcp/test_uct_iface.is_reachable*:tcp/test_uct_perf*:tcp/test_uct_loopback*:tcp/test_uct_tcp.listener_flood_connect_and_send_large*:tcp/test_uct_tcp.listener_flood_connect_and_send_small*:tcp/test_uct_tcp.check_addr_len*:shm*/*:mm_tcp/*:ib_shm/*:ud_tcp/*:all/*:*/test_ucp_loopback*:tcp/test_ucp_perf*:*/test_ucp_proto_mock_self.rkey_ptr*:test_config.test_config_file:test_config.test_config_file_parse_files:signal/*:*/test_async.many_timers*:*/test_ucp_peer_failure_keepalive*:self/test_ucp_wakeup.signal*:tcp/test_ucp_wakeup.signal*:tcp/test_proto_reset.am_eager_multi_bcopy*:tcp/test_uct_sockaddr.err_handle*:tcp/test_ucp_sockaddr_protocols_diff_net_devices*:tcp/test_ucp_sockaddr_iface_activate*:*/test_ucp_atomic*:*/test_ucp_mmap*:*/test_ucp_tag_match_rndv_align*:*/test_ucp_tag_probe*:tcp/test_ucp_sockaddr.*close_during_rndv*:tcp/test_ucp_sockaddr_protocols_err*:*test_ucp_wireup_1sided.stress_connect*:*/test_event_set.ucs_event_set_trig_modes* .include diff --git a/net/ucx/files/patch-config_m4_compiler.m4 b/net/ucx/files/patch-config_m4_compiler.m4 new file mode 100644 index 000000000000..80e7d70b12e5 --- /dev/null +++ b/net/ucx/files/patch-config_m4_compiler.m4 @@ -0,0 +1,16 @@ +--- config/m4/compiler.m4.orig 2026-07-01 18:11:37 UTC ++++ config/m4/compiler.m4 +@@ -10,7 +10,12 @@ + # + # Initialize CFLAGS + # +-BASE_CFLAGS="-g -Wall -Werror" ++case $host_os in ++freebsd*) ++ BASE_CFLAGS="-g -Wall" ;; ++*) ++ BASE_CFLAGS="-g -Wall -Werror" ;; ++esac + + # Prevent libtool from suppression of warnings + LT_CFLAGS="-no-suppress" diff --git a/net/ucx/files/patch-src_ucp_core_ucp__ep.c b/net/ucx/files/patch-src_ucp_core_ucp__ep.c new file mode 100644 index 000000000000..de942fa55c93 --- /dev/null +++ b/net/ucx/files/patch-src_ucp_core_ucp__ep.c @@ -0,0 +1,28 @@ +--- src/ucp/core/ucp_ep.c.orig 2026-07-01 23:04:16 UTC ++++ src/ucp/core/ucp_ep.c +@@ -3181,11 +3181,25 @@ void ucp_ep_config_lane_info_str(ucp_worker_h worker, + } + + dst_md_index = key->lanes[lane].dst_md_index; ++#ifdef __FreeBSD__ ++ if (key->dst_md_cmpts != NULL) { ++ cmpt_index = ucp_ep_config_get_dst_md_cmpt(key, dst_md_index); ++ ucs_string_buffer_appendf( ++ strbuf, "md[%d]/%s/sysdev[%d] seg %zu", dst_md_index, ++ context->tl_cmpts[cmpt_index].attr.name, ++ key->lanes[lane].dst_sys_dev, key->lanes[lane].seg_size); ++ } else { ++ ucs_string_buffer_appendf( ++ strbuf, "md[%d]/sysdev[%d] seg %zu", dst_md_index, ++ key->lanes[lane].dst_sys_dev, key->lanes[lane].seg_size); ++ } ++#else + cmpt_index = ucp_ep_config_get_dst_md_cmpt(key, dst_md_index); + ucs_string_buffer_appendf( + strbuf, "md[%d]/%s/sysdev[%d] seg %zu", dst_md_index, + context->tl_cmpts[cmpt_index].attr.name, key->lanes[lane].dst_sys_dev, + key->lanes[lane].seg_size); ++#endif + + prio = ucp_ep_config_get_multi_lane_prio(key->rma_bw_lanes, lane); + if (prio != -1) { diff --git a/net/ucx/files/patch-src_ucs_sys_event__set.c b/net/ucx/files/patch-src_ucs_sys_event__set.c index 0c269c24c9c4..9ea4db4b3ad4 100644 --- a/net/ucx/files/patch-src_ucs_sys_event__set.c +++ b/net/ucx/files/patch-src_ucs_sys_event__set.c @@ -1,232 +1,259 @@ ---- src/ucs/sys/event_set.c.orig 2026-02-04 09:52:46 UTC +--- src/ucs/sys/event_set.c.orig 2026-07-24 17:53:50 UTC +++ src/ucs/sys/event_set.c @@ -19,9 +19,14 @@ #include #include #include +#if defined(__FreeBSD__) +#include +#include +#include +#else #include +#endif - enum { UCS_SYS_EVENT_SET_EXTERNAL_EVENT_FD = UCS_BIT(0), }; @@ -32,9 +37,46 @@ const unsigned ucs_sys_event_set_max_wait_events = }; const unsigned ucs_sys_event_set_max_wait_events = +#if defined(__FreeBSD__) + UCS_ALLOCA_MAX_SIZE / sizeof(struct kevent); +#else UCS_ALLOCA_MAX_SIZE / sizeof(struct epoll_event); +#endif +#if defined(__FreeBSD__) +static inline int ucs_event_set_map_to_raw_flags(ucs_event_set_types_t events) +{ -+ /* Approximate edge-triggered behavior with EV_CLEAR */ -+ return (events & UCS_EVENT_SET_EDGE_TRIGGERED) ? EV_CLEAR : 0; ++ (void)events; ++ return 0; +} + +static inline int ucs_event_set_map_to_events(const struct kevent *kev) +{ + ucs_event_set_types_t events = 0; + + if (kev->filter == EVFILT_READ) { + events |= UCS_EVENT_SET_EVREAD; + } else if (kev->filter == EVFILT_WRITE) { + events |= UCS_EVENT_SET_EVWRITE; + } + if (kev->flags & EV_ERROR) { + events |= UCS_EVENT_SET_EVERR; + } + return events; +} + +static int ucs_kqueue_ctl(int kq, int fd, int filter, int op_flags, + int fflags, intptr_t data, void *udata) +{ + struct kevent kev; + EV_SET(&kev, (uintptr_t)fd, filter, op_flags, fflags, data, udata); + if (kevent(kq, &kev, 1, NULL, 0, NULL) < 0) { + return -1; + } + return 0; +} +#else static inline int ucs_event_set_map_to_raw_events(ucs_event_set_types_t events) { int raw_events = 0; @@ -72,6 +114,7 @@ static inline int ucs_event_set_map_to_events(int raw_ } return events; } +#endif static ucs_sys_event_set_t *ucs_event_set_alloc(int event_fd, unsigned flags) { @@ -105,12 +148,21 @@ ucs_status_t ucs_event_set_create(ucs_sys_event_set_t ucs_status_t status; int event_fd; +#if defined(__FreeBSD__) + /* Create kqueue set the thread will wait on */ + event_fd = kqueue(); + if (event_fd < 0) { + ucs_error("kqueue() failed: %m"); + return UCS_ERR_IO_ERROR; + } +#else /* Create epoll set the thread will wait on */ event_fd = epoll_create(1); if (event_fd < 0) { ucs_error("epoll_create() failed: %m"); return UCS_ERR_IO_ERROR; } +#endif *event_set_p = ucs_event_set_alloc(event_fd, 0); if (*event_set_p == NULL) { @@ -129,6 +181,26 @@ ucs_status_t ucs_event_set_add(ucs_sys_event_set_t *ev ucs_event_set_types_t events, void *callback_data) { +#if defined(__FreeBSD__) -+ int kq = event_set->event_fd; ++ int kq = event_set->event_fd; + int raw_flags = ucs_event_set_map_to_raw_flags(events); + + if (events & UCS_EVENT_SET_EVREAD) { + if (ucs_kqueue_ctl(kq, fd, EVFILT_READ, EV_ADD | EV_ENABLE | raw_flags, + 0, 0, callback_data) < 0) { + ucs_error("kevent(kq=%d, ADD, fd=%d, READ) failed: %m", kq, fd); + return UCS_ERR_IO_ERROR; + } + } + if (events & UCS_EVENT_SET_EVWRITE) { + if (ucs_kqueue_ctl(kq, fd, EVFILT_WRITE, EV_ADD | EV_ENABLE | raw_flags, + 0, 0, callback_data) < 0) { + ucs_error("kevent(kq=%d, ADD, fd=%d, WRITE) failed: %m", kq, fd); + return UCS_ERR_IO_ERROR; + } + } + return UCS_OK; +#else struct epoll_event raw_event; int ret; -@@ -144,12 +216,18 @@ ucs_status_t ucs_event_set_add(ucs_sys_event_set_t *ev +@@ -144,12 +216,45 @@ ucs_status_t ucs_event_set_add(ucs_sys_event_set_t *ev } return UCS_OK; +#endif } ucs_status_t ucs_event_set_mod(ucs_sys_event_set_t *event_set, int fd, ucs_event_set_types_t events, void *callback_data) { +#if defined(__FreeBSD__) -+ /* Simplest: delete then re-add with new mask */ -+ (void)ucs_event_set_del(event_set, fd); -+ return ucs_event_set_add(event_set, fd, events, callback_data); ++ int kq = event_set->event_fd; ++ int raw_flags = ucs_event_set_map_to_raw_flags(events); ++ ++ if (events & UCS_EVENT_SET_EVREAD) { ++ if (ucs_kqueue_ctl(kq, fd, EVFILT_READ, ++ EV_ADD | EV_ENABLE | raw_flags, ++ 0, 0, callback_data) < 0) { ++ ucs_error("kevent(kq=%d, MOD, fd=%d, READ) failed: %m", kq, fd); ++ return UCS_ERR_IO_ERROR; ++ } ++ } else { ++ if ((ucs_kqueue_ctl(kq, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL) < 0) && ++ (errno != ENOENT)) { ++ ucs_error("kevent(kq=%d, DEL READ, fd=%d) failed: %m", kq, fd); ++ } ++ } ++ if (events & UCS_EVENT_SET_EVWRITE) { ++ if (ucs_kqueue_ctl(kq, fd, EVFILT_WRITE, ++ EV_ADD | EV_ENABLE | raw_flags, ++ 0, 0, callback_data) < 0) { ++ ucs_error("kevent(kq=%d, MOD, fd=%d, WRITE) failed: %m", kq, fd); ++ return UCS_ERR_IO_ERROR; ++ } ++ } else { ++ if ((ucs_kqueue_ctl(kq, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL) < 0) && ++ (errno != ENOENT)) { ++ ucs_error("kevent(kq=%d, DEL WRITE, fd=%d) failed: %m", kq, fd); ++ } ++ } ++ return UCS_OK; +#else struct epoll_event raw_event; int ret; -@@ -165,10 +243,28 @@ ucs_status_t ucs_event_set_mod(ucs_sys_event_set_t *ev +@@ -165,10 +270,28 @@ ucs_status_t ucs_event_set_mod(ucs_sys_event_set_t *ev } return UCS_OK; +#endif } ucs_status_t ucs_event_set_del(ucs_sys_event_set_t *event_set, int fd) { +#if defined(__FreeBSD__) + int kq = event_set->event_fd; + int ret = 0; + + /* Delete both filters; ignore ENOENT (not registered). */ + if ((ucs_kqueue_ctl(kq, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL) < 0) && + (errno != ENOENT)) { + ucs_error("kevent(kq=%d, DEL, fd=%d, READ) failed: %m", kq, fd); + ret = -1; + } + if ((ucs_kqueue_ctl(kq, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL) < 0) && + (errno != ENOENT)) { + ucs_error("kevent(kq=%d, DEL, fd=%d, WRITE) failed: %m", kq, fd); + ret = -1; + } + return (ret < 0) ? UCS_ERR_IO_ERROR : UCS_OK; +#else int ret; ret = epoll_ctl(event_set->event_fd, EPOLL_CTL_DEL, fd, NULL); -@@ -179,6 +275,7 @@ ucs_status_t ucs_event_set_del(ucs_sys_event_set_t *ev +@@ -179,6 +302,7 @@ ucs_status_t ucs_event_set_del(ucs_sys_event_set_t *ev } return UCS_OK; +#endif } ucs_status_t ucs_event_set_wait(ucs_sys_event_set_t *event_set, -@@ -186,6 +283,45 @@ ucs_status_t ucs_event_set_wait(ucs_sys_event_set_t *e +@@ -186,6 +310,45 @@ ucs_status_t ucs_event_set_wait(ucs_sys_event_set_t *e ucs_event_set_handler_t event_set_handler, void *arg) { +#if defined(__FreeBSD__) + struct kevent *events; + int nready, i, io_events; + struct timespec ts, *tsp; + + ucs_assert(event_set_handler != NULL); + ucs_assert(num_events != NULL); + ucs_assert(*num_events <= ucs_sys_event_set_max_wait_events); + + events = ucs_alloca(sizeof(*events) * *num_events); + + if (timeout_ms < 0) { + tsp = NULL; + } else { + ts.tv_sec = timeout_ms / 1000; + ts.tv_nsec = (timeout_ms % 1000) * 1000000; + tsp = &ts; + } + + nready = kevent(event_set->event_fd, NULL, 0, events, *num_events, tsp); + if (ucs_unlikely(nready < 0)) { + *num_events = 0; + if (errno == EINTR) { + return UCS_INPROGRESS; + } + ucs_error("kevent() failed: %m"); + return UCS_ERR_IO_ERROR; + } + + ucs_assert(nready <= *num_events); + + for (i = 0; i < nready; i++) { + io_events = ucs_event_set_map_to_events(&events[i]); + event_set_handler(events[i].udata, io_events, arg); + } + + *num_events = nready; + return UCS_OK; +#else struct epoll_event *events; int nready, i, io_events; -@@ -217,6 +353,7 @@ ucs_status_t ucs_event_set_wait(ucs_sys_event_set_t *e +@@ -217,6 +380,7 @@ ucs_status_t ucs_event_set_wait(ucs_sys_event_set_t *e *num_events = nready; return UCS_OK; +#endif } void ucs_event_set_cleanup(ucs_sys_event_set_t *event_set) diff --git a/net/ucx/files/patch-src_ucs_vfs_fuse_vfs__fuse.c b/net/ucx/files/patch-src_ucs_vfs_fuse_vfs__fuse.c index 1def131f70d9..c3486228cc23 100644 --- a/net/ucx/files/patch-src_ucs_vfs_fuse_vfs__fuse.c +++ b/net/ucx/files/patch-src_ucs_vfs_fuse_vfs__fuse.c @@ -1,109 +1,125 @@ ---- src/ucs/vfs/fuse/vfs_fuse.c.orig 2026-02-04 09:52:46 UTC +--- src/ucs/vfs/fuse/vfs_fuse.c.orig 2026-06-26 16:34:01 UTC +++ src/ucs/vfs/fuse/vfs_fuse.c @@ -37,6 +37,7 @@ static struct { static struct { pthread_t thread_id; + int thread_started; pthread_mutex_t mutex; struct fuse *fuse; int fuse_fd; @@ -44,15 +45,20 @@ static struct { int inotify_fd; int watch_desc; } ucs_vfs_fuse_context = { - .thread_id = -1, - .mutex = PTHREAD_MUTEX_INITIALIZER, - .fuse = NULL, - .fuse_fd = -1, - .stop = 0, - .inotify_fd = -1, - .watch_desc = -1 + .thread_started = 0, + .mutex = PTHREAD_MUTEX_INITIALIZER, + .fuse = NULL, + .fuse_fd = -1, + .stop = 0, + .inotify_fd = -1, + .watch_desc = -1 }; +static void ucs_vfs_sigusr1_handler(int signo) +{ + (void)signo; +} + static void ucs_vfs_enum_dir_cb(const char *name, void *arg) { ucs_vfs_enum_dir_context_t *ctx = arg; -@@ -492,10 +498,10 @@ static void ucs_fuse_thread_stop() +@@ -302,9 +308,15 @@ static ucs_status_t ucs_vfs_fuse_wait_for_path(const c + ucs_vfs_fuse_context.inotify_fd, watch_dirname, + IN_CREATE | IN_IGNORED); + if (ucs_vfs_fuse_context.watch_desc < 0) { ++#ifdef __FreeBSD__ ++ ucs_warn("inotify_add_watch(%s) failed: %m. Disabling VFS live updates.", watch_dirname); ++ status = UCS_OK; ++ goto out_close_inotify_fd; ++#else + ucs_error("inotify_add_watch(%s) failed: %m", watch_dirname); + status = UCS_ERR_IO_ERROR; + goto out_close_inotify_fd; ++#endif + } + + /* Read events from inotify channel and exit when either the main thread set +@@ -492,10 +504,10 @@ static void ucs_fuse_thread_stop() static void ucs_fuse_thread_stop() { - sighandler_t orig_handler; + sig_t orig_handler; int ret; - orig_handler = signal(SIGUSR1, (sighandler_t)ucs_empty_function); + orig_handler = signal(SIGUSR1, ucs_vfs_sigusr1_handler); pthread_mutex_lock(&ucs_vfs_fuse_context.mutex); -@@ -518,15 +524,20 @@ static void ucs_fuse_thread_stop() +@@ -518,15 +530,20 @@ static void ucs_fuse_thread_stop() if (ucs_vfs_fuse_context.fuse != NULL) { fuse_exit(ucs_vfs_fuse_context.fuse); ucs_fuse_replace_fd_devnull(); - pthread_kill(ucs_vfs_fuse_context.thread_id, SIGUSR1); + if (ucs_vfs_fuse_context.thread_started) { + pthread_kill(ucs_vfs_fuse_context.thread_id, SIGUSR1); + } } pthread_mutex_unlock(&ucs_vfs_fuse_context.mutex); - ret = pthread_join(ucs_vfs_fuse_context.thread_id, NULL); - if (ret != 0) { - ucs_warn("pthread_join(0x%lx) failed: %m", - ucs_vfs_fuse_context.thread_id); + if (ucs_vfs_fuse_context.thread_started) { + ret = pthread_join(ucs_vfs_fuse_context.thread_id, NULL); + if (ret != 0) { + ucs_warn("pthread_join(0x%lx) failed: %m", + ucs_vfs_fuse_context.thread_id); + } + ucs_vfs_fuse_context.thread_started = 0; } signal(SIGUSR1, orig_handler); -@@ -536,11 +547,11 @@ static void ucs_vfs_fuse_atfork_child() +@@ -536,11 +553,11 @@ static void ucs_vfs_fuse_atfork_child() { /* Reset thread context at fork, since doing inotify_rm_watch() from child will prevent doing it later from the parent */ - ucs_vfs_fuse_context.thread_id = -1; - ucs_vfs_fuse_context.fuse = NULL; - ucs_vfs_fuse_context.fuse_fd = -1; - ucs_vfs_fuse_context.inotify_fd = -1; - ucs_vfs_fuse_context.watch_desc = -1; + ucs_vfs_fuse_context.thread_started = 0; + ucs_vfs_fuse_context.fuse = NULL; + ucs_vfs_fuse_context.fuse_fd = -1; + ucs_vfs_fuse_context.inotify_fd = -1; + ucs_vfs_fuse_context.watch_desc = -1; } void UCS_F_CTOR ucs_vfs_fuse_init() -@@ -549,12 +560,13 @@ void UCS_F_CTOR ucs_vfs_fuse_init() +@@ -549,12 +566,13 @@ void UCS_F_CTOR ucs_vfs_fuse_init() pthread_atfork(NULL, NULL, ucs_vfs_fuse_atfork_child); ucs_pthread_create(&ucs_vfs_fuse_context.thread_id, ucs_vfs_fuse_thread_func, NULL, "fuse"); + ucs_vfs_fuse_context.thread_started = 1; } } void UCS_F_DTOR ucs_vfs_fuse_cleanup() { - if (ucs_vfs_fuse_context.thread_id != -1) { + if (ucs_vfs_fuse_context.thread_started) { ucs_fuse_thread_stop(); } } diff --git a/net/ucx/files/patch-src_uct_base_uct__iface.c b/net/ucx/files/patch-src_uct_base_uct__iface.c new file mode 100644 index 000000000000..9f17767fbd5f --- /dev/null +++ b/net/ucx/files/patch-src_uct_base_uct__iface.c @@ -0,0 +1,22 @@ +--- src/uct/base/uct_iface.c.orig 2026-06-18 20:00:16 UTC ++++ src/uct/base/uct_iface.c +@@ -1025,6 +1025,11 @@ int uct_iface_local_is_reachable(uct_iface_local_addr_ + ucs_sys_namespace_type_t sys_ns_type, + const uct_iface_is_reachable_params_t *params) + { ++#ifdef __FreeBSD__ ++ /* On FreeBSD, local processes sharing loopback or IPC mechanisms ++ * are always mutually reachable. */ ++ return 1; ++#else + uct_iface_local_addr_ns_t my_addr = {}; + + uct_iface_get_local_address(&my_addr, sys_ns_type); +@@ -1054,6 +1059,7 @@ int uct_iface_local_is_reachable(uct_iface_local_addr_ + return 0; + } + return 1; ++#endif + } + + void uct_iface_mpool_config_copy(ucs_mpool_params_t *mp_params, diff --git a/net/ucx/files/patch-src_uct_tcp_tcp__iface.c b/net/ucx/files/patch-src_uct_tcp_tcp__iface.c index 6dbced1b33d7..09bb8fee678c 100644 --- a/net/ucx/files/patch-src_uct_tcp_tcp__iface.c +++ b/net/ucx/files/patch-src_uct_tcp_tcp__iface.c @@ -1,190 +1,258 @@ ---- src/uct/tcp/tcp_iface.c.orig 2026-05-06 13:47:14 UTC +--- src/uct/tcp/tcp_iface.c.orig 2026-07-24 21:46:07 UTC +++ src/uct/tcp/tcp_iface.c @@ -20,6 +20,10 @@ #include #include #include +#if defined(__FreeBSD__) +#include +#include +#endif #define UCT_TCP_IFACE_NETDEV_DIR "/sys/class/net" -@@ -284,6 +288,11 @@ uct_tcp_iface_get_sysfs_path(const char *dev_name, cha +@@ -195,6 +199,41 @@ uct_tcp_iface_get_address(uct_iface_h tl_iface, uct_if + return UCS_OK; + } + ++#if defined(__FreeBSD__) ++static int uct_tcp_iface_has_route(const struct sockaddr *addr) ++{ ++ struct sockaddr_storage addr_copy; ++ socklen_t addrlen; ++ int fd, ret; ++ ++ memcpy(&addr_copy, addr, sizeof(addr_copy)); ++ ++ if (addr->sa_family == AF_INET6) { ++ addrlen = sizeof(struct sockaddr_in6); ++ if (((struct sockaddr_in6*)&addr_copy)->sin6_port == 0) { ++ /* UDP connect() cannot target port 0; use a placeholder port ++ * since only route existence is being checked, not ++ * connectivity to a specific port. */ ++ ((struct sockaddr_in6*)&addr_copy)->sin6_port = htons(1); ++ } ++ } else { ++ addrlen = sizeof(struct sockaddr_in); ++ if (((struct sockaddr_in*)&addr_copy)->sin_port == 0) { ++ ((struct sockaddr_in*)&addr_copy)->sin_port = htons(1); ++ } ++ } ++ ++ fd = socket(addr->sa_family, SOCK_DGRAM, 0); ++ if (fd < 0) { ++ return 1; /* assume reachable if socket creation fails */ ++ } ++ ++ ret = connect(fd, (struct sockaddr*)&addr_copy, addrlen); ++ close(fd); ++ return (ret == 0); ++} ++#endif ++ + static int + uct_tcp_iface_is_reachable_v2(const uct_iface_h tl_iface, + const uct_iface_is_reachable_params_t *params) +@@ -207,6 +246,9 @@ uct_tcp_iface_is_reachable_v2(const uct_iface_h tl_ifa + char remote_addr_str[UCS_SOCKADDR_STRING_LEN]; + unsigned ndev_index; + ucs_status_t status; ++#if defined(__FreeBSD__) ++ int is_best_route; ++#endif + + if (!uct_iface_is_reachable_params_valid( + params, UCT_IFACE_IS_REACHABLE_FIELD_DEVICE_ADDR)) { +@@ -264,8 +306,13 @@ uct_tcp_iface_is_reachable_v2(const uct_iface_h tl_ifa + return 0; + } + +- if (!ucs_netlink_is_best_route(ndev_index, +- (const struct sockaddr*)&remote_addr)) { ++#if defined(__FreeBSD__) ++ is_best_route = uct_tcp_iface_has_route((const struct sockaddr*)&remote_addr); ++#else ++ int is_best_route = ucs_netlink_is_best_route(ndev_index, ++ (const struct sockaddr*)&remote_addr); ++#endif ++ if (!is_best_route) { + uct_iface_fill_info_str_buf( + params, "no route to %s", + ucs_sockaddr_str((const struct sockaddr *)&remote_addr, +@@ -284,6 +331,11 @@ uct_tcp_iface_get_sysfs_path(const char *dev_name, cha static const char * uct_tcp_iface_get_sysfs_path(const char *dev_name, char *path_buffer) { +#if defined(__FreeBSD__) + (void)dev_name; + (void)path_buffer; + return NULL; +#else const char *sysfs_path = NULL; ucs_status_t status; char *lowest_path_buf; -@@ -310,6 +319,7 @@ out: +@@ -310,6 +362,7 @@ out: ucs_free(lowest_path_buf); out: return sysfs_path; +#endif } static ucs_status_t uct_tcp_iface_query(uct_iface_h tl_iface, -@@ -422,7 +432,16 @@ static void uct_tcp_iface_handle_events(void *callback +@@ -422,7 +475,16 @@ static void uct_tcp_iface_handle_events(void *callback unsigned *count = (unsigned*)arg; uct_tcp_ep_t *ep = (uct_tcp_ep_t*)callback_data; +#if defined(__FreeBSD__) + /* kqueue may deliver a queued event for an ep that was closed and + * removed from the event set between the kevent() call and this + * callback. Treat it as a no-op rather than aborting. */ + if (ep->conn_state == UCT_TCP_EP_CONN_STATE_CLOSED) { + return; + } +#else ucs_assertv(ep->conn_state != UCT_TCP_EP_CONN_STATE_CLOSED, "ep=%p", ep); +#endif if (events & UCS_EVENT_SET_EVREAD) { *count += uct_tcp_ep_cm_state[ep->conn_state].rx_progress(ep); -@@ -943,6 +962,10 @@ static int uct_tcp_is_bridge(const char *if_name) +@@ -943,6 +1005,10 @@ static int uct_tcp_is_bridge(const char *if_name) static int uct_tcp_is_bridge(const char *if_name) { +#if defined(__FreeBSD__) + (void)if_name; + return 0; +#else char *path; int ret; struct stat st; -@@ -962,6 +985,7 @@ out: +@@ -962,6 +1028,7 @@ out: ucs_free(path); out: return ret; +#endif } ucs_status_t uct_tcp_query_devices(uct_md_h md, -@@ -971,7 +995,11 @@ ucs_status_t uct_tcp_query_devices(uct_md_h md, +@@ -971,7 +1038,11 @@ ucs_status_t uct_tcp_query_devices(uct_md_h md, uct_tcp_md_t *tcp_md = ucs_derived_of(md, uct_tcp_md_t); const unsigned sys_device_priority = 10; uct_tl_device_resource_t *devices, *tmp; - struct dirent **entries, **entry; +#if defined(__FreeBSD__) + struct if_nameindex *ifn, *it; +#else + struct dirent **entries, **entry; +#endif unsigned num_devices; int is_active, i, n; ucs_status_t status; -@@ -979,21 +1007,77 @@ ucs_status_t uct_tcp_query_devices(uct_md_h md, +@@ -979,21 +1050,77 @@ ucs_status_t uct_tcp_query_devices(uct_md_h md, char *path_buffer; ucs_sys_device_t sys_dev; +#if defined(__FreeBSD__) + ifn = if_nameindex(); + if (ifn == NULL) { + ucs_error("if_nameindex() failed: %m"); + status = UCS_ERR_IO_ERROR; + goto out; + } +#else n = scandir(UCT_TCP_IFACE_NETDEV_DIR, &entries, NULL, alphasort); if (n == -1) { ucs_error("scandir(%s) failed: %m", UCT_TCP_IFACE_NETDEV_DIR); status = UCS_ERR_IO_ERROR; goto out; } +#endif devices = NULL; num_devices = 0; +#if defined(__FreeBSD__) + path_buffer = NULL; + status = UCS_OK; +#else status = ucs_string_alloc_path_buffer(&path_buffer, "path_buffer"); if (status != UCS_OK) { - goto out; + goto out_release; } +#endif +#if defined(__FreeBSD__) + for (it = ifn; it->if_name != NULL; ++it) { + is_active = 0; + for (i = 0; i < tcp_md->config.af_prio_count; i++) { + if (ucs_netif_is_active(it->if_name, + tcp_md->config.af_prio_list[i])) { + is_active = 1; + break; + } + } + + if (!is_active) { + continue; + } + + if (!tcp_md->config.bridge_enable && + uct_tcp_is_bridge(it->if_name)) { + ucs_debug("filtered out bridge device %s", it->if_name); + continue; + } + + tmp = ucs_realloc(devices, sizeof(*devices) * (num_devices + 1), + "tcp devices"); + if (tmp == NULL) { + ucs_free(devices); + status = UCS_ERR_NO_MEMORY; + goto out_release; + } + devices = tmp; + + sysfs_path = uct_tcp_iface_get_sysfs_path(it->if_name, path_buffer); + sys_dev = ucs_topo_get_sysfs_dev(it->if_name, sysfs_path, + sys_device_priority); + + ucs_snprintf_zero(devices[num_devices].name, + sizeof(devices[num_devices].name), "%s", + it->if_name); + devices[num_devices].type = UCT_DEVICE_TYPE_NET; + devices[num_devices].sys_device = sys_dev; + ++num_devices; + } +#else ucs_carray_for_each(entry, entries, n) { /* According to the sysfs(5) manual page, all of entries * has to be a symbolic link representing one of the real -@@ -1045,18 +1129,28 @@ ucs_status_t uct_tcp_query_devices(uct_md_h md, +@@ -1045,18 +1172,28 @@ ucs_status_t uct_tcp_query_devices(uct_md_h md, devices[num_devices].sys_device = sys_dev; ++num_devices; } +#endif *num_devices_p = num_devices; *devices_p = devices; status = UCS_OK; out_release: +#if defined(__FreeBSD__) + if (ifn != NULL) { + if_freenameindex(ifn); + } + if (path_buffer != NULL) { + ucs_free(path_buffer); + } +#else ucs_carray_for_each(entry, entries, n) { free(*entry); } free(entries); ucs_free(path_buffer); +#endif out: return status; }