162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2004 Oracle. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * ---- 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Callers for this were originally written against a very simple synchronus 962306a36Sopenharmony_ci * API. This implementation reflects those simple callers. Some day I'm sure 1062306a36Sopenharmony_ci * we'll need to move to a more robust posting/callback mechanism. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Transmit calls pass in kernel virtual addresses and block copying this into 1362306a36Sopenharmony_ci * the socket's tx buffers via a usual blocking sendmsg. They'll block waiting 1462306a36Sopenharmony_ci * for a failed socket to timeout. TX callers can also pass in a poniter to an 1562306a36Sopenharmony_ci * 'int' which gets filled with an errno off the wire in response to the 1662306a36Sopenharmony_ci * message they send. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Handlers for unsolicited messages are registered. Each socket has a page 1962306a36Sopenharmony_ci * that incoming data is copied into. First the header, then the data. 2062306a36Sopenharmony_ci * Handlers are called from only one thread with a reference to this per-socket 2162306a36Sopenharmony_ci * page. This page is destroyed after the handler call, so it can't be 2262306a36Sopenharmony_ci * referenced beyond the call. Handlers may block but are discouraged from 2362306a36Sopenharmony_ci * doing so. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * Any framing errors (bad magic, large payload lengths) close a connection. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * Our sock_container holds the state we associate with a socket. It's current 2862306a36Sopenharmony_ci * framing state is held there as well as the refcounting we do around when it 2962306a36Sopenharmony_ci * is safe to tear down the socket. The socket is only finally torn down from 3062306a36Sopenharmony_ci * the container when the container loses all of its references -- so as long 3162306a36Sopenharmony_ci * as you hold a ref on the container you can trust that the socket is valid 3262306a36Sopenharmony_ci * for use with kernel socket APIs. 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * Connections are initiated between a pair of nodes when the node with the 3562306a36Sopenharmony_ci * higher node number gets a heartbeat callback which indicates that the lower 3662306a36Sopenharmony_ci * numbered node has started heartbeating. The lower numbered node is passive 3762306a36Sopenharmony_ci * and only accepts the connection if the higher numbered node is heartbeating. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#include <linux/kernel.h> 4162306a36Sopenharmony_ci#include <linux/sched/mm.h> 4262306a36Sopenharmony_ci#include <linux/jiffies.h> 4362306a36Sopenharmony_ci#include <linux/slab.h> 4462306a36Sopenharmony_ci#include <linux/idr.h> 4562306a36Sopenharmony_ci#include <linux/kref.h> 4662306a36Sopenharmony_ci#include <linux/net.h> 4762306a36Sopenharmony_ci#include <linux/export.h> 4862306a36Sopenharmony_ci#include <net/tcp.h> 4962306a36Sopenharmony_ci#include <trace/events/sock.h> 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#include <linux/uaccess.h> 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#include "heartbeat.h" 5462306a36Sopenharmony_ci#include "tcp.h" 5562306a36Sopenharmony_ci#include "nodemanager.h" 5662306a36Sopenharmony_ci#define MLOG_MASK_PREFIX ML_TCP 5762306a36Sopenharmony_ci#include "masklog.h" 5862306a36Sopenharmony_ci#include "quorum.h" 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#include "tcp_internal.h" 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define SC_NODEF_FMT "node %s (num %u) at %pI4:%u" 6362306a36Sopenharmony_ci#define SC_NODEF_ARGS(sc) sc->sc_node->nd_name, sc->sc_node->nd_num, \ 6462306a36Sopenharmony_ci &sc->sc_node->nd_ipv4_address, \ 6562306a36Sopenharmony_ci ntohs(sc->sc_node->nd_ipv4_port) 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* 6862306a36Sopenharmony_ci * In the following two log macros, the whitespace after the ',' just 6962306a36Sopenharmony_ci * before ##args is intentional. Otherwise, gcc 2.95 will eat the 7062306a36Sopenharmony_ci * previous token if args expands to nothing. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci#define msglog(hdr, fmt, args...) do { \ 7362306a36Sopenharmony_ci typeof(hdr) __hdr = (hdr); \ 7462306a36Sopenharmony_ci mlog(ML_MSG, "[mag %u len %u typ %u stat %d sys_stat %d " \ 7562306a36Sopenharmony_ci "key %08x num %u] " fmt, \ 7662306a36Sopenharmony_ci be16_to_cpu(__hdr->magic), be16_to_cpu(__hdr->data_len), \ 7762306a36Sopenharmony_ci be16_to_cpu(__hdr->msg_type), be32_to_cpu(__hdr->status), \ 7862306a36Sopenharmony_ci be32_to_cpu(__hdr->sys_status), be32_to_cpu(__hdr->key), \ 7962306a36Sopenharmony_ci be32_to_cpu(__hdr->msg_num) , ##args); \ 8062306a36Sopenharmony_ci} while (0) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#define sclog(sc, fmt, args...) do { \ 8362306a36Sopenharmony_ci typeof(sc) __sc = (sc); \ 8462306a36Sopenharmony_ci mlog(ML_SOCKET, "[sc %p refs %d sock %p node %u page %p " \ 8562306a36Sopenharmony_ci "pg_off %zu] " fmt, __sc, \ 8662306a36Sopenharmony_ci kref_read(&__sc->sc_kref), __sc->sc_sock, \ 8762306a36Sopenharmony_ci __sc->sc_node->nd_num, __sc->sc_page, __sc->sc_page_off , \ 8862306a36Sopenharmony_ci ##args); \ 8962306a36Sopenharmony_ci} while (0) 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic DEFINE_RWLOCK(o2net_handler_lock); 9262306a36Sopenharmony_cistatic struct rb_root o2net_handler_tree = RB_ROOT; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic struct o2net_node o2net_nodes[O2NM_MAX_NODES]; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* XXX someday we'll need better accounting */ 9762306a36Sopenharmony_cistatic struct socket *o2net_listen_sock; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* 10062306a36Sopenharmony_ci * listen work is only queued by the listening socket callbacks on the 10162306a36Sopenharmony_ci * o2net_wq. teardown detaches the callbacks before destroying the workqueue. 10262306a36Sopenharmony_ci * quorum work is queued as sock containers are shutdown.. stop_listening 10362306a36Sopenharmony_ci * tears down all the node's sock containers, preventing future shutdowns 10462306a36Sopenharmony_ci * and queued quroum work, before canceling delayed quorum work and 10562306a36Sopenharmony_ci * destroying the work queue. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_cistatic struct workqueue_struct *o2net_wq; 10862306a36Sopenharmony_cistatic struct work_struct o2net_listen_work; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic struct o2hb_callback_func o2net_hb_up, o2net_hb_down; 11162306a36Sopenharmony_ci#define O2NET_HB_PRI 0x1 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic struct o2net_handshake *o2net_hand; 11462306a36Sopenharmony_cistatic struct o2net_msg *o2net_keep_req, *o2net_keep_resp; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int o2net_sys_err_translations[O2NET_ERR_MAX] = 11762306a36Sopenharmony_ci {[O2NET_ERR_NONE] = 0, 11862306a36Sopenharmony_ci [O2NET_ERR_NO_HNDLR] = -ENOPROTOOPT, 11962306a36Sopenharmony_ci [O2NET_ERR_OVERFLOW] = -EOVERFLOW, 12062306a36Sopenharmony_ci [O2NET_ERR_DIED] = -EHOSTDOWN,}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* can't quite avoid *all* internal declarations :/ */ 12362306a36Sopenharmony_cistatic void o2net_sc_connect_completed(struct work_struct *work); 12462306a36Sopenharmony_cistatic void o2net_rx_until_empty(struct work_struct *work); 12562306a36Sopenharmony_cistatic void o2net_shutdown_sc(struct work_struct *work); 12662306a36Sopenharmony_cistatic void o2net_listen_data_ready(struct sock *sk); 12762306a36Sopenharmony_cistatic void o2net_sc_send_keep_req(struct work_struct *work); 12862306a36Sopenharmony_cistatic void o2net_idle_timer(struct timer_list *t); 12962306a36Sopenharmony_cistatic void o2net_sc_postpone_idle(struct o2net_sock_container *sc); 13062306a36Sopenharmony_cistatic void o2net_sc_reset_idle_timer(struct o2net_sock_container *sc); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 13362306a36Sopenharmony_cistatic void o2net_init_nst(struct o2net_send_tracking *nst, u32 msgtype, 13462306a36Sopenharmony_ci u32 msgkey, struct task_struct *task, u8 node) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci INIT_LIST_HEAD(&nst->st_net_debug_item); 13762306a36Sopenharmony_ci nst->st_task = task; 13862306a36Sopenharmony_ci nst->st_msg_type = msgtype; 13962306a36Sopenharmony_ci nst->st_msg_key = msgkey; 14062306a36Sopenharmony_ci nst->st_node = node; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic inline void o2net_set_nst_sock_time(struct o2net_send_tracking *nst) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci nst->st_sock_time = ktime_get(); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic inline void o2net_set_nst_send_time(struct o2net_send_tracking *nst) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci nst->st_send_time = ktime_get(); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic inline void o2net_set_nst_status_time(struct o2net_send_tracking *nst) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci nst->st_status_time = ktime_get(); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic inline void o2net_set_nst_sock_container(struct o2net_send_tracking *nst, 15962306a36Sopenharmony_ci struct o2net_sock_container *sc) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci nst->st_sc = sc; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic inline void o2net_set_nst_msg_id(struct o2net_send_tracking *nst, 16562306a36Sopenharmony_ci u32 msg_id) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci nst->st_id = msg_id; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic inline void o2net_set_sock_timer(struct o2net_sock_container *sc) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci sc->sc_tv_timer = ktime_get(); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic inline void o2net_set_data_ready_time(struct o2net_sock_container *sc) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci sc->sc_tv_data_ready = ktime_get(); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic inline void o2net_set_advance_start_time(struct o2net_sock_container *sc) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci sc->sc_tv_advance_start = ktime_get(); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic inline void o2net_set_advance_stop_time(struct o2net_sock_container *sc) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci sc->sc_tv_advance_stop = ktime_get(); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic inline void o2net_set_func_start_time(struct o2net_sock_container *sc) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci sc->sc_tv_func_start = ktime_get(); 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic inline void o2net_set_func_stop_time(struct o2net_sock_container *sc) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci sc->sc_tv_func_stop = ktime_get(); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci#else /* CONFIG_DEBUG_FS */ 20162306a36Sopenharmony_ci# define o2net_init_nst(a, b, c, d, e) 20262306a36Sopenharmony_ci# define o2net_set_nst_sock_time(a) 20362306a36Sopenharmony_ci# define o2net_set_nst_send_time(a) 20462306a36Sopenharmony_ci# define o2net_set_nst_status_time(a) 20562306a36Sopenharmony_ci# define o2net_set_nst_sock_container(a, b) 20662306a36Sopenharmony_ci# define o2net_set_nst_msg_id(a, b) 20762306a36Sopenharmony_ci# define o2net_set_sock_timer(a) 20862306a36Sopenharmony_ci# define o2net_set_data_ready_time(a) 20962306a36Sopenharmony_ci# define o2net_set_advance_start_time(a) 21062306a36Sopenharmony_ci# define o2net_set_advance_stop_time(a) 21162306a36Sopenharmony_ci# define o2net_set_func_start_time(a) 21262306a36Sopenharmony_ci# define o2net_set_func_stop_time(a) 21362306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci#ifdef CONFIG_OCFS2_FS_STATS 21662306a36Sopenharmony_cistatic ktime_t o2net_get_func_run_time(struct o2net_sock_container *sc) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci return ktime_sub(sc->sc_tv_func_stop, sc->sc_tv_func_start); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void o2net_update_send_stats(struct o2net_send_tracking *nst, 22262306a36Sopenharmony_ci struct o2net_sock_container *sc) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci sc->sc_tv_status_total = ktime_add(sc->sc_tv_status_total, 22562306a36Sopenharmony_ci ktime_sub(ktime_get(), 22662306a36Sopenharmony_ci nst->st_status_time)); 22762306a36Sopenharmony_ci sc->sc_tv_send_total = ktime_add(sc->sc_tv_send_total, 22862306a36Sopenharmony_ci ktime_sub(nst->st_status_time, 22962306a36Sopenharmony_ci nst->st_send_time)); 23062306a36Sopenharmony_ci sc->sc_tv_acquiry_total = ktime_add(sc->sc_tv_acquiry_total, 23162306a36Sopenharmony_ci ktime_sub(nst->st_send_time, 23262306a36Sopenharmony_ci nst->st_sock_time)); 23362306a36Sopenharmony_ci sc->sc_send_count++; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic void o2net_update_recv_stats(struct o2net_sock_container *sc) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci sc->sc_tv_process_total = ktime_add(sc->sc_tv_process_total, 23962306a36Sopenharmony_ci o2net_get_func_run_time(sc)); 24062306a36Sopenharmony_ci sc->sc_recv_count++; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci#else 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci# define o2net_update_send_stats(a, b) 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci# define o2net_update_recv_stats(sc) 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci#endif /* CONFIG_OCFS2_FS_STATS */ 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic inline unsigned int o2net_reconnect_delay(void) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci return o2nm_single_cluster->cl_reconnect_delay_ms; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic inline unsigned int o2net_keepalive_delay(void) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci return o2nm_single_cluster->cl_keepalive_delay_ms; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic inline unsigned int o2net_idle_timeout(void) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci return o2nm_single_cluster->cl_idle_timeout_ms; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic inline int o2net_sys_err_to_errno(enum o2net_system_error err) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci int trans; 26962306a36Sopenharmony_ci BUG_ON(err >= O2NET_ERR_MAX); 27062306a36Sopenharmony_ci trans = o2net_sys_err_translations[err]; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Just in case we mess up the translation table above */ 27362306a36Sopenharmony_ci BUG_ON(err != O2NET_ERR_NONE && trans == 0); 27462306a36Sopenharmony_ci return trans; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic struct o2net_node * o2net_nn_from_num(u8 node_num) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci BUG_ON(node_num >= ARRAY_SIZE(o2net_nodes)); 28062306a36Sopenharmony_ci return &o2net_nodes[node_num]; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic u8 o2net_num_from_nn(struct o2net_node *nn) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci BUG_ON(nn == NULL); 28662306a36Sopenharmony_ci return nn - o2net_nodes; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci/* ------------------------------------------------------------ */ 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic int o2net_prep_nsw(struct o2net_node *nn, struct o2net_status_wait *nsw) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci int ret; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci spin_lock(&nn->nn_lock); 29662306a36Sopenharmony_ci ret = idr_alloc(&nn->nn_status_idr, nsw, 0, 0, GFP_ATOMIC); 29762306a36Sopenharmony_ci if (ret >= 0) { 29862306a36Sopenharmony_ci nsw->ns_id = ret; 29962306a36Sopenharmony_ci list_add_tail(&nsw->ns_node_item, &nn->nn_status_list); 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci spin_unlock(&nn->nn_lock); 30262306a36Sopenharmony_ci if (ret < 0) 30362306a36Sopenharmony_ci return ret; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci init_waitqueue_head(&nsw->ns_wq); 30662306a36Sopenharmony_ci nsw->ns_sys_status = O2NET_ERR_NONE; 30762306a36Sopenharmony_ci nsw->ns_status = 0; 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic void o2net_complete_nsw_locked(struct o2net_node *nn, 31262306a36Sopenharmony_ci struct o2net_status_wait *nsw, 31362306a36Sopenharmony_ci enum o2net_system_error sys_status, 31462306a36Sopenharmony_ci s32 status) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci assert_spin_locked(&nn->nn_lock); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (!list_empty(&nsw->ns_node_item)) { 31962306a36Sopenharmony_ci list_del_init(&nsw->ns_node_item); 32062306a36Sopenharmony_ci nsw->ns_sys_status = sys_status; 32162306a36Sopenharmony_ci nsw->ns_status = status; 32262306a36Sopenharmony_ci idr_remove(&nn->nn_status_idr, nsw->ns_id); 32362306a36Sopenharmony_ci wake_up(&nsw->ns_wq); 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void o2net_complete_nsw(struct o2net_node *nn, 32862306a36Sopenharmony_ci struct o2net_status_wait *nsw, 32962306a36Sopenharmony_ci u64 id, enum o2net_system_error sys_status, 33062306a36Sopenharmony_ci s32 status) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci spin_lock(&nn->nn_lock); 33362306a36Sopenharmony_ci if (nsw == NULL) { 33462306a36Sopenharmony_ci if (id > INT_MAX) 33562306a36Sopenharmony_ci goto out; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci nsw = idr_find(&nn->nn_status_idr, id); 33862306a36Sopenharmony_ci if (nsw == NULL) 33962306a36Sopenharmony_ci goto out; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci o2net_complete_nsw_locked(nn, nsw, sys_status, status); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ciout: 34562306a36Sopenharmony_ci spin_unlock(&nn->nn_lock); 34662306a36Sopenharmony_ci return; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic void o2net_complete_nodes_nsw(struct o2net_node *nn) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct o2net_status_wait *nsw, *tmp; 35262306a36Sopenharmony_ci unsigned int num_kills = 0; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci assert_spin_locked(&nn->nn_lock); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci list_for_each_entry_safe(nsw, tmp, &nn->nn_status_list, ns_node_item) { 35762306a36Sopenharmony_ci o2net_complete_nsw_locked(nn, nsw, O2NET_ERR_DIED, 0); 35862306a36Sopenharmony_ci num_kills++; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci mlog(0, "completed %d messages for node %u\n", num_kills, 36262306a36Sopenharmony_ci o2net_num_from_nn(nn)); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int o2net_nsw_completed(struct o2net_node *nn, 36662306a36Sopenharmony_ci struct o2net_status_wait *nsw) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci int completed; 36962306a36Sopenharmony_ci spin_lock(&nn->nn_lock); 37062306a36Sopenharmony_ci completed = list_empty(&nsw->ns_node_item); 37162306a36Sopenharmony_ci spin_unlock(&nn->nn_lock); 37262306a36Sopenharmony_ci return completed; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci/* ------------------------------------------------------------ */ 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic void sc_kref_release(struct kref *kref) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct o2net_sock_container *sc = container_of(kref, 38062306a36Sopenharmony_ci struct o2net_sock_container, sc_kref); 38162306a36Sopenharmony_ci BUG_ON(timer_pending(&sc->sc_idle_timeout)); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci sclog(sc, "releasing\n"); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (sc->sc_sock) { 38662306a36Sopenharmony_ci sock_release(sc->sc_sock); 38762306a36Sopenharmony_ci sc->sc_sock = NULL; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci o2nm_undepend_item(&sc->sc_node->nd_item); 39162306a36Sopenharmony_ci o2nm_node_put(sc->sc_node); 39262306a36Sopenharmony_ci sc->sc_node = NULL; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci o2net_debug_del_sc(sc); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (sc->sc_page) 39762306a36Sopenharmony_ci __free_page(sc->sc_page); 39862306a36Sopenharmony_ci kfree(sc); 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic void sc_put(struct o2net_sock_container *sc) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci sclog(sc, "put\n"); 40462306a36Sopenharmony_ci kref_put(&sc->sc_kref, sc_kref_release); 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_cistatic void sc_get(struct o2net_sock_container *sc) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci sclog(sc, "get\n"); 40962306a36Sopenharmony_ci kref_get(&sc->sc_kref); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_cistatic struct o2net_sock_container *sc_alloc(struct o2nm_node *node) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct o2net_sock_container *sc, *ret = NULL; 41462306a36Sopenharmony_ci struct page *page = NULL; 41562306a36Sopenharmony_ci int status = 0; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci page = alloc_page(GFP_NOFS); 41862306a36Sopenharmony_ci sc = kzalloc(sizeof(*sc), GFP_NOFS); 41962306a36Sopenharmony_ci if (sc == NULL || page == NULL) 42062306a36Sopenharmony_ci goto out; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci kref_init(&sc->sc_kref); 42362306a36Sopenharmony_ci o2nm_node_get(node); 42462306a36Sopenharmony_ci sc->sc_node = node; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* pin the node item of the remote node */ 42762306a36Sopenharmony_ci status = o2nm_depend_item(&node->nd_item); 42862306a36Sopenharmony_ci if (status) { 42962306a36Sopenharmony_ci mlog_errno(status); 43062306a36Sopenharmony_ci o2nm_node_put(node); 43162306a36Sopenharmony_ci goto out; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci INIT_WORK(&sc->sc_connect_work, o2net_sc_connect_completed); 43462306a36Sopenharmony_ci INIT_WORK(&sc->sc_rx_work, o2net_rx_until_empty); 43562306a36Sopenharmony_ci INIT_WORK(&sc->sc_shutdown_work, o2net_shutdown_sc); 43662306a36Sopenharmony_ci INIT_DELAYED_WORK(&sc->sc_keepalive_work, o2net_sc_send_keep_req); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci timer_setup(&sc->sc_idle_timeout, o2net_idle_timer, 0); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci sclog(sc, "alloced\n"); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci ret = sc; 44362306a36Sopenharmony_ci sc->sc_page = page; 44462306a36Sopenharmony_ci o2net_debug_add_sc(sc); 44562306a36Sopenharmony_ci sc = NULL; 44662306a36Sopenharmony_ci page = NULL; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ciout: 44962306a36Sopenharmony_ci if (page) 45062306a36Sopenharmony_ci __free_page(page); 45162306a36Sopenharmony_ci kfree(sc); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return ret; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci/* ------------------------------------------------------------ */ 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic void o2net_sc_queue_work(struct o2net_sock_container *sc, 45962306a36Sopenharmony_ci struct work_struct *work) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci sc_get(sc); 46262306a36Sopenharmony_ci if (!queue_work(o2net_wq, work)) 46362306a36Sopenharmony_ci sc_put(sc); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_cistatic void o2net_sc_queue_delayed_work(struct o2net_sock_container *sc, 46662306a36Sopenharmony_ci struct delayed_work *work, 46762306a36Sopenharmony_ci int delay) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci sc_get(sc); 47062306a36Sopenharmony_ci if (!queue_delayed_work(o2net_wq, work, delay)) 47162306a36Sopenharmony_ci sc_put(sc); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_cistatic void o2net_sc_cancel_delayed_work(struct o2net_sock_container *sc, 47462306a36Sopenharmony_ci struct delayed_work *work) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci if (cancel_delayed_work(work)) 47762306a36Sopenharmony_ci sc_put(sc); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic atomic_t o2net_connected_peers = ATOMIC_INIT(0); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ciint o2net_num_connected_peers(void) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci return atomic_read(&o2net_connected_peers); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic void o2net_set_nn_state(struct o2net_node *nn, 48862306a36Sopenharmony_ci struct o2net_sock_container *sc, 48962306a36Sopenharmony_ci unsigned valid, int err) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci int was_valid = nn->nn_sc_valid; 49262306a36Sopenharmony_ci int was_err = nn->nn_persistent_error; 49362306a36Sopenharmony_ci struct o2net_sock_container *old_sc = nn->nn_sc; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci assert_spin_locked(&nn->nn_lock); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (old_sc && !sc) 49862306a36Sopenharmony_ci atomic_dec(&o2net_connected_peers); 49962306a36Sopenharmony_ci else if (!old_sc && sc) 50062306a36Sopenharmony_ci atomic_inc(&o2net_connected_peers); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* the node num comparison and single connect/accept path should stop 50362306a36Sopenharmony_ci * an non-null sc from being overwritten with another */ 50462306a36Sopenharmony_ci BUG_ON(sc && nn->nn_sc && nn->nn_sc != sc); 50562306a36Sopenharmony_ci mlog_bug_on_msg(err && valid, "err %d valid %u\n", err, valid); 50662306a36Sopenharmony_ci mlog_bug_on_msg(valid && !sc, "valid %u sc %p\n", valid, sc); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (was_valid && !valid && err == 0) 50962306a36Sopenharmony_ci err = -ENOTCONN; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci mlog(ML_CONN, "node %u sc: %p -> %p, valid %u -> %u, err %d -> %d\n", 51262306a36Sopenharmony_ci o2net_num_from_nn(nn), nn->nn_sc, sc, nn->nn_sc_valid, valid, 51362306a36Sopenharmony_ci nn->nn_persistent_error, err); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci nn->nn_sc = sc; 51662306a36Sopenharmony_ci nn->nn_sc_valid = valid ? 1 : 0; 51762306a36Sopenharmony_ci nn->nn_persistent_error = err; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* mirrors o2net_tx_can_proceed() */ 52062306a36Sopenharmony_ci if (nn->nn_persistent_error || nn->nn_sc_valid) 52162306a36Sopenharmony_ci wake_up(&nn->nn_sc_wq); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (was_valid && !was_err && nn->nn_persistent_error) { 52462306a36Sopenharmony_ci o2quo_conn_err(o2net_num_from_nn(nn)); 52562306a36Sopenharmony_ci queue_delayed_work(o2net_wq, &nn->nn_still_up, 52662306a36Sopenharmony_ci msecs_to_jiffies(O2NET_QUORUM_DELAY_MS)); 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (was_valid && !valid) { 53062306a36Sopenharmony_ci if (old_sc) 53162306a36Sopenharmony_ci printk(KERN_NOTICE "o2net: No longer connected to " 53262306a36Sopenharmony_ci SC_NODEF_FMT "\n", SC_NODEF_ARGS(old_sc)); 53362306a36Sopenharmony_ci o2net_complete_nodes_nsw(nn); 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (!was_valid && valid) { 53762306a36Sopenharmony_ci o2quo_conn_up(o2net_num_from_nn(nn)); 53862306a36Sopenharmony_ci cancel_delayed_work(&nn->nn_connect_expired); 53962306a36Sopenharmony_ci printk(KERN_NOTICE "o2net: %s " SC_NODEF_FMT "\n", 54062306a36Sopenharmony_ci o2nm_this_node() > sc->sc_node->nd_num ? 54162306a36Sopenharmony_ci "Connected to" : "Accepted connection from", 54262306a36Sopenharmony_ci SC_NODEF_ARGS(sc)); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* trigger the connecting worker func as long as we're not valid, 54662306a36Sopenharmony_ci * it will back off if it shouldn't connect. This can be called 54762306a36Sopenharmony_ci * from node config teardown and so needs to be careful about 54862306a36Sopenharmony_ci * the work queue actually being up. */ 54962306a36Sopenharmony_ci if (!valid && o2net_wq) { 55062306a36Sopenharmony_ci unsigned long delay; 55162306a36Sopenharmony_ci /* delay if we're within a RECONNECT_DELAY of the 55262306a36Sopenharmony_ci * last attempt */ 55362306a36Sopenharmony_ci delay = (nn->nn_last_connect_attempt + 55462306a36Sopenharmony_ci msecs_to_jiffies(o2net_reconnect_delay())) 55562306a36Sopenharmony_ci - jiffies; 55662306a36Sopenharmony_ci if (delay > msecs_to_jiffies(o2net_reconnect_delay())) 55762306a36Sopenharmony_ci delay = 0; 55862306a36Sopenharmony_ci mlog(ML_CONN, "queueing conn attempt in %lu jiffies\n", delay); 55962306a36Sopenharmony_ci queue_delayed_work(o2net_wq, &nn->nn_connect_work, delay); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* 56262306a36Sopenharmony_ci * Delay the expired work after idle timeout. 56362306a36Sopenharmony_ci * 56462306a36Sopenharmony_ci * We might have lots of failed connection attempts that run 56562306a36Sopenharmony_ci * through here but we only cancel the connect_expired work when 56662306a36Sopenharmony_ci * a connection attempt succeeds. So only the first enqueue of 56762306a36Sopenharmony_ci * the connect_expired work will do anything. The rest will see 56862306a36Sopenharmony_ci * that it's already queued and do nothing. 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_ci delay += msecs_to_jiffies(o2net_idle_timeout()); 57162306a36Sopenharmony_ci queue_delayed_work(o2net_wq, &nn->nn_connect_expired, delay); 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* keep track of the nn's sc ref for the caller */ 57562306a36Sopenharmony_ci if ((old_sc == NULL) && sc) 57662306a36Sopenharmony_ci sc_get(sc); 57762306a36Sopenharmony_ci if (old_sc && (old_sc != sc)) { 57862306a36Sopenharmony_ci o2net_sc_queue_work(old_sc, &old_sc->sc_shutdown_work); 57962306a36Sopenharmony_ci sc_put(old_sc); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci/* see o2net_register_callbacks() */ 58462306a36Sopenharmony_cistatic void o2net_data_ready(struct sock *sk) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci void (*ready)(struct sock *sk); 58762306a36Sopenharmony_ci struct o2net_sock_container *sc; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci trace_sk_data_ready(sk); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci read_lock_bh(&sk->sk_callback_lock); 59262306a36Sopenharmony_ci sc = sk->sk_user_data; 59362306a36Sopenharmony_ci if (sc) { 59462306a36Sopenharmony_ci sclog(sc, "data_ready hit\n"); 59562306a36Sopenharmony_ci o2net_set_data_ready_time(sc); 59662306a36Sopenharmony_ci o2net_sc_queue_work(sc, &sc->sc_rx_work); 59762306a36Sopenharmony_ci ready = sc->sc_data_ready; 59862306a36Sopenharmony_ci } else { 59962306a36Sopenharmony_ci ready = sk->sk_data_ready; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci read_unlock_bh(&sk->sk_callback_lock); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci ready(sk); 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci/* see o2net_register_callbacks() */ 60762306a36Sopenharmony_cistatic void o2net_state_change(struct sock *sk) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci void (*state_change)(struct sock *sk); 61062306a36Sopenharmony_ci struct o2net_sock_container *sc; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci read_lock_bh(&sk->sk_callback_lock); 61362306a36Sopenharmony_ci sc = sk->sk_user_data; 61462306a36Sopenharmony_ci if (sc == NULL) { 61562306a36Sopenharmony_ci state_change = sk->sk_state_change; 61662306a36Sopenharmony_ci goto out; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci sclog(sc, "state_change to %d\n", sk->sk_state); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci state_change = sc->sc_state_change; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci switch(sk->sk_state) { 62462306a36Sopenharmony_ci /* ignore connecting sockets as they make progress */ 62562306a36Sopenharmony_ci case TCP_SYN_SENT: 62662306a36Sopenharmony_ci case TCP_SYN_RECV: 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci case TCP_ESTABLISHED: 62962306a36Sopenharmony_ci o2net_sc_queue_work(sc, &sc->sc_connect_work); 63062306a36Sopenharmony_ci break; 63162306a36Sopenharmony_ci default: 63262306a36Sopenharmony_ci printk(KERN_INFO "o2net: Connection to " SC_NODEF_FMT 63362306a36Sopenharmony_ci " shutdown, state %d\n", 63462306a36Sopenharmony_ci SC_NODEF_ARGS(sc), sk->sk_state); 63562306a36Sopenharmony_ci o2net_sc_queue_work(sc, &sc->sc_shutdown_work); 63662306a36Sopenharmony_ci break; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ciout: 63962306a36Sopenharmony_ci read_unlock_bh(&sk->sk_callback_lock); 64062306a36Sopenharmony_ci state_change(sk); 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci/* 64462306a36Sopenharmony_ci * we register callbacks so we can queue work on events before calling 64562306a36Sopenharmony_ci * the original callbacks. our callbacks our careful to test user_data 64662306a36Sopenharmony_ci * to discover when they've reaced with o2net_unregister_callbacks(). 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_cistatic void o2net_register_callbacks(struct sock *sk, 64962306a36Sopenharmony_ci struct o2net_sock_container *sc) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci /* accepted sockets inherit the old listen socket data ready */ 65462306a36Sopenharmony_ci if (sk->sk_data_ready == o2net_listen_data_ready) { 65562306a36Sopenharmony_ci sk->sk_data_ready = sk->sk_user_data; 65662306a36Sopenharmony_ci sk->sk_user_data = NULL; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci BUG_ON(sk->sk_user_data != NULL); 66062306a36Sopenharmony_ci sk->sk_user_data = sc; 66162306a36Sopenharmony_ci sc_get(sc); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci sc->sc_data_ready = sk->sk_data_ready; 66462306a36Sopenharmony_ci sc->sc_state_change = sk->sk_state_change; 66562306a36Sopenharmony_ci sk->sk_data_ready = o2net_data_ready; 66662306a36Sopenharmony_ci sk->sk_state_change = o2net_state_change; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci mutex_init(&sc->sc_send_lock); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic int o2net_unregister_callbacks(struct sock *sk, 67462306a36Sopenharmony_ci struct o2net_sock_container *sc) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci int ret = 0; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 67962306a36Sopenharmony_ci if (sk->sk_user_data == sc) { 68062306a36Sopenharmony_ci ret = 1; 68162306a36Sopenharmony_ci sk->sk_user_data = NULL; 68262306a36Sopenharmony_ci sk->sk_data_ready = sc->sc_data_ready; 68362306a36Sopenharmony_ci sk->sk_state_change = sc->sc_state_change; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci return ret; 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci/* 69162306a36Sopenharmony_ci * this is a little helper that is called by callers who have seen a problem 69262306a36Sopenharmony_ci * with an sc and want to detach it from the nn if someone already hasn't beat 69362306a36Sopenharmony_ci * them to it. if an error is given then the shutdown will be persistent 69462306a36Sopenharmony_ci * and pending transmits will be canceled. 69562306a36Sopenharmony_ci */ 69662306a36Sopenharmony_cistatic void o2net_ensure_shutdown(struct o2net_node *nn, 69762306a36Sopenharmony_ci struct o2net_sock_container *sc, 69862306a36Sopenharmony_ci int err) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci spin_lock(&nn->nn_lock); 70162306a36Sopenharmony_ci if (nn->nn_sc == sc) 70262306a36Sopenharmony_ci o2net_set_nn_state(nn, NULL, 0, err); 70362306a36Sopenharmony_ci spin_unlock(&nn->nn_lock); 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci/* 70762306a36Sopenharmony_ci * This work queue function performs the blocking parts of socket shutdown. A 70862306a36Sopenharmony_ci * few paths lead here. set_nn_state will trigger this callback if it sees an 70962306a36Sopenharmony_ci * sc detached from the nn. state_change will also trigger this callback 71062306a36Sopenharmony_ci * directly when it sees errors. In that case we need to call set_nn_state 71162306a36Sopenharmony_ci * ourselves as state_change couldn't get the nn_lock and call set_nn_state 71262306a36Sopenharmony_ci * itself. 71362306a36Sopenharmony_ci */ 71462306a36Sopenharmony_cistatic void o2net_shutdown_sc(struct work_struct *work) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci struct o2net_sock_container *sc = 71762306a36Sopenharmony_ci container_of(work, struct o2net_sock_container, 71862306a36Sopenharmony_ci sc_shutdown_work); 71962306a36Sopenharmony_ci struct o2net_node *nn = o2net_nn_from_num(sc->sc_node->nd_num); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci sclog(sc, "shutting down\n"); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci /* drop the callbacks ref and call shutdown only once */ 72462306a36Sopenharmony_ci if (o2net_unregister_callbacks(sc->sc_sock->sk, sc)) { 72562306a36Sopenharmony_ci /* we shouldn't flush as we're in the thread, the 72662306a36Sopenharmony_ci * races with pending sc work structs are harmless */ 72762306a36Sopenharmony_ci del_timer_sync(&sc->sc_idle_timeout); 72862306a36Sopenharmony_ci o2net_sc_cancel_delayed_work(sc, &sc->sc_keepalive_work); 72962306a36Sopenharmony_ci sc_put(sc); 73062306a36Sopenharmony_ci kernel_sock_shutdown(sc->sc_sock, SHUT_RDWR); 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci /* not fatal so failed connects before the other guy has our 73462306a36Sopenharmony_ci * heartbeat can be retried */ 73562306a36Sopenharmony_ci o2net_ensure_shutdown(nn, sc, 0); 73662306a36Sopenharmony_ci sc_put(sc); 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci/* ------------------------------------------------------------ */ 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic int o2net_handler_cmp(struct o2net_msg_handler *nmh, u32 msg_type, 74262306a36Sopenharmony_ci u32 key) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci int ret = memcmp(&nmh->nh_key, &key, sizeof(key)); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci if (ret == 0) 74762306a36Sopenharmony_ci ret = memcmp(&nmh->nh_msg_type, &msg_type, sizeof(msg_type)); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci return ret; 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic struct o2net_msg_handler * 75362306a36Sopenharmony_cio2net_handler_tree_lookup(u32 msg_type, u32 key, struct rb_node ***ret_p, 75462306a36Sopenharmony_ci struct rb_node **ret_parent) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct rb_node **p = &o2net_handler_tree.rb_node; 75762306a36Sopenharmony_ci struct rb_node *parent = NULL; 75862306a36Sopenharmony_ci struct o2net_msg_handler *nmh, *ret = NULL; 75962306a36Sopenharmony_ci int cmp; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci while (*p) { 76262306a36Sopenharmony_ci parent = *p; 76362306a36Sopenharmony_ci nmh = rb_entry(parent, struct o2net_msg_handler, nh_node); 76462306a36Sopenharmony_ci cmp = o2net_handler_cmp(nmh, msg_type, key); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (cmp < 0) 76762306a36Sopenharmony_ci p = &(*p)->rb_left; 76862306a36Sopenharmony_ci else if (cmp > 0) 76962306a36Sopenharmony_ci p = &(*p)->rb_right; 77062306a36Sopenharmony_ci else { 77162306a36Sopenharmony_ci ret = nmh; 77262306a36Sopenharmony_ci break; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (ret_p != NULL) 77762306a36Sopenharmony_ci *ret_p = p; 77862306a36Sopenharmony_ci if (ret_parent != NULL) 77962306a36Sopenharmony_ci *ret_parent = parent; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci return ret; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic void o2net_handler_kref_release(struct kref *kref) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci struct o2net_msg_handler *nmh; 78762306a36Sopenharmony_ci nmh = container_of(kref, struct o2net_msg_handler, nh_kref); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci kfree(nmh); 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic void o2net_handler_put(struct o2net_msg_handler *nmh) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci kref_put(&nmh->nh_kref, o2net_handler_kref_release); 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci/* max_len is protection for the handler func. incoming messages won't 79862306a36Sopenharmony_ci * be given to the handler if their payload is longer than the max. */ 79962306a36Sopenharmony_ciint o2net_register_handler(u32 msg_type, u32 key, u32 max_len, 80062306a36Sopenharmony_ci o2net_msg_handler_func *func, void *data, 80162306a36Sopenharmony_ci o2net_post_msg_handler_func *post_func, 80262306a36Sopenharmony_ci struct list_head *unreg_list) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci struct o2net_msg_handler *nmh = NULL; 80562306a36Sopenharmony_ci struct rb_node **p, *parent; 80662306a36Sopenharmony_ci int ret = 0; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (max_len > O2NET_MAX_PAYLOAD_BYTES) { 80962306a36Sopenharmony_ci mlog(0, "max_len for message handler out of range: %u\n", 81062306a36Sopenharmony_ci max_len); 81162306a36Sopenharmony_ci ret = -EINVAL; 81262306a36Sopenharmony_ci goto out; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (!msg_type) { 81662306a36Sopenharmony_ci mlog(0, "no message type provided: %u, %p\n", msg_type, func); 81762306a36Sopenharmony_ci ret = -EINVAL; 81862306a36Sopenharmony_ci goto out; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci if (!func) { 82262306a36Sopenharmony_ci mlog(0, "no message handler provided: %u, %p\n", 82362306a36Sopenharmony_ci msg_type, func); 82462306a36Sopenharmony_ci ret = -EINVAL; 82562306a36Sopenharmony_ci goto out; 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci nmh = kzalloc(sizeof(struct o2net_msg_handler), GFP_NOFS); 82962306a36Sopenharmony_ci if (nmh == NULL) { 83062306a36Sopenharmony_ci ret = -ENOMEM; 83162306a36Sopenharmony_ci goto out; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci nmh->nh_func = func; 83562306a36Sopenharmony_ci nmh->nh_func_data = data; 83662306a36Sopenharmony_ci nmh->nh_post_func = post_func; 83762306a36Sopenharmony_ci nmh->nh_msg_type = msg_type; 83862306a36Sopenharmony_ci nmh->nh_max_len = max_len; 83962306a36Sopenharmony_ci nmh->nh_key = key; 84062306a36Sopenharmony_ci /* the tree and list get this ref.. they're both removed in 84162306a36Sopenharmony_ci * unregister when this ref is dropped */ 84262306a36Sopenharmony_ci kref_init(&nmh->nh_kref); 84362306a36Sopenharmony_ci INIT_LIST_HEAD(&nmh->nh_unregister_item); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci write_lock(&o2net_handler_lock); 84662306a36Sopenharmony_ci if (o2net_handler_tree_lookup(msg_type, key, &p, &parent)) 84762306a36Sopenharmony_ci ret = -EEXIST; 84862306a36Sopenharmony_ci else { 84962306a36Sopenharmony_ci rb_link_node(&nmh->nh_node, parent, p); 85062306a36Sopenharmony_ci rb_insert_color(&nmh->nh_node, &o2net_handler_tree); 85162306a36Sopenharmony_ci list_add_tail(&nmh->nh_unregister_item, unreg_list); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci mlog(ML_TCP, "registered handler func %p type %u key %08x\n", 85462306a36Sopenharmony_ci func, msg_type, key); 85562306a36Sopenharmony_ci /* we've had some trouble with handlers seemingly vanishing. */ 85662306a36Sopenharmony_ci mlog_bug_on_msg(o2net_handler_tree_lookup(msg_type, key, &p, 85762306a36Sopenharmony_ci &parent) == NULL, 85862306a36Sopenharmony_ci "couldn't find handler we *just* registered " 85962306a36Sopenharmony_ci "for type %u key %08x\n", msg_type, key); 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci write_unlock(&o2net_handler_lock); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ciout: 86462306a36Sopenharmony_ci if (ret) 86562306a36Sopenharmony_ci kfree(nmh); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci return ret; 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(o2net_register_handler); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_civoid o2net_unregister_handler_list(struct list_head *list) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci struct o2net_msg_handler *nmh, *n; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci write_lock(&o2net_handler_lock); 87662306a36Sopenharmony_ci list_for_each_entry_safe(nmh, n, list, nh_unregister_item) { 87762306a36Sopenharmony_ci mlog(ML_TCP, "unregistering handler func %p type %u key %08x\n", 87862306a36Sopenharmony_ci nmh->nh_func, nmh->nh_msg_type, nmh->nh_key); 87962306a36Sopenharmony_ci rb_erase(&nmh->nh_node, &o2net_handler_tree); 88062306a36Sopenharmony_ci list_del_init(&nmh->nh_unregister_item); 88162306a36Sopenharmony_ci kref_put(&nmh->nh_kref, o2net_handler_kref_release); 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci write_unlock(&o2net_handler_lock); 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(o2net_unregister_handler_list); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_cistatic struct o2net_msg_handler *o2net_handler_get(u32 msg_type, u32 key) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci struct o2net_msg_handler *nmh; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci read_lock(&o2net_handler_lock); 89262306a36Sopenharmony_ci nmh = o2net_handler_tree_lookup(msg_type, key, NULL, NULL); 89362306a36Sopenharmony_ci if (nmh) 89462306a36Sopenharmony_ci kref_get(&nmh->nh_kref); 89562306a36Sopenharmony_ci read_unlock(&o2net_handler_lock); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci return nmh; 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci/* ------------------------------------------------------------ */ 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_cistatic int o2net_recv_tcp_msg(struct socket *sock, void *data, size_t len) 90362306a36Sopenharmony_ci{ 90462306a36Sopenharmony_ci struct kvec vec = { .iov_len = len, .iov_base = data, }; 90562306a36Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT, }; 90662306a36Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, ITER_DEST, &vec, 1, len); 90762306a36Sopenharmony_ci return sock_recvmsg(sock, &msg, MSG_DONTWAIT); 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_cistatic int o2net_send_tcp_msg(struct socket *sock, struct kvec *vec, 91162306a36Sopenharmony_ci size_t veclen, size_t total) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci int ret; 91462306a36Sopenharmony_ci struct msghdr msg = {.msg_flags = 0,}; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (sock == NULL) { 91762306a36Sopenharmony_ci ret = -EINVAL; 91862306a36Sopenharmony_ci goto out; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci ret = kernel_sendmsg(sock, &msg, vec, veclen, total); 92262306a36Sopenharmony_ci if (likely(ret == total)) 92362306a36Sopenharmony_ci return 0; 92462306a36Sopenharmony_ci mlog(ML_ERROR, "sendmsg returned %d instead of %zu\n", ret, total); 92562306a36Sopenharmony_ci if (ret >= 0) 92662306a36Sopenharmony_ci ret = -EPIPE; /* should be smarter, I bet */ 92762306a36Sopenharmony_ciout: 92862306a36Sopenharmony_ci mlog(0, "returning error: %d\n", ret); 92962306a36Sopenharmony_ci return ret; 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_cistatic void o2net_sendpage(struct o2net_sock_container *sc, 93362306a36Sopenharmony_ci void *virt, size_t size) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci struct o2net_node *nn = o2net_nn_from_num(sc->sc_node->nd_num); 93662306a36Sopenharmony_ci struct msghdr msg = {}; 93762306a36Sopenharmony_ci struct bio_vec bv; 93862306a36Sopenharmony_ci ssize_t ret; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci bvec_set_virt(&bv, virt, size); 94162306a36Sopenharmony_ci iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bv, 1, size); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci while (1) { 94462306a36Sopenharmony_ci msg.msg_flags = MSG_DONTWAIT | MSG_SPLICE_PAGES; 94562306a36Sopenharmony_ci mutex_lock(&sc->sc_send_lock); 94662306a36Sopenharmony_ci ret = sock_sendmsg(sc->sc_sock, &msg); 94762306a36Sopenharmony_ci mutex_unlock(&sc->sc_send_lock); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci if (ret == size) 95062306a36Sopenharmony_ci break; 95162306a36Sopenharmony_ci if (ret == (ssize_t)-EAGAIN) { 95262306a36Sopenharmony_ci mlog(0, "sendpage of size %zu to " SC_NODEF_FMT 95362306a36Sopenharmony_ci " returned EAGAIN\n", size, SC_NODEF_ARGS(sc)); 95462306a36Sopenharmony_ci cond_resched(); 95562306a36Sopenharmony_ci continue; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci mlog(ML_ERROR, "sendpage of size %zu to " SC_NODEF_FMT 95862306a36Sopenharmony_ci " failed with %zd\n", size, SC_NODEF_ARGS(sc), ret); 95962306a36Sopenharmony_ci o2net_ensure_shutdown(nn, sc, 0); 96062306a36Sopenharmony_ci break; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_cistatic void o2net_init_msg(struct o2net_msg *msg, u16 data_len, u16 msg_type, u32 key) 96562306a36Sopenharmony_ci{ 96662306a36Sopenharmony_ci memset(msg, 0, sizeof(struct o2net_msg)); 96762306a36Sopenharmony_ci msg->magic = cpu_to_be16(O2NET_MSG_MAGIC); 96862306a36Sopenharmony_ci msg->data_len = cpu_to_be16(data_len); 96962306a36Sopenharmony_ci msg->msg_type = cpu_to_be16(msg_type); 97062306a36Sopenharmony_ci msg->sys_status = cpu_to_be32(O2NET_ERR_NONE); 97162306a36Sopenharmony_ci msg->status = 0; 97262306a36Sopenharmony_ci msg->key = cpu_to_be32(key); 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cistatic int o2net_tx_can_proceed(struct o2net_node *nn, 97662306a36Sopenharmony_ci struct o2net_sock_container **sc_ret, 97762306a36Sopenharmony_ci int *error) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci int ret = 0; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci spin_lock(&nn->nn_lock); 98262306a36Sopenharmony_ci if (nn->nn_persistent_error) { 98362306a36Sopenharmony_ci ret = 1; 98462306a36Sopenharmony_ci *sc_ret = NULL; 98562306a36Sopenharmony_ci *error = nn->nn_persistent_error; 98662306a36Sopenharmony_ci } else if (nn->nn_sc_valid) { 98762306a36Sopenharmony_ci kref_get(&nn->nn_sc->sc_kref); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci ret = 1; 99062306a36Sopenharmony_ci *sc_ret = nn->nn_sc; 99162306a36Sopenharmony_ci *error = 0; 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci spin_unlock(&nn->nn_lock); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci return ret; 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci/* Get a map of all nodes to which this node is currently connected to */ 99962306a36Sopenharmony_civoid o2net_fill_node_map(unsigned long *map, unsigned int bits) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci struct o2net_sock_container *sc; 100262306a36Sopenharmony_ci int node, ret; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci bitmap_zero(map, bits); 100562306a36Sopenharmony_ci for (node = 0; node < O2NM_MAX_NODES; ++node) { 100662306a36Sopenharmony_ci if (!o2net_tx_can_proceed(o2net_nn_from_num(node), &sc, &ret)) 100762306a36Sopenharmony_ci continue; 100862306a36Sopenharmony_ci if (!ret) { 100962306a36Sopenharmony_ci set_bit(node, map); 101062306a36Sopenharmony_ci sc_put(sc); 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(o2net_fill_node_map); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ciint o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, 101762306a36Sopenharmony_ci size_t caller_veclen, u8 target_node, int *status) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci int ret = 0; 102062306a36Sopenharmony_ci struct o2net_msg *msg = NULL; 102162306a36Sopenharmony_ci size_t veclen, caller_bytes = 0; 102262306a36Sopenharmony_ci struct kvec *vec = NULL; 102362306a36Sopenharmony_ci struct o2net_sock_container *sc = NULL; 102462306a36Sopenharmony_ci struct o2net_node *nn = o2net_nn_from_num(target_node); 102562306a36Sopenharmony_ci struct o2net_status_wait nsw = { 102662306a36Sopenharmony_ci .ns_node_item = LIST_HEAD_INIT(nsw.ns_node_item), 102762306a36Sopenharmony_ci }; 102862306a36Sopenharmony_ci struct o2net_send_tracking nst; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci o2net_init_nst(&nst, msg_type, key, current, target_node); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (o2net_wq == NULL) { 103362306a36Sopenharmony_ci mlog(0, "attempt to tx without o2netd running\n"); 103462306a36Sopenharmony_ci ret = -ESRCH; 103562306a36Sopenharmony_ci goto out; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci if (caller_veclen == 0) { 103962306a36Sopenharmony_ci mlog(0, "bad kvec array length\n"); 104062306a36Sopenharmony_ci ret = -EINVAL; 104162306a36Sopenharmony_ci goto out; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci caller_bytes = iov_length((struct iovec *)caller_vec, caller_veclen); 104562306a36Sopenharmony_ci if (caller_bytes > O2NET_MAX_PAYLOAD_BYTES) { 104662306a36Sopenharmony_ci mlog(0, "total payload len %zu too large\n", caller_bytes); 104762306a36Sopenharmony_ci ret = -EINVAL; 104862306a36Sopenharmony_ci goto out; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci if (target_node == o2nm_this_node()) { 105262306a36Sopenharmony_ci ret = -ELOOP; 105362306a36Sopenharmony_ci goto out; 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci o2net_debug_add_nst(&nst); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci o2net_set_nst_sock_time(&nst); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci wait_event(nn->nn_sc_wq, o2net_tx_can_proceed(nn, &sc, &ret)); 106162306a36Sopenharmony_ci if (ret) 106262306a36Sopenharmony_ci goto out; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci o2net_set_nst_sock_container(&nst, sc); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci veclen = caller_veclen + 1; 106762306a36Sopenharmony_ci vec = kmalloc_array(veclen, sizeof(struct kvec), GFP_ATOMIC); 106862306a36Sopenharmony_ci if (vec == NULL) { 106962306a36Sopenharmony_ci mlog(0, "failed to %zu element kvec!\n", veclen); 107062306a36Sopenharmony_ci ret = -ENOMEM; 107162306a36Sopenharmony_ci goto out; 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci msg = kmalloc(sizeof(struct o2net_msg), GFP_ATOMIC); 107562306a36Sopenharmony_ci if (!msg) { 107662306a36Sopenharmony_ci mlog(0, "failed to allocate a o2net_msg!\n"); 107762306a36Sopenharmony_ci ret = -ENOMEM; 107862306a36Sopenharmony_ci goto out; 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci o2net_init_msg(msg, caller_bytes, msg_type, key); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci vec[0].iov_len = sizeof(struct o2net_msg); 108462306a36Sopenharmony_ci vec[0].iov_base = msg; 108562306a36Sopenharmony_ci memcpy(&vec[1], caller_vec, caller_veclen * sizeof(struct kvec)); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci ret = o2net_prep_nsw(nn, &nsw); 108862306a36Sopenharmony_ci if (ret) 108962306a36Sopenharmony_ci goto out; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci msg->msg_num = cpu_to_be32(nsw.ns_id); 109262306a36Sopenharmony_ci o2net_set_nst_msg_id(&nst, nsw.ns_id); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci o2net_set_nst_send_time(&nst); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* finally, convert the message header to network byte-order 109762306a36Sopenharmony_ci * and send */ 109862306a36Sopenharmony_ci mutex_lock(&sc->sc_send_lock); 109962306a36Sopenharmony_ci ret = o2net_send_tcp_msg(sc->sc_sock, vec, veclen, 110062306a36Sopenharmony_ci sizeof(struct o2net_msg) + caller_bytes); 110162306a36Sopenharmony_ci mutex_unlock(&sc->sc_send_lock); 110262306a36Sopenharmony_ci msglog(msg, "sending returned %d\n", ret); 110362306a36Sopenharmony_ci if (ret < 0) { 110462306a36Sopenharmony_ci mlog(0, "error returned from o2net_send_tcp_msg=%d\n", ret); 110562306a36Sopenharmony_ci goto out; 110662306a36Sopenharmony_ci } 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci /* wait on other node's handler */ 110962306a36Sopenharmony_ci o2net_set_nst_status_time(&nst); 111062306a36Sopenharmony_ci wait_event(nsw.ns_wq, o2net_nsw_completed(nn, &nsw)); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci o2net_update_send_stats(&nst, sc); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci /* Note that we avoid overwriting the callers status return 111562306a36Sopenharmony_ci * variable if a system error was reported on the other 111662306a36Sopenharmony_ci * side. Callers beware. */ 111762306a36Sopenharmony_ci ret = o2net_sys_err_to_errno(nsw.ns_sys_status); 111862306a36Sopenharmony_ci if (status && !ret) 111962306a36Sopenharmony_ci *status = nsw.ns_status; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci mlog(0, "woken, returning system status %d, user status %d\n", 112262306a36Sopenharmony_ci ret, nsw.ns_status); 112362306a36Sopenharmony_ciout: 112462306a36Sopenharmony_ci o2net_debug_del_nst(&nst); /* must be before dropping sc and node */ 112562306a36Sopenharmony_ci if (sc) 112662306a36Sopenharmony_ci sc_put(sc); 112762306a36Sopenharmony_ci kfree(vec); 112862306a36Sopenharmony_ci kfree(msg); 112962306a36Sopenharmony_ci o2net_complete_nsw(nn, &nsw, 0, 0, 0); 113062306a36Sopenharmony_ci return ret; 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(o2net_send_message_vec); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ciint o2net_send_message(u32 msg_type, u32 key, void *data, u32 len, 113562306a36Sopenharmony_ci u8 target_node, int *status) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci struct kvec vec = { 113862306a36Sopenharmony_ci .iov_base = data, 113962306a36Sopenharmony_ci .iov_len = len, 114062306a36Sopenharmony_ci }; 114162306a36Sopenharmony_ci return o2net_send_message_vec(msg_type, key, &vec, 1, 114262306a36Sopenharmony_ci target_node, status); 114362306a36Sopenharmony_ci} 114462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(o2net_send_message); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_cistatic int o2net_send_status_magic(struct socket *sock, struct o2net_msg *hdr, 114762306a36Sopenharmony_ci enum o2net_system_error syserr, int err) 114862306a36Sopenharmony_ci{ 114962306a36Sopenharmony_ci struct kvec vec = { 115062306a36Sopenharmony_ci .iov_base = hdr, 115162306a36Sopenharmony_ci .iov_len = sizeof(struct o2net_msg), 115262306a36Sopenharmony_ci }; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci BUG_ON(syserr >= O2NET_ERR_MAX); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci /* leave other fields intact from the incoming message, msg_num 115762306a36Sopenharmony_ci * in particular */ 115862306a36Sopenharmony_ci hdr->sys_status = cpu_to_be32(syserr); 115962306a36Sopenharmony_ci hdr->status = cpu_to_be32(err); 116062306a36Sopenharmony_ci hdr->magic = cpu_to_be16(O2NET_MSG_STATUS_MAGIC); // twiddle the magic 116162306a36Sopenharmony_ci hdr->data_len = 0; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci msglog(hdr, "about to send status magic %d\n", err); 116462306a36Sopenharmony_ci /* hdr has been in host byteorder this whole time */ 116562306a36Sopenharmony_ci return o2net_send_tcp_msg(sock, &vec, 1, sizeof(struct o2net_msg)); 116662306a36Sopenharmony_ci} 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci/* this returns -errno if the header was unknown or too large, etc. 116962306a36Sopenharmony_ci * after this is called the buffer us reused for the next message */ 117062306a36Sopenharmony_cistatic int o2net_process_message(struct o2net_sock_container *sc, 117162306a36Sopenharmony_ci struct o2net_msg *hdr) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci struct o2net_node *nn = o2net_nn_from_num(sc->sc_node->nd_num); 117462306a36Sopenharmony_ci int ret = 0, handler_status; 117562306a36Sopenharmony_ci enum o2net_system_error syserr; 117662306a36Sopenharmony_ci struct o2net_msg_handler *nmh = NULL; 117762306a36Sopenharmony_ci void *ret_data = NULL; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci msglog(hdr, "processing message\n"); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci o2net_sc_postpone_idle(sc); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci switch(be16_to_cpu(hdr->magic)) { 118462306a36Sopenharmony_ci case O2NET_MSG_STATUS_MAGIC: 118562306a36Sopenharmony_ci /* special type for returning message status */ 118662306a36Sopenharmony_ci o2net_complete_nsw(nn, NULL, 118762306a36Sopenharmony_ci be32_to_cpu(hdr->msg_num), 118862306a36Sopenharmony_ci be32_to_cpu(hdr->sys_status), 118962306a36Sopenharmony_ci be32_to_cpu(hdr->status)); 119062306a36Sopenharmony_ci goto out; 119162306a36Sopenharmony_ci case O2NET_MSG_KEEP_REQ_MAGIC: 119262306a36Sopenharmony_ci o2net_sendpage(sc, o2net_keep_resp, 119362306a36Sopenharmony_ci sizeof(*o2net_keep_resp)); 119462306a36Sopenharmony_ci goto out; 119562306a36Sopenharmony_ci case O2NET_MSG_KEEP_RESP_MAGIC: 119662306a36Sopenharmony_ci goto out; 119762306a36Sopenharmony_ci case O2NET_MSG_MAGIC: 119862306a36Sopenharmony_ci break; 119962306a36Sopenharmony_ci default: 120062306a36Sopenharmony_ci msglog(hdr, "bad magic\n"); 120162306a36Sopenharmony_ci ret = -EINVAL; 120262306a36Sopenharmony_ci goto out; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci /* find a handler for it */ 120662306a36Sopenharmony_ci handler_status = 0; 120762306a36Sopenharmony_ci nmh = o2net_handler_get(be16_to_cpu(hdr->msg_type), 120862306a36Sopenharmony_ci be32_to_cpu(hdr->key)); 120962306a36Sopenharmony_ci if (!nmh) { 121062306a36Sopenharmony_ci mlog(ML_TCP, "couldn't find handler for type %u key %08x\n", 121162306a36Sopenharmony_ci be16_to_cpu(hdr->msg_type), be32_to_cpu(hdr->key)); 121262306a36Sopenharmony_ci syserr = O2NET_ERR_NO_HNDLR; 121362306a36Sopenharmony_ci goto out_respond; 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci syserr = O2NET_ERR_NONE; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci if (be16_to_cpu(hdr->data_len) > nmh->nh_max_len) 121962306a36Sopenharmony_ci syserr = O2NET_ERR_OVERFLOW; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci if (syserr != O2NET_ERR_NONE) 122262306a36Sopenharmony_ci goto out_respond; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci o2net_set_func_start_time(sc); 122562306a36Sopenharmony_ci sc->sc_msg_key = be32_to_cpu(hdr->key); 122662306a36Sopenharmony_ci sc->sc_msg_type = be16_to_cpu(hdr->msg_type); 122762306a36Sopenharmony_ci handler_status = (nmh->nh_func)(hdr, sizeof(struct o2net_msg) + 122862306a36Sopenharmony_ci be16_to_cpu(hdr->data_len), 122962306a36Sopenharmony_ci nmh->nh_func_data, &ret_data); 123062306a36Sopenharmony_ci o2net_set_func_stop_time(sc); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci o2net_update_recv_stats(sc); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ciout_respond: 123562306a36Sopenharmony_ci /* this destroys the hdr, so don't use it after this */ 123662306a36Sopenharmony_ci mutex_lock(&sc->sc_send_lock); 123762306a36Sopenharmony_ci ret = o2net_send_status_magic(sc->sc_sock, hdr, syserr, 123862306a36Sopenharmony_ci handler_status); 123962306a36Sopenharmony_ci mutex_unlock(&sc->sc_send_lock); 124062306a36Sopenharmony_ci hdr = NULL; 124162306a36Sopenharmony_ci mlog(0, "sending handler status %d, syserr %d returned %d\n", 124262306a36Sopenharmony_ci handler_status, syserr, ret); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci if (nmh) { 124562306a36Sopenharmony_ci BUG_ON(ret_data != NULL && nmh->nh_post_func == NULL); 124662306a36Sopenharmony_ci if (nmh->nh_post_func) 124762306a36Sopenharmony_ci (nmh->nh_post_func)(handler_status, nmh->nh_func_data, 124862306a36Sopenharmony_ci ret_data); 124962306a36Sopenharmony_ci } 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ciout: 125262306a36Sopenharmony_ci if (nmh) 125362306a36Sopenharmony_ci o2net_handler_put(nmh); 125462306a36Sopenharmony_ci return ret; 125562306a36Sopenharmony_ci} 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_cistatic int o2net_check_handshake(struct o2net_sock_container *sc) 125862306a36Sopenharmony_ci{ 125962306a36Sopenharmony_ci struct o2net_handshake *hand = page_address(sc->sc_page); 126062306a36Sopenharmony_ci struct o2net_node *nn = o2net_nn_from_num(sc->sc_node->nd_num); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci if (hand->protocol_version != cpu_to_be64(O2NET_PROTOCOL_VERSION)) { 126362306a36Sopenharmony_ci printk(KERN_NOTICE "o2net: " SC_NODEF_FMT " Advertised net " 126462306a36Sopenharmony_ci "protocol version %llu but %llu is required. " 126562306a36Sopenharmony_ci "Disconnecting.\n", SC_NODEF_ARGS(sc), 126662306a36Sopenharmony_ci (unsigned long long)be64_to_cpu(hand->protocol_version), 126762306a36Sopenharmony_ci O2NET_PROTOCOL_VERSION); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci /* don't bother reconnecting if its the wrong version. */ 127062306a36Sopenharmony_ci o2net_ensure_shutdown(nn, sc, -ENOTCONN); 127162306a36Sopenharmony_ci return -1; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci /* 127562306a36Sopenharmony_ci * Ensure timeouts are consistent with other nodes, otherwise 127662306a36Sopenharmony_ci * we can end up with one node thinking that the other must be down, 127762306a36Sopenharmony_ci * but isn't. This can ultimately cause corruption. 127862306a36Sopenharmony_ci */ 127962306a36Sopenharmony_ci if (be32_to_cpu(hand->o2net_idle_timeout_ms) != 128062306a36Sopenharmony_ci o2net_idle_timeout()) { 128162306a36Sopenharmony_ci printk(KERN_NOTICE "o2net: " SC_NODEF_FMT " uses a network " 128262306a36Sopenharmony_ci "idle timeout of %u ms, but we use %u ms locally. " 128362306a36Sopenharmony_ci "Disconnecting.\n", SC_NODEF_ARGS(sc), 128462306a36Sopenharmony_ci be32_to_cpu(hand->o2net_idle_timeout_ms), 128562306a36Sopenharmony_ci o2net_idle_timeout()); 128662306a36Sopenharmony_ci o2net_ensure_shutdown(nn, sc, -ENOTCONN); 128762306a36Sopenharmony_ci return -1; 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci if (be32_to_cpu(hand->o2net_keepalive_delay_ms) != 129162306a36Sopenharmony_ci o2net_keepalive_delay()) { 129262306a36Sopenharmony_ci printk(KERN_NOTICE "o2net: " SC_NODEF_FMT " uses a keepalive " 129362306a36Sopenharmony_ci "delay of %u ms, but we use %u ms locally. " 129462306a36Sopenharmony_ci "Disconnecting.\n", SC_NODEF_ARGS(sc), 129562306a36Sopenharmony_ci be32_to_cpu(hand->o2net_keepalive_delay_ms), 129662306a36Sopenharmony_ci o2net_keepalive_delay()); 129762306a36Sopenharmony_ci o2net_ensure_shutdown(nn, sc, -ENOTCONN); 129862306a36Sopenharmony_ci return -1; 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci if (be32_to_cpu(hand->o2hb_heartbeat_timeout_ms) != 130262306a36Sopenharmony_ci O2HB_MAX_WRITE_TIMEOUT_MS) { 130362306a36Sopenharmony_ci printk(KERN_NOTICE "o2net: " SC_NODEF_FMT " uses a heartbeat " 130462306a36Sopenharmony_ci "timeout of %u ms, but we use %u ms locally. " 130562306a36Sopenharmony_ci "Disconnecting.\n", SC_NODEF_ARGS(sc), 130662306a36Sopenharmony_ci be32_to_cpu(hand->o2hb_heartbeat_timeout_ms), 130762306a36Sopenharmony_ci O2HB_MAX_WRITE_TIMEOUT_MS); 130862306a36Sopenharmony_ci o2net_ensure_shutdown(nn, sc, -ENOTCONN); 130962306a36Sopenharmony_ci return -1; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci sc->sc_handshake_ok = 1; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci spin_lock(&nn->nn_lock); 131562306a36Sopenharmony_ci /* set valid and queue the idle timers only if it hasn't been 131662306a36Sopenharmony_ci * shut down already */ 131762306a36Sopenharmony_ci if (nn->nn_sc == sc) { 131862306a36Sopenharmony_ci o2net_sc_reset_idle_timer(sc); 131962306a36Sopenharmony_ci atomic_set(&nn->nn_timeout, 0); 132062306a36Sopenharmony_ci o2net_set_nn_state(nn, sc, 1, 0); 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci spin_unlock(&nn->nn_lock); 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci /* shift everything up as though it wasn't there */ 132562306a36Sopenharmony_ci sc->sc_page_off -= sizeof(struct o2net_handshake); 132662306a36Sopenharmony_ci if (sc->sc_page_off) 132762306a36Sopenharmony_ci memmove(hand, hand + 1, sc->sc_page_off); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci return 0; 133062306a36Sopenharmony_ci} 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci/* this demuxes the queued rx bytes into header or payload bits and calls 133362306a36Sopenharmony_ci * handlers as each full message is read off the socket. it returns -error, 133462306a36Sopenharmony_ci * == 0 eof, or > 0 for progress made.*/ 133562306a36Sopenharmony_cistatic int o2net_advance_rx(struct o2net_sock_container *sc) 133662306a36Sopenharmony_ci{ 133762306a36Sopenharmony_ci struct o2net_msg *hdr; 133862306a36Sopenharmony_ci int ret = 0; 133962306a36Sopenharmony_ci void *data; 134062306a36Sopenharmony_ci size_t datalen; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci sclog(sc, "receiving\n"); 134362306a36Sopenharmony_ci o2net_set_advance_start_time(sc); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if (unlikely(sc->sc_handshake_ok == 0)) { 134662306a36Sopenharmony_ci if(sc->sc_page_off < sizeof(struct o2net_handshake)) { 134762306a36Sopenharmony_ci data = page_address(sc->sc_page) + sc->sc_page_off; 134862306a36Sopenharmony_ci datalen = sizeof(struct o2net_handshake) - sc->sc_page_off; 134962306a36Sopenharmony_ci ret = o2net_recv_tcp_msg(sc->sc_sock, data, datalen); 135062306a36Sopenharmony_ci if (ret > 0) 135162306a36Sopenharmony_ci sc->sc_page_off += ret; 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci if (sc->sc_page_off == sizeof(struct o2net_handshake)) { 135562306a36Sopenharmony_ci o2net_check_handshake(sc); 135662306a36Sopenharmony_ci if (unlikely(sc->sc_handshake_ok == 0)) 135762306a36Sopenharmony_ci ret = -EPROTO; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci goto out; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci /* do we need more header? */ 136362306a36Sopenharmony_ci if (sc->sc_page_off < sizeof(struct o2net_msg)) { 136462306a36Sopenharmony_ci data = page_address(sc->sc_page) + sc->sc_page_off; 136562306a36Sopenharmony_ci datalen = sizeof(struct o2net_msg) - sc->sc_page_off; 136662306a36Sopenharmony_ci ret = o2net_recv_tcp_msg(sc->sc_sock, data, datalen); 136762306a36Sopenharmony_ci if (ret > 0) { 136862306a36Sopenharmony_ci sc->sc_page_off += ret; 136962306a36Sopenharmony_ci /* only swab incoming here.. we can 137062306a36Sopenharmony_ci * only get here once as we cross from 137162306a36Sopenharmony_ci * being under to over */ 137262306a36Sopenharmony_ci if (sc->sc_page_off == sizeof(struct o2net_msg)) { 137362306a36Sopenharmony_ci hdr = page_address(sc->sc_page); 137462306a36Sopenharmony_ci if (be16_to_cpu(hdr->data_len) > 137562306a36Sopenharmony_ci O2NET_MAX_PAYLOAD_BYTES) 137662306a36Sopenharmony_ci ret = -EOVERFLOW; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci if (ret <= 0) 138062306a36Sopenharmony_ci goto out; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (sc->sc_page_off < sizeof(struct o2net_msg)) { 138462306a36Sopenharmony_ci /* oof, still don't have a header */ 138562306a36Sopenharmony_ci goto out; 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci /* this was swabbed above when we first read it */ 138962306a36Sopenharmony_ci hdr = page_address(sc->sc_page); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci msglog(hdr, "at page_off %zu\n", sc->sc_page_off); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci /* do we need more payload? */ 139462306a36Sopenharmony_ci if (sc->sc_page_off - sizeof(struct o2net_msg) < be16_to_cpu(hdr->data_len)) { 139562306a36Sopenharmony_ci /* need more payload */ 139662306a36Sopenharmony_ci data = page_address(sc->sc_page) + sc->sc_page_off; 139762306a36Sopenharmony_ci datalen = (sizeof(struct o2net_msg) + be16_to_cpu(hdr->data_len)) - 139862306a36Sopenharmony_ci sc->sc_page_off; 139962306a36Sopenharmony_ci ret = o2net_recv_tcp_msg(sc->sc_sock, data, datalen); 140062306a36Sopenharmony_ci if (ret > 0) 140162306a36Sopenharmony_ci sc->sc_page_off += ret; 140262306a36Sopenharmony_ci if (ret <= 0) 140362306a36Sopenharmony_ci goto out; 140462306a36Sopenharmony_ci } 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci if (sc->sc_page_off - sizeof(struct o2net_msg) == be16_to_cpu(hdr->data_len)) { 140762306a36Sopenharmony_ci /* we can only get here once, the first time we read 140862306a36Sopenharmony_ci * the payload.. so set ret to progress if the handler 140962306a36Sopenharmony_ci * works out. after calling this the message is toast */ 141062306a36Sopenharmony_ci ret = o2net_process_message(sc, hdr); 141162306a36Sopenharmony_ci if (ret == 0) 141262306a36Sopenharmony_ci ret = 1; 141362306a36Sopenharmony_ci sc->sc_page_off = 0; 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ciout: 141762306a36Sopenharmony_ci sclog(sc, "ret = %d\n", ret); 141862306a36Sopenharmony_ci o2net_set_advance_stop_time(sc); 141962306a36Sopenharmony_ci return ret; 142062306a36Sopenharmony_ci} 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci/* this work func is triggerd by data ready. it reads until it can read no 142362306a36Sopenharmony_ci * more. it interprets 0, eof, as fatal. if data_ready hits while we're doing 142462306a36Sopenharmony_ci * our work the work struct will be marked and we'll be called again. */ 142562306a36Sopenharmony_cistatic void o2net_rx_until_empty(struct work_struct *work) 142662306a36Sopenharmony_ci{ 142762306a36Sopenharmony_ci struct o2net_sock_container *sc = 142862306a36Sopenharmony_ci container_of(work, struct o2net_sock_container, sc_rx_work); 142962306a36Sopenharmony_ci int ret; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci do { 143262306a36Sopenharmony_ci ret = o2net_advance_rx(sc); 143362306a36Sopenharmony_ci } while (ret > 0); 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci if (ret <= 0 && ret != -EAGAIN) { 143662306a36Sopenharmony_ci struct o2net_node *nn = o2net_nn_from_num(sc->sc_node->nd_num); 143762306a36Sopenharmony_ci sclog(sc, "saw error %d, closing\n", ret); 143862306a36Sopenharmony_ci /* not permanent so read failed handshake can retry */ 143962306a36Sopenharmony_ci o2net_ensure_shutdown(nn, sc, 0); 144062306a36Sopenharmony_ci } 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci sc_put(sc); 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_cistatic void o2net_initialize_handshake(void) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci o2net_hand->o2hb_heartbeat_timeout_ms = cpu_to_be32( 144862306a36Sopenharmony_ci O2HB_MAX_WRITE_TIMEOUT_MS); 144962306a36Sopenharmony_ci o2net_hand->o2net_idle_timeout_ms = cpu_to_be32(o2net_idle_timeout()); 145062306a36Sopenharmony_ci o2net_hand->o2net_keepalive_delay_ms = cpu_to_be32( 145162306a36Sopenharmony_ci o2net_keepalive_delay()); 145262306a36Sopenharmony_ci o2net_hand->o2net_reconnect_delay_ms = cpu_to_be32( 145362306a36Sopenharmony_ci o2net_reconnect_delay()); 145462306a36Sopenharmony_ci} 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci/* ------------------------------------------------------------ */ 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci/* called when a connect completes and after a sock is accepted. the 145962306a36Sopenharmony_ci * rx path will see the response and mark the sc valid */ 146062306a36Sopenharmony_cistatic void o2net_sc_connect_completed(struct work_struct *work) 146162306a36Sopenharmony_ci{ 146262306a36Sopenharmony_ci struct o2net_sock_container *sc = 146362306a36Sopenharmony_ci container_of(work, struct o2net_sock_container, 146462306a36Sopenharmony_ci sc_connect_work); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci mlog(ML_MSG, "sc sending handshake with ver %llu id %llx\n", 146762306a36Sopenharmony_ci (unsigned long long)O2NET_PROTOCOL_VERSION, 146862306a36Sopenharmony_ci (unsigned long long)be64_to_cpu(o2net_hand->connector_id)); 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci o2net_initialize_handshake(); 147162306a36Sopenharmony_ci o2net_sendpage(sc, o2net_hand, sizeof(*o2net_hand)); 147262306a36Sopenharmony_ci sc_put(sc); 147362306a36Sopenharmony_ci} 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci/* this is called as a work_struct func. */ 147662306a36Sopenharmony_cistatic void o2net_sc_send_keep_req(struct work_struct *work) 147762306a36Sopenharmony_ci{ 147862306a36Sopenharmony_ci struct o2net_sock_container *sc = 147962306a36Sopenharmony_ci container_of(work, struct o2net_sock_container, 148062306a36Sopenharmony_ci sc_keepalive_work.work); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci o2net_sendpage(sc, o2net_keep_req, sizeof(*o2net_keep_req)); 148362306a36Sopenharmony_ci sc_put(sc); 148462306a36Sopenharmony_ci} 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci/* socket shutdown does a del_timer_sync against this as it tears down. 148762306a36Sopenharmony_ci * we can't start this timer until we've got to the point in sc buildup 148862306a36Sopenharmony_ci * where shutdown is going to be involved */ 148962306a36Sopenharmony_cistatic void o2net_idle_timer(struct timer_list *t) 149062306a36Sopenharmony_ci{ 149162306a36Sopenharmony_ci struct o2net_sock_container *sc = from_timer(sc, t, sc_idle_timeout); 149262306a36Sopenharmony_ci struct o2net_node *nn = o2net_nn_from_num(sc->sc_node->nd_num); 149362306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 149462306a36Sopenharmony_ci unsigned long msecs = ktime_to_ms(ktime_get()) - 149562306a36Sopenharmony_ci ktime_to_ms(sc->sc_tv_timer); 149662306a36Sopenharmony_ci#else 149762306a36Sopenharmony_ci unsigned long msecs = o2net_idle_timeout(); 149862306a36Sopenharmony_ci#endif 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci printk(KERN_NOTICE "o2net: Connection to " SC_NODEF_FMT " has been " 150162306a36Sopenharmony_ci "idle for %lu.%lu secs.\n", 150262306a36Sopenharmony_ci SC_NODEF_ARGS(sc), msecs / 1000, msecs % 1000); 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci /* idle timerout happen, don't shutdown the connection, but 150562306a36Sopenharmony_ci * make fence decision. Maybe the connection can recover before 150662306a36Sopenharmony_ci * the decision is made. 150762306a36Sopenharmony_ci */ 150862306a36Sopenharmony_ci atomic_set(&nn->nn_timeout, 1); 150962306a36Sopenharmony_ci o2quo_conn_err(o2net_num_from_nn(nn)); 151062306a36Sopenharmony_ci queue_delayed_work(o2net_wq, &nn->nn_still_up, 151162306a36Sopenharmony_ci msecs_to_jiffies(O2NET_QUORUM_DELAY_MS)); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci o2net_sc_reset_idle_timer(sc); 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci} 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_cistatic void o2net_sc_reset_idle_timer(struct o2net_sock_container *sc) 151862306a36Sopenharmony_ci{ 151962306a36Sopenharmony_ci o2net_sc_cancel_delayed_work(sc, &sc->sc_keepalive_work); 152062306a36Sopenharmony_ci o2net_sc_queue_delayed_work(sc, &sc->sc_keepalive_work, 152162306a36Sopenharmony_ci msecs_to_jiffies(o2net_keepalive_delay())); 152262306a36Sopenharmony_ci o2net_set_sock_timer(sc); 152362306a36Sopenharmony_ci mod_timer(&sc->sc_idle_timeout, 152462306a36Sopenharmony_ci jiffies + msecs_to_jiffies(o2net_idle_timeout())); 152562306a36Sopenharmony_ci} 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_cistatic void o2net_sc_postpone_idle(struct o2net_sock_container *sc) 152862306a36Sopenharmony_ci{ 152962306a36Sopenharmony_ci struct o2net_node *nn = o2net_nn_from_num(sc->sc_node->nd_num); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci /* clear fence decision since the connection recover from timeout*/ 153262306a36Sopenharmony_ci if (atomic_read(&nn->nn_timeout)) { 153362306a36Sopenharmony_ci o2quo_conn_up(o2net_num_from_nn(nn)); 153462306a36Sopenharmony_ci cancel_delayed_work(&nn->nn_still_up); 153562306a36Sopenharmony_ci atomic_set(&nn->nn_timeout, 0); 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci /* Only push out an existing timer */ 153962306a36Sopenharmony_ci if (timer_pending(&sc->sc_idle_timeout)) 154062306a36Sopenharmony_ci o2net_sc_reset_idle_timer(sc); 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci/* this work func is kicked whenever a path sets the nn state which doesn't 154462306a36Sopenharmony_ci * have valid set. This includes seeing hb come up, losing a connection, 154562306a36Sopenharmony_ci * having a connect attempt fail, etc. This centralizes the logic which decides 154662306a36Sopenharmony_ci * if a connect attempt should be made or if we should give up and all future 154762306a36Sopenharmony_ci * transmit attempts should fail */ 154862306a36Sopenharmony_cistatic void o2net_start_connect(struct work_struct *work) 154962306a36Sopenharmony_ci{ 155062306a36Sopenharmony_ci struct o2net_node *nn = 155162306a36Sopenharmony_ci container_of(work, struct o2net_node, nn_connect_work.work); 155262306a36Sopenharmony_ci struct o2net_sock_container *sc = NULL; 155362306a36Sopenharmony_ci struct o2nm_node *node = NULL, *mynode = NULL; 155462306a36Sopenharmony_ci struct socket *sock = NULL; 155562306a36Sopenharmony_ci struct sockaddr_in myaddr = {0, }, remoteaddr = {0, }; 155662306a36Sopenharmony_ci int ret = 0, stop; 155762306a36Sopenharmony_ci unsigned int timeout; 155862306a36Sopenharmony_ci unsigned int nofs_flag; 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci /* 156162306a36Sopenharmony_ci * sock_create allocates the sock with GFP_KERNEL. We must 156262306a36Sopenharmony_ci * prevent the filesystem from being reentered by memory reclaim. 156362306a36Sopenharmony_ci */ 156462306a36Sopenharmony_ci nofs_flag = memalloc_nofs_save(); 156562306a36Sopenharmony_ci /* if we're greater we initiate tx, otherwise we accept */ 156662306a36Sopenharmony_ci if (o2nm_this_node() <= o2net_num_from_nn(nn)) 156762306a36Sopenharmony_ci goto out; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci /* watch for racing with tearing a node down */ 157062306a36Sopenharmony_ci node = o2nm_get_node_by_num(o2net_num_from_nn(nn)); 157162306a36Sopenharmony_ci if (node == NULL) 157262306a36Sopenharmony_ci goto out; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci mynode = o2nm_get_node_by_num(o2nm_this_node()); 157562306a36Sopenharmony_ci if (mynode == NULL) 157662306a36Sopenharmony_ci goto out; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci spin_lock(&nn->nn_lock); 157962306a36Sopenharmony_ci /* 158062306a36Sopenharmony_ci * see if we already have one pending or have given up. 158162306a36Sopenharmony_ci * For nn_timeout, it is set when we close the connection 158262306a36Sopenharmony_ci * because of the idle time out. So it means that we have 158362306a36Sopenharmony_ci * at least connected to that node successfully once, 158462306a36Sopenharmony_ci * now try to connect to it again. 158562306a36Sopenharmony_ci */ 158662306a36Sopenharmony_ci timeout = atomic_read(&nn->nn_timeout); 158762306a36Sopenharmony_ci stop = (nn->nn_sc || 158862306a36Sopenharmony_ci (nn->nn_persistent_error && 158962306a36Sopenharmony_ci (nn->nn_persistent_error != -ENOTCONN || timeout == 0))); 159062306a36Sopenharmony_ci spin_unlock(&nn->nn_lock); 159162306a36Sopenharmony_ci if (stop) 159262306a36Sopenharmony_ci goto out; 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci nn->nn_last_connect_attempt = jiffies; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci sc = sc_alloc(node); 159762306a36Sopenharmony_ci if (sc == NULL) { 159862306a36Sopenharmony_ci mlog(0, "couldn't allocate sc\n"); 159962306a36Sopenharmony_ci ret = -ENOMEM; 160062306a36Sopenharmony_ci goto out; 160162306a36Sopenharmony_ci } 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); 160462306a36Sopenharmony_ci if (ret < 0) { 160562306a36Sopenharmony_ci mlog(0, "can't create socket: %d\n", ret); 160662306a36Sopenharmony_ci goto out; 160762306a36Sopenharmony_ci } 160862306a36Sopenharmony_ci sc->sc_sock = sock; /* freed by sc_kref_release */ 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci sock->sk->sk_allocation = GFP_ATOMIC; 161162306a36Sopenharmony_ci sock->sk->sk_use_task_frag = false; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci myaddr.sin_family = AF_INET; 161462306a36Sopenharmony_ci myaddr.sin_addr.s_addr = mynode->nd_ipv4_address; 161562306a36Sopenharmony_ci myaddr.sin_port = htons(0); /* any port */ 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci ret = sock->ops->bind(sock, (struct sockaddr *)&myaddr, 161862306a36Sopenharmony_ci sizeof(myaddr)); 161962306a36Sopenharmony_ci if (ret) { 162062306a36Sopenharmony_ci mlog(ML_ERROR, "bind failed with %d at address %pI4\n", 162162306a36Sopenharmony_ci ret, &mynode->nd_ipv4_address); 162262306a36Sopenharmony_ci goto out; 162362306a36Sopenharmony_ci } 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci tcp_sock_set_nodelay(sc->sc_sock->sk); 162662306a36Sopenharmony_ci tcp_sock_set_user_timeout(sock->sk, O2NET_TCP_USER_TIMEOUT); 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci o2net_register_callbacks(sc->sc_sock->sk, sc); 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci spin_lock(&nn->nn_lock); 163162306a36Sopenharmony_ci /* handshake completion will set nn->nn_sc_valid */ 163262306a36Sopenharmony_ci o2net_set_nn_state(nn, sc, 0, 0); 163362306a36Sopenharmony_ci spin_unlock(&nn->nn_lock); 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci remoteaddr.sin_family = AF_INET; 163662306a36Sopenharmony_ci remoteaddr.sin_addr.s_addr = node->nd_ipv4_address; 163762306a36Sopenharmony_ci remoteaddr.sin_port = node->nd_ipv4_port; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci ret = sc->sc_sock->ops->connect(sc->sc_sock, 164062306a36Sopenharmony_ci (struct sockaddr *)&remoteaddr, 164162306a36Sopenharmony_ci sizeof(remoteaddr), 164262306a36Sopenharmony_ci O_NONBLOCK); 164362306a36Sopenharmony_ci if (ret == -EINPROGRESS) 164462306a36Sopenharmony_ci ret = 0; 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ciout: 164762306a36Sopenharmony_ci if (ret && sc) { 164862306a36Sopenharmony_ci printk(KERN_NOTICE "o2net: Connect attempt to " SC_NODEF_FMT 164962306a36Sopenharmony_ci " failed with errno %d\n", SC_NODEF_ARGS(sc), ret); 165062306a36Sopenharmony_ci /* 0 err so that another will be queued and attempted 165162306a36Sopenharmony_ci * from set_nn_state */ 165262306a36Sopenharmony_ci o2net_ensure_shutdown(nn, sc, 0); 165362306a36Sopenharmony_ci } 165462306a36Sopenharmony_ci if (sc) 165562306a36Sopenharmony_ci sc_put(sc); 165662306a36Sopenharmony_ci if (node) 165762306a36Sopenharmony_ci o2nm_node_put(node); 165862306a36Sopenharmony_ci if (mynode) 165962306a36Sopenharmony_ci o2nm_node_put(mynode); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci memalloc_nofs_restore(nofs_flag); 166262306a36Sopenharmony_ci return; 166362306a36Sopenharmony_ci} 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_cistatic void o2net_connect_expired(struct work_struct *work) 166662306a36Sopenharmony_ci{ 166762306a36Sopenharmony_ci struct o2net_node *nn = 166862306a36Sopenharmony_ci container_of(work, struct o2net_node, nn_connect_expired.work); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci spin_lock(&nn->nn_lock); 167162306a36Sopenharmony_ci if (!nn->nn_sc_valid) { 167262306a36Sopenharmony_ci printk(KERN_NOTICE "o2net: No connection established with " 167362306a36Sopenharmony_ci "node %u after %u.%u seconds, check network and" 167462306a36Sopenharmony_ci " cluster configuration.\n", 167562306a36Sopenharmony_ci o2net_num_from_nn(nn), 167662306a36Sopenharmony_ci o2net_idle_timeout() / 1000, 167762306a36Sopenharmony_ci o2net_idle_timeout() % 1000); 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci o2net_set_nn_state(nn, NULL, 0, 0); 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci spin_unlock(&nn->nn_lock); 168262306a36Sopenharmony_ci} 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_cistatic void o2net_still_up(struct work_struct *work) 168562306a36Sopenharmony_ci{ 168662306a36Sopenharmony_ci struct o2net_node *nn = 168762306a36Sopenharmony_ci container_of(work, struct o2net_node, nn_still_up.work); 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci o2quo_hb_still_up(o2net_num_from_nn(nn)); 169062306a36Sopenharmony_ci} 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci/* ------------------------------------------------------------ */ 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_civoid o2net_disconnect_node(struct o2nm_node *node) 169562306a36Sopenharmony_ci{ 169662306a36Sopenharmony_ci struct o2net_node *nn = o2net_nn_from_num(node->nd_num); 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci /* don't reconnect until it's heartbeating again */ 169962306a36Sopenharmony_ci spin_lock(&nn->nn_lock); 170062306a36Sopenharmony_ci atomic_set(&nn->nn_timeout, 0); 170162306a36Sopenharmony_ci o2net_set_nn_state(nn, NULL, 0, -ENOTCONN); 170262306a36Sopenharmony_ci spin_unlock(&nn->nn_lock); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci if (o2net_wq) { 170562306a36Sopenharmony_ci cancel_delayed_work(&nn->nn_connect_expired); 170662306a36Sopenharmony_ci cancel_delayed_work(&nn->nn_connect_work); 170762306a36Sopenharmony_ci cancel_delayed_work(&nn->nn_still_up); 170862306a36Sopenharmony_ci flush_workqueue(o2net_wq); 170962306a36Sopenharmony_ci } 171062306a36Sopenharmony_ci} 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_cistatic void o2net_hb_node_down_cb(struct o2nm_node *node, int node_num, 171362306a36Sopenharmony_ci void *data) 171462306a36Sopenharmony_ci{ 171562306a36Sopenharmony_ci o2quo_hb_down(node_num); 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci if (!node) 171862306a36Sopenharmony_ci return; 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci if (node_num != o2nm_this_node()) 172162306a36Sopenharmony_ci o2net_disconnect_node(node); 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci BUG_ON(atomic_read(&o2net_connected_peers) < 0); 172462306a36Sopenharmony_ci} 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_cistatic void o2net_hb_node_up_cb(struct o2nm_node *node, int node_num, 172762306a36Sopenharmony_ci void *data) 172862306a36Sopenharmony_ci{ 172962306a36Sopenharmony_ci struct o2net_node *nn = o2net_nn_from_num(node_num); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci o2quo_hb_up(node_num); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci BUG_ON(!node); 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci /* ensure an immediate connect attempt */ 173662306a36Sopenharmony_ci nn->nn_last_connect_attempt = jiffies - 173762306a36Sopenharmony_ci (msecs_to_jiffies(o2net_reconnect_delay()) + 1); 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci if (node_num != o2nm_this_node()) { 174062306a36Sopenharmony_ci /* believe it or not, accept and node heartbeating testing 174162306a36Sopenharmony_ci * can succeed for this node before we got here.. so 174262306a36Sopenharmony_ci * only use set_nn_state to clear the persistent error 174362306a36Sopenharmony_ci * if that hasn't already happened */ 174462306a36Sopenharmony_ci spin_lock(&nn->nn_lock); 174562306a36Sopenharmony_ci atomic_set(&nn->nn_timeout, 0); 174662306a36Sopenharmony_ci if (nn->nn_persistent_error) 174762306a36Sopenharmony_ci o2net_set_nn_state(nn, NULL, 0, 0); 174862306a36Sopenharmony_ci spin_unlock(&nn->nn_lock); 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci} 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_civoid o2net_unregister_hb_callbacks(void) 175362306a36Sopenharmony_ci{ 175462306a36Sopenharmony_ci o2hb_unregister_callback(NULL, &o2net_hb_up); 175562306a36Sopenharmony_ci o2hb_unregister_callback(NULL, &o2net_hb_down); 175662306a36Sopenharmony_ci} 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ciint o2net_register_hb_callbacks(void) 175962306a36Sopenharmony_ci{ 176062306a36Sopenharmony_ci int ret; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci o2hb_setup_callback(&o2net_hb_down, O2HB_NODE_DOWN_CB, 176362306a36Sopenharmony_ci o2net_hb_node_down_cb, NULL, O2NET_HB_PRI); 176462306a36Sopenharmony_ci o2hb_setup_callback(&o2net_hb_up, O2HB_NODE_UP_CB, 176562306a36Sopenharmony_ci o2net_hb_node_up_cb, NULL, O2NET_HB_PRI); 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci ret = o2hb_register_callback(NULL, &o2net_hb_up); 176862306a36Sopenharmony_ci if (ret == 0) 176962306a36Sopenharmony_ci ret = o2hb_register_callback(NULL, &o2net_hb_down); 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci if (ret) 177262306a36Sopenharmony_ci o2net_unregister_hb_callbacks(); 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci return ret; 177562306a36Sopenharmony_ci} 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci/* ------------------------------------------------------------ */ 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_cistatic int o2net_accept_one(struct socket *sock, int *more) 178062306a36Sopenharmony_ci{ 178162306a36Sopenharmony_ci int ret; 178262306a36Sopenharmony_ci struct sockaddr_in sin; 178362306a36Sopenharmony_ci struct socket *new_sock = NULL; 178462306a36Sopenharmony_ci struct o2nm_node *node = NULL; 178562306a36Sopenharmony_ci struct o2nm_node *local_node = NULL; 178662306a36Sopenharmony_ci struct o2net_sock_container *sc = NULL; 178762306a36Sopenharmony_ci struct o2net_node *nn; 178862306a36Sopenharmony_ci unsigned int nofs_flag; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci /* 179162306a36Sopenharmony_ci * sock_create_lite allocates the sock with GFP_KERNEL. We must 179262306a36Sopenharmony_ci * prevent the filesystem from being reentered by memory reclaim. 179362306a36Sopenharmony_ci */ 179462306a36Sopenharmony_ci nofs_flag = memalloc_nofs_save(); 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci BUG_ON(sock == NULL); 179762306a36Sopenharmony_ci *more = 0; 179862306a36Sopenharmony_ci ret = sock_create_lite(sock->sk->sk_family, sock->sk->sk_type, 179962306a36Sopenharmony_ci sock->sk->sk_protocol, &new_sock); 180062306a36Sopenharmony_ci if (ret) 180162306a36Sopenharmony_ci goto out; 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci new_sock->type = sock->type; 180462306a36Sopenharmony_ci new_sock->ops = sock->ops; 180562306a36Sopenharmony_ci ret = sock->ops->accept(sock, new_sock, O_NONBLOCK, false); 180662306a36Sopenharmony_ci if (ret < 0) 180762306a36Sopenharmony_ci goto out; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci *more = 1; 181062306a36Sopenharmony_ci new_sock->sk->sk_allocation = GFP_ATOMIC; 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci tcp_sock_set_nodelay(new_sock->sk); 181362306a36Sopenharmony_ci tcp_sock_set_user_timeout(new_sock->sk, O2NET_TCP_USER_TIMEOUT); 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci ret = new_sock->ops->getname(new_sock, (struct sockaddr *) &sin, 1); 181662306a36Sopenharmony_ci if (ret < 0) 181762306a36Sopenharmony_ci goto out; 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci node = o2nm_get_node_by_ip(sin.sin_addr.s_addr); 182062306a36Sopenharmony_ci if (node == NULL) { 182162306a36Sopenharmony_ci printk(KERN_NOTICE "o2net: Attempt to connect from unknown " 182262306a36Sopenharmony_ci "node at %pI4:%d\n", &sin.sin_addr.s_addr, 182362306a36Sopenharmony_ci ntohs(sin.sin_port)); 182462306a36Sopenharmony_ci ret = -EINVAL; 182562306a36Sopenharmony_ci goto out; 182662306a36Sopenharmony_ci } 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci if (o2nm_this_node() >= node->nd_num) { 182962306a36Sopenharmony_ci local_node = o2nm_get_node_by_num(o2nm_this_node()); 183062306a36Sopenharmony_ci if (local_node) 183162306a36Sopenharmony_ci printk(KERN_NOTICE "o2net: Unexpected connect attempt " 183262306a36Sopenharmony_ci "seen at node '%s' (%u, %pI4:%d) from " 183362306a36Sopenharmony_ci "node '%s' (%u, %pI4:%d)\n", 183462306a36Sopenharmony_ci local_node->nd_name, local_node->nd_num, 183562306a36Sopenharmony_ci &(local_node->nd_ipv4_address), 183662306a36Sopenharmony_ci ntohs(local_node->nd_ipv4_port), 183762306a36Sopenharmony_ci node->nd_name, 183862306a36Sopenharmony_ci node->nd_num, &sin.sin_addr.s_addr, 183962306a36Sopenharmony_ci ntohs(sin.sin_port)); 184062306a36Sopenharmony_ci ret = -EINVAL; 184162306a36Sopenharmony_ci goto out; 184262306a36Sopenharmony_ci } 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci /* this happens all the time when the other node sees our heartbeat 184562306a36Sopenharmony_ci * and tries to connect before we see their heartbeat */ 184662306a36Sopenharmony_ci if (!o2hb_check_node_heartbeating_from_callback(node->nd_num)) { 184762306a36Sopenharmony_ci mlog(ML_CONN, "attempt to connect from node '%s' at " 184862306a36Sopenharmony_ci "%pI4:%d but it isn't heartbeating\n", 184962306a36Sopenharmony_ci node->nd_name, &sin.sin_addr.s_addr, 185062306a36Sopenharmony_ci ntohs(sin.sin_port)); 185162306a36Sopenharmony_ci ret = -EINVAL; 185262306a36Sopenharmony_ci goto out; 185362306a36Sopenharmony_ci } 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci nn = o2net_nn_from_num(node->nd_num); 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci spin_lock(&nn->nn_lock); 185862306a36Sopenharmony_ci if (nn->nn_sc) 185962306a36Sopenharmony_ci ret = -EBUSY; 186062306a36Sopenharmony_ci else 186162306a36Sopenharmony_ci ret = 0; 186262306a36Sopenharmony_ci spin_unlock(&nn->nn_lock); 186362306a36Sopenharmony_ci if (ret) { 186462306a36Sopenharmony_ci printk(KERN_NOTICE "o2net: Attempt to connect from node '%s' " 186562306a36Sopenharmony_ci "at %pI4:%d but it already has an open connection\n", 186662306a36Sopenharmony_ci node->nd_name, &sin.sin_addr.s_addr, 186762306a36Sopenharmony_ci ntohs(sin.sin_port)); 186862306a36Sopenharmony_ci goto out; 186962306a36Sopenharmony_ci } 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci sc = sc_alloc(node); 187262306a36Sopenharmony_ci if (sc == NULL) { 187362306a36Sopenharmony_ci ret = -ENOMEM; 187462306a36Sopenharmony_ci goto out; 187562306a36Sopenharmony_ci } 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci sc->sc_sock = new_sock; 187862306a36Sopenharmony_ci new_sock = NULL; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci spin_lock(&nn->nn_lock); 188162306a36Sopenharmony_ci atomic_set(&nn->nn_timeout, 0); 188262306a36Sopenharmony_ci o2net_set_nn_state(nn, sc, 0, 0); 188362306a36Sopenharmony_ci spin_unlock(&nn->nn_lock); 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci o2net_register_callbacks(sc->sc_sock->sk, sc); 188662306a36Sopenharmony_ci o2net_sc_queue_work(sc, &sc->sc_rx_work); 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci o2net_initialize_handshake(); 188962306a36Sopenharmony_ci o2net_sendpage(sc, o2net_hand, sizeof(*o2net_hand)); 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ciout: 189262306a36Sopenharmony_ci if (new_sock) 189362306a36Sopenharmony_ci sock_release(new_sock); 189462306a36Sopenharmony_ci if (node) 189562306a36Sopenharmony_ci o2nm_node_put(node); 189662306a36Sopenharmony_ci if (local_node) 189762306a36Sopenharmony_ci o2nm_node_put(local_node); 189862306a36Sopenharmony_ci if (sc) 189962306a36Sopenharmony_ci sc_put(sc); 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci memalloc_nofs_restore(nofs_flag); 190262306a36Sopenharmony_ci return ret; 190362306a36Sopenharmony_ci} 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci/* 190662306a36Sopenharmony_ci * This function is invoked in response to one or more 190762306a36Sopenharmony_ci * pending accepts at softIRQ level. We must drain the 190862306a36Sopenharmony_ci * entire que before returning. 190962306a36Sopenharmony_ci */ 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_cistatic void o2net_accept_many(struct work_struct *work) 191262306a36Sopenharmony_ci{ 191362306a36Sopenharmony_ci struct socket *sock = o2net_listen_sock; 191462306a36Sopenharmony_ci int more; 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci /* 191762306a36Sopenharmony_ci * It is critical to note that due to interrupt moderation 191862306a36Sopenharmony_ci * at the network driver level, we can't assume to get a 191962306a36Sopenharmony_ci * softIRQ for every single conn since tcp SYN packets 192062306a36Sopenharmony_ci * can arrive back-to-back, and therefore many pending 192162306a36Sopenharmony_ci * accepts may result in just 1 softIRQ. If we terminate 192262306a36Sopenharmony_ci * the o2net_accept_one() loop upon seeing an err, what happens 192362306a36Sopenharmony_ci * to the rest of the conns in the queue? If no new SYN 192462306a36Sopenharmony_ci * arrives for hours, no softIRQ will be delivered, 192562306a36Sopenharmony_ci * and the connections will just sit in the queue. 192662306a36Sopenharmony_ci */ 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci for (;;) { 192962306a36Sopenharmony_ci o2net_accept_one(sock, &more); 193062306a36Sopenharmony_ci if (!more) 193162306a36Sopenharmony_ci break; 193262306a36Sopenharmony_ci cond_resched(); 193362306a36Sopenharmony_ci } 193462306a36Sopenharmony_ci} 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_cistatic void o2net_listen_data_ready(struct sock *sk) 193762306a36Sopenharmony_ci{ 193862306a36Sopenharmony_ci void (*ready)(struct sock *sk); 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci trace_sk_data_ready(sk); 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci read_lock_bh(&sk->sk_callback_lock); 194362306a36Sopenharmony_ci ready = sk->sk_user_data; 194462306a36Sopenharmony_ci if (ready == NULL) { /* check for teardown race */ 194562306a36Sopenharmony_ci ready = sk->sk_data_ready; 194662306a36Sopenharmony_ci goto out; 194762306a36Sopenharmony_ci } 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci /* This callback may called twice when a new connection 195062306a36Sopenharmony_ci * is being established as a child socket inherits everything 195162306a36Sopenharmony_ci * from a parent LISTEN socket, including the data_ready cb of 195262306a36Sopenharmony_ci * the parent. This leads to a hazard. In o2net_accept_one() 195362306a36Sopenharmony_ci * we are still initializing the child socket but have not 195462306a36Sopenharmony_ci * changed the inherited data_ready callback yet when 195562306a36Sopenharmony_ci * data starts arriving. 195662306a36Sopenharmony_ci * We avoid this hazard by checking the state. 195762306a36Sopenharmony_ci * For the listening socket, the state will be TCP_LISTEN; for the new 195862306a36Sopenharmony_ci * socket, will be TCP_ESTABLISHED. Also, in this case, 195962306a36Sopenharmony_ci * sk->sk_user_data is not a valid function pointer. 196062306a36Sopenharmony_ci */ 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci if (sk->sk_state == TCP_LISTEN) { 196362306a36Sopenharmony_ci queue_work(o2net_wq, &o2net_listen_work); 196462306a36Sopenharmony_ci } else { 196562306a36Sopenharmony_ci ready = NULL; 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ciout: 196962306a36Sopenharmony_ci read_unlock_bh(&sk->sk_callback_lock); 197062306a36Sopenharmony_ci if (ready != NULL) 197162306a36Sopenharmony_ci ready(sk); 197262306a36Sopenharmony_ci} 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_cistatic int o2net_open_listening_sock(__be32 addr, __be16 port) 197562306a36Sopenharmony_ci{ 197662306a36Sopenharmony_ci struct socket *sock = NULL; 197762306a36Sopenharmony_ci int ret; 197862306a36Sopenharmony_ci struct sockaddr_in sin = { 197962306a36Sopenharmony_ci .sin_family = PF_INET, 198062306a36Sopenharmony_ci .sin_addr = { .s_addr = addr }, 198162306a36Sopenharmony_ci .sin_port = port, 198262306a36Sopenharmony_ci }; 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); 198562306a36Sopenharmony_ci if (ret < 0) { 198662306a36Sopenharmony_ci printk(KERN_ERR "o2net: Error %d while creating socket\n", ret); 198762306a36Sopenharmony_ci goto out; 198862306a36Sopenharmony_ci } 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci sock->sk->sk_allocation = GFP_ATOMIC; 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci write_lock_bh(&sock->sk->sk_callback_lock); 199362306a36Sopenharmony_ci sock->sk->sk_user_data = sock->sk->sk_data_ready; 199462306a36Sopenharmony_ci sock->sk->sk_data_ready = o2net_listen_data_ready; 199562306a36Sopenharmony_ci write_unlock_bh(&sock->sk->sk_callback_lock); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci o2net_listen_sock = sock; 199862306a36Sopenharmony_ci INIT_WORK(&o2net_listen_work, o2net_accept_many); 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci sock->sk->sk_reuse = SK_CAN_REUSE; 200162306a36Sopenharmony_ci ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin)); 200262306a36Sopenharmony_ci if (ret < 0) { 200362306a36Sopenharmony_ci printk(KERN_ERR "o2net: Error %d while binding socket at " 200462306a36Sopenharmony_ci "%pI4:%u\n", ret, &addr, ntohs(port)); 200562306a36Sopenharmony_ci goto out; 200662306a36Sopenharmony_ci } 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci ret = sock->ops->listen(sock, 64); 200962306a36Sopenharmony_ci if (ret < 0) 201062306a36Sopenharmony_ci printk(KERN_ERR "o2net: Error %d while listening on %pI4:%u\n", 201162306a36Sopenharmony_ci ret, &addr, ntohs(port)); 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ciout: 201462306a36Sopenharmony_ci if (ret) { 201562306a36Sopenharmony_ci o2net_listen_sock = NULL; 201662306a36Sopenharmony_ci if (sock) 201762306a36Sopenharmony_ci sock_release(sock); 201862306a36Sopenharmony_ci } 201962306a36Sopenharmony_ci return ret; 202062306a36Sopenharmony_ci} 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci/* 202362306a36Sopenharmony_ci * called from node manager when we should bring up our network listening 202462306a36Sopenharmony_ci * socket. node manager handles all the serialization to only call this 202562306a36Sopenharmony_ci * once and to match it with o2net_stop_listening(). note, 202662306a36Sopenharmony_ci * o2nm_this_node() doesn't work yet as we're being called while it 202762306a36Sopenharmony_ci * is being set up. 202862306a36Sopenharmony_ci */ 202962306a36Sopenharmony_ciint o2net_start_listening(struct o2nm_node *node) 203062306a36Sopenharmony_ci{ 203162306a36Sopenharmony_ci int ret = 0; 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci BUG_ON(o2net_wq != NULL); 203462306a36Sopenharmony_ci BUG_ON(o2net_listen_sock != NULL); 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci mlog(ML_KTHREAD, "starting o2net thread...\n"); 203762306a36Sopenharmony_ci o2net_wq = alloc_ordered_workqueue("o2net", WQ_MEM_RECLAIM); 203862306a36Sopenharmony_ci if (o2net_wq == NULL) { 203962306a36Sopenharmony_ci mlog(ML_ERROR, "unable to launch o2net thread\n"); 204062306a36Sopenharmony_ci return -ENOMEM; /* ? */ 204162306a36Sopenharmony_ci } 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci ret = o2net_open_listening_sock(node->nd_ipv4_address, 204462306a36Sopenharmony_ci node->nd_ipv4_port); 204562306a36Sopenharmony_ci if (ret) { 204662306a36Sopenharmony_ci destroy_workqueue(o2net_wq); 204762306a36Sopenharmony_ci o2net_wq = NULL; 204862306a36Sopenharmony_ci } else 204962306a36Sopenharmony_ci o2quo_conn_up(node->nd_num); 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci return ret; 205262306a36Sopenharmony_ci} 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci/* again, o2nm_this_node() doesn't work here as we're involved in 205562306a36Sopenharmony_ci * tearing it down */ 205662306a36Sopenharmony_civoid o2net_stop_listening(struct o2nm_node *node) 205762306a36Sopenharmony_ci{ 205862306a36Sopenharmony_ci struct socket *sock = o2net_listen_sock; 205962306a36Sopenharmony_ci size_t i; 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci BUG_ON(o2net_wq == NULL); 206262306a36Sopenharmony_ci BUG_ON(o2net_listen_sock == NULL); 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci /* stop the listening socket from generating work */ 206562306a36Sopenharmony_ci write_lock_bh(&sock->sk->sk_callback_lock); 206662306a36Sopenharmony_ci sock->sk->sk_data_ready = sock->sk->sk_user_data; 206762306a36Sopenharmony_ci sock->sk->sk_user_data = NULL; 206862306a36Sopenharmony_ci write_unlock_bh(&sock->sk->sk_callback_lock); 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(o2net_nodes); i++) { 207162306a36Sopenharmony_ci struct o2nm_node *node = o2nm_get_node_by_num(i); 207262306a36Sopenharmony_ci if (node) { 207362306a36Sopenharmony_ci o2net_disconnect_node(node); 207462306a36Sopenharmony_ci o2nm_node_put(node); 207562306a36Sopenharmony_ci } 207662306a36Sopenharmony_ci } 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci /* finish all work and tear down the work queue */ 207962306a36Sopenharmony_ci mlog(ML_KTHREAD, "waiting for o2net thread to exit....\n"); 208062306a36Sopenharmony_ci destroy_workqueue(o2net_wq); 208162306a36Sopenharmony_ci o2net_wq = NULL; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci sock_release(o2net_listen_sock); 208462306a36Sopenharmony_ci o2net_listen_sock = NULL; 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci o2quo_conn_err(node->nd_num); 208762306a36Sopenharmony_ci} 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci/* ------------------------------------------------------------ */ 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ciint o2net_init(void) 209262306a36Sopenharmony_ci{ 209362306a36Sopenharmony_ci struct folio *folio; 209462306a36Sopenharmony_ci void *p; 209562306a36Sopenharmony_ci unsigned long i; 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci o2quo_init(); 209862306a36Sopenharmony_ci o2net_debugfs_init(); 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci folio = folio_alloc(GFP_KERNEL | __GFP_ZERO, 0); 210162306a36Sopenharmony_ci if (!folio) 210262306a36Sopenharmony_ci goto out; 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci p = folio_address(folio); 210562306a36Sopenharmony_ci o2net_hand = p; 210662306a36Sopenharmony_ci p += sizeof(struct o2net_handshake); 210762306a36Sopenharmony_ci o2net_keep_req = p; 210862306a36Sopenharmony_ci p += sizeof(struct o2net_msg); 210962306a36Sopenharmony_ci o2net_keep_resp = p; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci o2net_hand->protocol_version = cpu_to_be64(O2NET_PROTOCOL_VERSION); 211262306a36Sopenharmony_ci o2net_hand->connector_id = cpu_to_be64(1); 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci o2net_keep_req->magic = cpu_to_be16(O2NET_MSG_KEEP_REQ_MAGIC); 211562306a36Sopenharmony_ci o2net_keep_resp->magic = cpu_to_be16(O2NET_MSG_KEEP_RESP_MAGIC); 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(o2net_nodes); i++) { 211862306a36Sopenharmony_ci struct o2net_node *nn = o2net_nn_from_num(i); 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci atomic_set(&nn->nn_timeout, 0); 212162306a36Sopenharmony_ci spin_lock_init(&nn->nn_lock); 212262306a36Sopenharmony_ci INIT_DELAYED_WORK(&nn->nn_connect_work, o2net_start_connect); 212362306a36Sopenharmony_ci INIT_DELAYED_WORK(&nn->nn_connect_expired, 212462306a36Sopenharmony_ci o2net_connect_expired); 212562306a36Sopenharmony_ci INIT_DELAYED_WORK(&nn->nn_still_up, o2net_still_up); 212662306a36Sopenharmony_ci /* until we see hb from a node we'll return einval */ 212762306a36Sopenharmony_ci nn->nn_persistent_error = -ENOTCONN; 212862306a36Sopenharmony_ci init_waitqueue_head(&nn->nn_sc_wq); 212962306a36Sopenharmony_ci idr_init(&nn->nn_status_idr); 213062306a36Sopenharmony_ci INIT_LIST_HEAD(&nn->nn_status_list); 213162306a36Sopenharmony_ci } 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci return 0; 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ciout: 213662306a36Sopenharmony_ci o2net_debugfs_exit(); 213762306a36Sopenharmony_ci o2quo_exit(); 213862306a36Sopenharmony_ci return -ENOMEM; 213962306a36Sopenharmony_ci} 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_civoid o2net_exit(void) 214262306a36Sopenharmony_ci{ 214362306a36Sopenharmony_ci o2quo_exit(); 214462306a36Sopenharmony_ci o2net_debugfs_exit(); 214562306a36Sopenharmony_ci folio_put(virt_to_folio(o2net_hand)); 214662306a36Sopenharmony_ci} 2147