X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lnet%2Flnet%2Fapi-ni.c;h=d8922ccbde6dba11e9511ddb2482e16a79725b69;hp=f1c94a5aeac3d38263ca8f99b81183d15088ad00;hb=3b760208109b249fd9051d97dbc98664ca4b5769;hpb=adae4295b62b1074f5c3c45543c586282394b1be diff --git a/lnet/lnet/api-ni.c b/lnet/lnet/api-ni.c index f1c94a5..d8922cc 100644 --- a/lnet/lnet/api-ni.c +++ b/lnet/lnet/api-ni.c @@ -27,7 +27,6 @@ */ /* * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. */ #define DEBUG_SUBSYSTEM S_LNET @@ -40,7 +39,7 @@ #ifdef HAVE_SCHED_HEADERS #include #endif - +#include #include #define D_LNI D_CONSOLE @@ -71,10 +70,10 @@ static int rnet_htable_size = LNET_REMOTE_NETS_HASH_DEFAULT; module_param(rnet_htable_size, int, 0444); MODULE_PARM_DESC(rnet_htable_size, "size of remote network hash table"); -static int use_tcp_bonding = false; +static int use_tcp_bonding; module_param(use_tcp_bonding, int, 0444); MODULE_PARM_DESC(use_tcp_bonding, - "Set to 1 to use socklnd bonding. 0 to use Multi-Rail"); + "use_tcp_bonding parameter has been removed"); unsigned int lnet_numa_range = 0; module_param(lnet_numa_range, uint, 0444); @@ -122,7 +121,33 @@ module_param_call(lnet_recovery_interval, recovery_interval_set, param_get_int, &lnet_recovery_interval, S_IRUGO|S_IWUSR); #endif MODULE_PARM_DESC(lnet_recovery_interval, - "Interval to recover unhealthy interfaces in seconds"); + "DEPRECATED - Interval to recover unhealthy interfaces in seconds"); + +unsigned int lnet_recovery_limit; +module_param(lnet_recovery_limit, uint, 0644); +MODULE_PARM_DESC(lnet_recovery_limit, + "How long to attempt recovery of unhealthy peer interfaces in seconds. Set to 0 to allow indefinite recovery"); + +unsigned int lnet_max_recovery_ping_interval = 900; +unsigned int lnet_max_recovery_ping_count = 9; +static int max_recovery_ping_interval_set(const char *val, + cfs_kernel_param_arg_t *kp); + +#define param_check_max_recovery_ping_interval(name, p) \ + __param_check(name, p, int) + +#ifdef HAVE_KERNEL_PARAM_OPS +static struct kernel_param_ops param_ops_max_recovery_ping_interval = { + .set = max_recovery_ping_interval_set, + .get = param_get_int, +}; +module_param(lnet_max_recovery_ping_interval, max_recovery_ping_interval, 0644); +#else +module_param_call(lnet_max_recovery_ping_interval, max_recovery_ping_interval, + param_get_int, &lnet_max_recovery_ping_interval, 0644); +#endif +MODULE_PARM_DESC(lnet_max_recovery_ping_interval, + "The max interval between LNet recovery pings, in seconds"); static int lnet_interfaces_max = LNET_INTERFACES_MAX_DEFAULT; static int intf_max_set(const char *val, cfs_kernel_param_arg_t *kp); @@ -182,10 +207,8 @@ module_param_call(lnet_drop_asym_route, drop_asym_route_set, param_get_int, MODULE_PARM_DESC(lnet_drop_asym_route, "Set to 1 to drop asymmetrical route messages."); -#define LNET_TRANSACTION_TIMEOUT_NO_HEALTH_DEFAULT 50 -#define LNET_TRANSACTION_TIMEOUT_HEALTH_DEFAULT 50 - -unsigned lnet_transaction_timeout = LNET_TRANSACTION_TIMEOUT_HEALTH_DEFAULT; +#define LNET_TRANSACTION_TIMEOUT_DEFAULT 50 +unsigned int lnet_transaction_timeout = LNET_TRANSACTION_TIMEOUT_DEFAULT; static int transaction_to_set(const char *val, cfs_kernel_param_arg_t *kp); #ifdef HAVE_KERNEL_PARAM_OPS static struct kernel_param_ops param_ops_transaction_timeout = { @@ -203,8 +226,8 @@ module_param_call(lnet_transaction_timeout, transaction_to_set, param_get_int, MODULE_PARM_DESC(lnet_transaction_timeout, "Maximum number of seconds to wait for a peer response."); -#define LNET_RETRY_COUNT_HEALTH_DEFAULT 2 -unsigned lnet_retry_count = LNET_RETRY_COUNT_HEALTH_DEFAULT; +#define LNET_RETRY_COUNT_DEFAULT 2 +unsigned int lnet_retry_count = LNET_RETRY_COUNT_DEFAULT; static int retry_count_set(const char *val, cfs_kernel_param_arg_t *kp); #ifdef HAVE_KERNEL_PARAM_OPS static struct kernel_param_ops param_ops_retry_count = { @@ -222,9 +245,33 @@ module_param_call(lnet_retry_count, retry_count_set, param_get_int, MODULE_PARM_DESC(lnet_retry_count, "Maximum number of times to retry transmitting a message"); +unsigned int lnet_response_tracking = 3; +static int response_tracking_set(const char *val, cfs_kernel_param_arg_t *kp); -unsigned lnet_lnd_timeout = LNET_LND_DEFAULT_TIMEOUT; -unsigned int lnet_current_net_count; +#ifdef HAVE_KERNEL_PARAM_OPS +static struct kernel_param_ops param_ops_response_tracking = { + .set = response_tracking_set, + .get = param_get_int, +}; + +#define param_check_response_tracking(name, p) \ + __param_check(name, p, int) +module_param(lnet_response_tracking, response_tracking, 0644); +#else +module_param_call(lnet_response_tracking, response_tracking_set, param_get_int, + &lnet_response_tracking, 0644); +#endif +MODULE_PARM_DESC(lnet_response_tracking, + "(0|1|2|3) LNet Internal Only|GET Reply only|PUT ACK only|Full Tracking (default)"); + +#define LNET_LND_TIMEOUT_DEFAULT ((LNET_TRANSACTION_TIMEOUT_DEFAULT - 1) / \ + (LNET_RETRY_COUNT_DEFAULT + 1)) +unsigned int lnet_lnd_timeout = LNET_LND_TIMEOUT_DEFAULT; +static void lnet_set_lnd_timeout(void) +{ + lnet_lnd_timeout = (lnet_transaction_timeout - 1) / + (lnet_retry_count + 1); +} /* * This sequence number keeps track of how many times DLC was used to @@ -235,8 +282,9 @@ unsigned int lnet_current_net_count; */ static atomic_t lnet_dlc_seq_no = ATOMIC_INIT(0); -static int lnet_ping(struct lnet_process_id id, signed long timeout, - struct lnet_process_id __user *ids, int n_ids); +static int lnet_ping(struct lnet_process_id id4, struct lnet_nid *src_nid, + signed long timeout, struct lnet_process_id __user *ids, + int n_ids); static int lnet_discover(struct lnet_process_id id, __u32 force, struct lnet_process_id __user *ids, int n_ids); @@ -267,21 +315,9 @@ sensitivity_set(const char *val, cfs_kernel_param_arg_t *kp) return -EINVAL; } - /* - * if we're turning on health then use the health timeout - * defaults. - */ - if (*sensitivity == 0 && value != 0) { - lnet_transaction_timeout = LNET_TRANSACTION_TIMEOUT_HEALTH_DEFAULT; - lnet_retry_count = LNET_RETRY_COUNT_HEALTH_DEFAULT; - /* - * if we're turning off health then use the no health timeout - * default. - */ - } else if (*sensitivity != 0 && value == 0) { - lnet_transaction_timeout = - LNET_TRANSACTION_TIMEOUT_NO_HEALTH_DEFAULT; + if (*sensitivity != 0 && value == 0 && lnet_retry_count != 0) { lnet_retry_count = 0; + lnet_set_lnd_timeout(); } *sensitivity = value; @@ -294,29 +330,39 @@ sensitivity_set(const char *val, cfs_kernel_param_arg_t *kp) static int recovery_interval_set(const char *val, cfs_kernel_param_arg_t *kp) { + CWARN("'lnet_recovery_interval' has been deprecated\n"); + + return 0; +} + +static int +max_recovery_ping_interval_set(const char *val, cfs_kernel_param_arg_t *kp) +{ int rc; - unsigned *interval = (unsigned *)kp->arg; unsigned long value; rc = kstrtoul(val, 0, &value); if (rc) { - CERROR("Invalid module parameter value for 'lnet_recovery_interval'\n"); + CERROR("Invalid module parameter value for 'lnet_max_recovery_ping_interval'\n"); return rc; } - if (value < 1) { - CERROR("lnet_recovery_interval must be at least 1 second\n"); + if (!value) { + CERROR("Invalid max ping timeout. Must be strictly positive\n"); return -EINVAL; } - /* - * The purpose of locking the api_mutex here is to ensure that + /* The purpose of locking the api_mutex here is to ensure that * the correct value ends up stored properly. */ mutex_lock(&the_lnet.ln_api_mutex); - - *interval = value; - + lnet_max_recovery_ping_interval = value; + lnet_max_recovery_ping_count = 0; + value >>= 1; + while (value) { + lnet_max_recovery_ping_count++; + value >>= 1; + } mutex_unlock(&the_lnet.ln_api_mutex); return 0; @@ -432,7 +478,7 @@ transaction_to_set(const char *val, cfs_kernel_param_arg_t *kp) */ mutex_lock(&the_lnet.ln_api_mutex); - if (value < lnet_retry_count || value == 0) { + if (value <= lnet_retry_count || value == 0) { mutex_unlock(&the_lnet.ln_api_mutex); CERROR("Invalid value for lnet_transaction_timeout (%lu). " "Has to be greater than lnet_retry_count (%u)\n", @@ -446,10 +492,10 @@ transaction_to_set(const char *val, cfs_kernel_param_arg_t *kp) } *transaction_to = value; - if (lnet_retry_count == 0) - lnet_lnd_timeout = value; - else - lnet_lnd_timeout = value / lnet_retry_count; + /* Update the lnet_lnd_timeout now that we've modified the + * transaction timeout + */ + lnet_set_lnd_timeout(); mutex_unlock(&the_lnet.ln_api_mutex); @@ -475,9 +521,9 @@ retry_count_set(const char *val, cfs_kernel_param_arg_t *kp) */ mutex_lock(&the_lnet.ln_api_mutex); - if (lnet_health_sensitivity == 0) { + if (lnet_health_sensitivity == 0 && value > 0) { mutex_unlock(&the_lnet.ln_api_mutex); - CERROR("Can not set retry_count when health feature is turned off\n"); + CERROR("Can not set lnet_retry_count when health feature is turned off\n"); return -EINVAL; } @@ -491,10 +537,10 @@ retry_count_set(const char *val, cfs_kernel_param_arg_t *kp) *retry_count = value; - if (value == 0) - lnet_lnd_timeout = lnet_transaction_timeout; - else - lnet_lnd_timeout = lnet_transaction_timeout / value; + /* Update the lnet_lnd_timeout now that we've modified the + * retry count + */ + lnet_set_lnd_timeout(); mutex_unlock(&the_lnet.ln_api_mutex); @@ -523,6 +569,29 @@ intf_max_set(const char *val, cfs_kernel_param_arg_t *kp) return 0; } +static int +response_tracking_set(const char *val, cfs_kernel_param_arg_t *kp) +{ + int rc; + unsigned long new_value; + + rc = kstrtoul(val, 0, &new_value); + if (rc) { + CERROR("Invalid value for 'lnet_response_tracking'\n"); + return -EINVAL; + } + + if (new_value < 0 || new_value > 3) { + CWARN("Invalid value (%lu) for 'lnet_response_tracking'\n", + new_value); + return -EINVAL; + } + + lnet_response_tracking = new_value; + + return 0; +} + static const char * lnet_get_routes(void) { @@ -564,6 +633,7 @@ lnet_init_locks(void) struct kmem_cache *lnet_mes_cachep; /* MEs kmem_cache */ struct kmem_cache *lnet_small_mds_cachep; /* <= LNET_SMALL_MD_SIZE bytes * MDs kmem_cache */ +struct kmem_cache *lnet_udsp_cachep; /* udsp cache */ struct kmem_cache *lnet_rspt_cachep; /* response tracker cache */ struct kmem_cache *lnet_msg_cachep; @@ -584,6 +654,12 @@ lnet_slab_setup(void) if (!lnet_small_mds_cachep) return -ENOMEM; + lnet_udsp_cachep = kmem_cache_create("lnet_udsp", + sizeof(struct lnet_udsp), + 0, 0, NULL); + if (!lnet_udsp_cachep) + return -ENOMEM; + lnet_rspt_cachep = kmem_cache_create("lnet_rspt", sizeof(struct lnet_rsp_tracker), 0, 0, NULL); if (!lnet_rspt_cachep) @@ -605,12 +681,16 @@ lnet_slab_cleanup(void) lnet_msg_cachep = NULL; } - if (lnet_rspt_cachep) { kmem_cache_destroy(lnet_rspt_cachep); lnet_rspt_cachep = NULL; } + if (lnet_udsp_cachep) { + kmem_cache_destroy(lnet_udsp_cachep); + lnet_udsp_cachep = NULL; + } + if (lnet_small_mds_cachep) { kmem_cache_destroy(lnet_small_mds_cachep); lnet_small_mds_cachep = NULL; @@ -697,7 +777,8 @@ static void lnet_assert_wire_constants(void) /* Wire protocol assertions generated by 'wirecheck' * running on Linux robert.bartonsoftware.com 2.6.8-1.521 * #1 Mon Aug 16 09:01:18 EDT 2004 i686 athlon i386 GNU/Linux - * with gcc version 3.3.3 20040412 (Red Hat Linux 3.3.3-7) */ + * with gcc version 3.3.3 20040412 (Red Hat Linux 3.3.3-7) + */ /* Constants... */ BUILD_BUG_ON(LNET_PROTO_TCP_MAGIC != 0xeebc0ded); @@ -709,6 +790,27 @@ static void lnet_assert_wire_constants(void) BUILD_BUG_ON(LNET_MSG_REPLY != 3); BUILD_BUG_ON(LNET_MSG_HELLO != 4); + BUILD_BUG_ON((int)sizeof(lnet_nid_t) != 8); + BUILD_BUG_ON((int)sizeof(lnet_pid_t) != 4); + + /* Checks for struct lnet_nid */ + BUILD_BUG_ON((int)sizeof(struct lnet_nid) != 20); + BUILD_BUG_ON((int)offsetof(struct lnet_nid, nid_size) != 0); + BUILD_BUG_ON((int)sizeof(((struct lnet_nid *)0)->nid_size) != 1); + BUILD_BUG_ON((int)offsetof(struct lnet_nid, nid_type) != 1); + BUILD_BUG_ON((int)sizeof(((struct lnet_nid *)0)->nid_type) != 1); + BUILD_BUG_ON((int)offsetof(struct lnet_nid, nid_num) != 2); + BUILD_BUG_ON((int)sizeof(((struct lnet_nid *)0)->nid_num) != 2); + BUILD_BUG_ON((int)offsetof(struct lnet_nid, nid_addr) != 4); + BUILD_BUG_ON((int)sizeof(((struct lnet_nid *)0)->nid_addr) != 16); + + /* Checks for struct lnet_process_id_packed */ + BUILD_BUG_ON((int)sizeof(struct lnet_process_id_packed) != 12); + BUILD_BUG_ON((int)offsetof(struct lnet_process_id_packed, nid) != 0); + BUILD_BUG_ON((int)sizeof(((struct lnet_process_id_packed *)0)->nid) != 8); + BUILD_BUG_ON((int)offsetof(struct lnet_process_id_packed, pid) != 8); + BUILD_BUG_ON((int)sizeof(((struct lnet_process_id_packed *)0)->pid) != 4); + /* Checks for struct lnet_handle_wire */ BUILD_BUG_ON((int)sizeof(struct lnet_handle_wire) != 16); BUILD_BUG_ON((int)offsetof(struct lnet_handle_wire, @@ -728,64 +830,64 @@ static void lnet_assert_wire_constants(void) version_minor) != 6); BUILD_BUG_ON((int)sizeof(((struct lnet_magicversion *)0)->version_minor) != 2); - /* Checks for struct struct lnet_hdr */ - BUILD_BUG_ON((int)sizeof(struct lnet_hdr) != 72); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, dest_nid) != 0); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->dest_nid) != 8); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, src_nid) != 8); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->src_nid) != 8); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, dest_pid) != 16); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->dest_pid) != 4); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, src_pid) != 20); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->src_pid) != 4); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, type) != 24); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->type) != 4); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, payload_length) != 28); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->payload_length) != 4); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg) != 32); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg) != 40); + /* Checks for struct _lnet_hdr_nid4 */ + BUILD_BUG_ON((int)sizeof(struct _lnet_hdr_nid4) != 72); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, dest_nid) != 0); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->dest_nid) != 8); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, src_nid) != 8); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->src_nid) != 8); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, dest_pid) != 16); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->dest_pid) != 4); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, src_pid) != 20); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->src_pid) != 4); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, type) != 24); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->type) != 4); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, payload_length) != 28); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->payload_length) != 4); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg) != 32); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg) != 40); /* Ack */ - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.ack.dst_wmd) != 32); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.ack.dst_wmd) != 16); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.ack.match_bits) != 48); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.ack.match_bits) != 8); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.ack.mlength) != 56); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.ack.mlength) != 4); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.ack.dst_wmd) != 32); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.ack.dst_wmd) != 16); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.ack.match_bits) != 48); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.ack.match_bits) != 8); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.ack.mlength) != 56); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.ack.mlength) != 4); /* Put */ - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.ack_wmd) != 32); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.ack_wmd) != 16); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.match_bits) != 48); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.match_bits) != 8); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.hdr_data) != 56); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.hdr_data) != 8); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.ptl_index) != 64); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.ptl_index) != 4); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.offset) != 68); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.offset) != 4); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.put.ack_wmd) != 32); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.put.ack_wmd) != 16); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.put.match_bits) != 48); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.put.match_bits) != 8); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.put.hdr_data) != 56); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.put.hdr_data) != 8); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.put.ptl_index) != 64); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.put.ptl_index) != 4); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.put.offset) != 68); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.put.offset) != 4); /* Get */ - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.return_wmd) != 32); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.return_wmd) != 16); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.match_bits) != 48); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.match_bits) != 8); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.ptl_index) != 56); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.ptl_index) != 4); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.src_offset) != 60); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.src_offset) != 4); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.sink_length) != 64); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.sink_length) != 4); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.get.return_wmd) != 32); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.get.return_wmd) != 16); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.get.match_bits) != 48); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.get.match_bits) != 8); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.get.ptl_index) != 56); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.get.ptl_index) != 4); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.get.src_offset) != 60); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.get.src_offset) != 4); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.get.sink_length) != 64); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.get.sink_length) != 4); /* Reply */ - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.reply.dst_wmd) != 32); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.reply.dst_wmd) != 16); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.reply.dst_wmd) != 32); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.reply.dst_wmd) != 16); /* Hello */ - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.hello.incarnation) != 32); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.hello.incarnation) != 8); - BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.hello.type) != 40); - BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.hello.type) != 4); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.hello.incarnation) != 32); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.hello.incarnation) != 8); + BUILD_BUG_ON((int)offsetof(struct _lnet_hdr_nid4, msg.hello.type) != 40); + BUILD_BUG_ON((int)sizeof(((struct _lnet_hdr_nid4 *)0)->msg.hello.type) != 4); /* Checks for struct lnet_ni_status and related constants */ BUILD_BUG_ON(LNET_NI_STATUS_INVALID != 0x00000000); @@ -823,6 +925,52 @@ static void lnet_assert_wire_constants(void) BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_nnis) != 4); BUILD_BUG_ON((int)offsetof(struct lnet_ping_info, pi_ni) != 16); BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_ni) != 0); + + /* Acceptor connection request */ + BUILD_BUG_ON(LNET_PROTO_ACCEPTOR_VERSION != 1); + + /* Checks for struct lnet_acceptor_connreq */ + BUILD_BUG_ON((int)sizeof(struct lnet_acceptor_connreq) != 16); + BUILD_BUG_ON((int)offsetof(struct lnet_acceptor_connreq, acr_magic) != 0); + BUILD_BUG_ON((int)sizeof(((struct lnet_acceptor_connreq *)0)->acr_magic) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_acceptor_connreq, acr_version) != 4); + BUILD_BUG_ON((int)sizeof(((struct lnet_acceptor_connreq *)0)->acr_version) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_acceptor_connreq, acr_nid) != 8); + BUILD_BUG_ON((int)sizeof(((struct lnet_acceptor_connreq *)0)->acr_nid) != 8); + + /* Checks for struct lnet_acceptor_connreq_v2 */ + BUILD_BUG_ON((int)sizeof(struct lnet_acceptor_connreq_v2) != 28); + BUILD_BUG_ON((int)offsetof(struct lnet_acceptor_connreq_v2, acr_magic) != 0); + BUILD_BUG_ON((int)sizeof(((struct lnet_acceptor_connreq_v2 *)0)->acr_magic) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_acceptor_connreq_v2, acr_version) != 4); + BUILD_BUG_ON((int)sizeof(((struct lnet_acceptor_connreq_v2 *)0)->acr_version) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_acceptor_connreq_v2, acr_nid) != 8); + BUILD_BUG_ON((int)sizeof(((struct lnet_acceptor_connreq_v2 *)0)->acr_nid) != 20); + + /* Checks for struct lnet_counters_common */ + BUILD_BUG_ON((int)sizeof(struct lnet_counters_common) != 60); + BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_msgs_alloc) != 0); + BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_msgs_alloc) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_msgs_max) != 4); + BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_msgs_max) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_errors) != 8); + BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_errors) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_send_count) != 12); + BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_send_count) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_recv_count) != 16); + BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_recv_count) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_route_count) != 20); + BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_route_count) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_drop_count) != 24); + BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_drop_count) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_send_length) != 28); + BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_send_length) != 8); + BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_recv_length) != 36); + BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_recv_length) != 8); + BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_route_length) != 44); + BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_route_length) != 8); + BUILD_BUG_ON((int)offsetof(struct lnet_counters_common, lcc_drop_length) != 52); + BUILD_BUG_ON((int)sizeof(((struct lnet_counters_common *)0)->lcc_drop_length) != 8); } static const struct lnet_lnd *lnet_find_lnd_by_type(__u32 type) @@ -875,16 +1023,17 @@ lnet_unregister_lnd(const struct lnet_lnd *lnd) } EXPORT_SYMBOL(lnet_unregister_lnd); -void -lnet_counters_get_common(struct lnet_counters_common *common) +static void +lnet_counters_get_common_locked(struct lnet_counters_common *common) { struct lnet_counters *ctr; int i; + /* FIXME !!! Their is no assert_lnet_net_locked() to ensure this + * actually called under the protection of the lnet_net_lock. + */ memset(common, 0, sizeof(*common)); - lnet_net_lock(LNET_LOCK_EX); - cfs_percpt_for_each(ctr, i, the_lnet.ln_counters) { common->lcc_msgs_max += ctr->lct_common.lcc_msgs_max; common->lcc_msgs_alloc += ctr->lct_common.lcc_msgs_alloc; @@ -898,23 +1047,33 @@ lnet_counters_get_common(struct lnet_counters_common *common) common->lcc_route_length += ctr->lct_common.lcc_route_length; common->lcc_drop_length += ctr->lct_common.lcc_drop_length; } +} + +void +lnet_counters_get_common(struct lnet_counters_common *common) +{ + lnet_net_lock(LNET_LOCK_EX); + lnet_counters_get_common_locked(common); lnet_net_unlock(LNET_LOCK_EX); } EXPORT_SYMBOL(lnet_counters_get_common); -void +int lnet_counters_get(struct lnet_counters *counters) { struct lnet_counters *ctr; struct lnet_counters_health *health = &counters->lct_health; - int i; + int i, rc = 0; memset(counters, 0, sizeof(*counters)); - lnet_counters_get_common(&counters->lct_common); - lnet_net_lock(LNET_LOCK_EX); + if (the_lnet.ln_state != LNET_STATE_RUNNING) + GOTO(out_unlock, rc = -ENODEV); + + lnet_counters_get_common_locked(&counters->lct_common); + cfs_percpt_for_each(ctr, i, the_lnet.ln_counters) { health->lch_rst_alloc += ctr->lct_health.lch_rst_alloc; health->lch_resend_count += ctr->lct_health.lch_resend_count; @@ -941,7 +1100,9 @@ lnet_counters_get(struct lnet_counters *counters) health->lch_network_timeout_count += ctr->lct_health.lch_network_timeout_count; } +out_unlock: lnet_net_unlock(LNET_LOCK_EX); + return rc; } EXPORT_SYMBOL(lnet_counters_get); @@ -953,9 +1114,12 @@ lnet_counters_reset(void) lnet_net_lock(LNET_LOCK_EX); + if (the_lnet.ln_state != LNET_STATE_RUNNING) + goto avoid_reset; + cfs_percpt_for_each(counters, i, the_lnet.ln_counters) memset(counters, 0, sizeof(struct lnet_counters)); - +avoid_reset: lnet_net_unlock(LNET_LOCK_EX); } @@ -1172,6 +1336,7 @@ lnet_prepare(lnet_pid_t requested_pid) INIT_LIST_HEAD(&the_lnet.ln_dc_expired); INIT_LIST_HEAD(&the_lnet.ln_mt_localNIRecovq); INIT_LIST_HEAD(&the_lnet.ln_mt_peerNIRecovq); + INIT_LIST_HEAD(&the_lnet.ln_udsp_list); init_waitqueue_head(&the_lnet.ln_dc_waitq); the_lnet.ln_mt_handler = NULL; init_completion(&the_lnet.ln_started); @@ -1239,7 +1404,7 @@ lnet_prepare(lnet_pid_t requested_pid) } static int -lnet_unprepare (void) +lnet_unprepare(void) { /* NB no LNET_LOCK since this is the last reference. All LND instances * have shut down already, so it is safe to unlink and free all @@ -1278,6 +1443,7 @@ lnet_unprepare (void) the_lnet.ln_counters = NULL; } lnet_destroy_remote_nets_table(); + lnet_udsp_destroy(true); lnet_slab_cleanup(); return 0; @@ -1293,8 +1459,8 @@ lnet_net2ni_locked(__u32 net_id, int cpt) list_for_each_entry(net, &the_lnet.ln_nets, net_list) { if (net->net_id == net_id) { - ni = list_entry(net->net_ni_list.next, struct lnet_ni, - ni_netlist); + ni = list_first_entry(&net->net_ni_list, struct lnet_ni, + ni_netlist); return ni; } } @@ -1330,27 +1496,126 @@ lnet_get_net_locked(__u32 net_id) return NULL; } +void +lnet_net_clr_pref_rtrs(struct lnet_net *net) +{ + struct list_head zombies; + struct lnet_nid_list *ne; + struct lnet_nid_list *tmp; + + INIT_LIST_HEAD(&zombies); + + lnet_net_lock(LNET_LOCK_EX); + list_splice_init(&net->net_rtr_pref_nids, &zombies); + lnet_net_unlock(LNET_LOCK_EX); + + list_for_each_entry_safe(ne, tmp, &zombies, nl_list) { + list_del_init(&ne->nl_list); + LIBCFS_FREE(ne, sizeof(*ne)); + } +} + +int +lnet_net_add_pref_rtr(struct lnet_net *net, + struct lnet_nid *gw_nid) +__must_hold(&the_lnet.ln_api_mutex) +{ + struct lnet_nid_list *ne; + + /* This function is called with api_mutex held. When the api_mutex + * is held the list can not be modified, as it is only modified as + * a result of applying a UDSP and that happens under api_mutex + * lock. + */ + list_for_each_entry(ne, &net->net_rtr_pref_nids, nl_list) { + if (nid_same(&ne->nl_nid, gw_nid)) + return -EEXIST; + } + + LIBCFS_ALLOC(ne, sizeof(*ne)); + if (!ne) + return -ENOMEM; + + ne->nl_nid = *gw_nid; + + /* Lock the cpt to protect against addition and checks in the + * selection algorithm + */ + lnet_net_lock(LNET_LOCK_EX); + list_add(&ne->nl_list, &net->net_rtr_pref_nids); + lnet_net_unlock(LNET_LOCK_EX); + + return 0; +} + +bool +lnet_net_is_pref_rtr_locked(struct lnet_net *net, struct lnet_nid *rtr_nid) +{ + struct lnet_nid_list *ne; + + CDEBUG(D_NET, "%s: rtr pref empty: %d\n", + libcfs_net2str(net->net_id), + list_empty(&net->net_rtr_pref_nids)); + + if (list_empty(&net->net_rtr_pref_nids)) + return false; + + list_for_each_entry(ne, &net->net_rtr_pref_nids, nl_list) { + CDEBUG(D_NET, "Comparing pref %s with gw %s\n", + libcfs_nidstr(&ne->nl_nid), + libcfs_nidstr(rtr_nid)); + if (nid_same(rtr_nid, &ne->nl_nid)) + return true; + } + + return false; +} + +static unsigned int +lnet_nid4_cpt_hash(lnet_nid_t nid, unsigned int number) +{ + __u64 key = nid; + __u64 pair_bits = 0x0001000100010001LLU; + __u64 mask = pair_bits * 0xFF; + __u64 pair_sum; + + /* Use (sum-by-multiplication of nid bytes) mod (number of CPTs) + * to match nid to a CPT. + */ + pair_sum = (key & mask) + ((key >> 8) & mask); + pair_sum = (pair_sum * pair_bits) >> 48; + + CDEBUG(D_NET, "Match nid %s to cpt %u\n", + libcfs_nid2str(nid), (unsigned int)(pair_sum) % number); + + return (unsigned int)(pair_sum) % number; +} + unsigned int -lnet_nid_cpt_hash(lnet_nid_t nid, unsigned int number) +lnet_nid_cpt_hash(struct lnet_nid *nid, unsigned int number) { - __u64 key = nid; - unsigned int val; + unsigned int val; + u32 h = 0; + int i; LASSERT(number >= 1 && number <= LNET_CPT_NUMBER); if (number == 1) return 0; - val = hash_long(key, LNET_CPT_BITS); - /* NB: LNET_CP_NUMBER doesn't have to be PO2 */ + if (nid_is_nid4(nid)) + return lnet_nid4_cpt_hash(lnet_nid_to_nid4(nid), number); + + for (i = 0; i < 4; i++) + h = hash_32(nid->nid_addr[i]^h, 32); + val = hash_32(LNET_NID_NET(nid) ^ h, LNET_CPT_BITS); if (val < number) return val; - - return (unsigned int)(key + val + (val >> 1)) % number; + return (unsigned int)(h + val + (val >> 1)) % number; } int -lnet_cpt_of_nid_locked(lnet_nid_t nid, struct lnet_ni *ni) +lnet_cpt_of_nid_locked(struct lnet_nid *nid, struct lnet_ni *ni) { struct lnet_net *net; @@ -1374,7 +1639,7 @@ lnet_cpt_of_nid_locked(lnet_nid_t nid, struct lnet_ni *ni) } /* no NI provided so look at the net */ - net = lnet_get_net_locked(LNET_NIDNET(nid)); + net = lnet_get_net_locked(LNET_NID_NET(nid)); if (net != NULL && net->net_cpts != NULL) { return net->net_cpts[lnet_nid_cpt_hash(nid, net->net_ncpts)]; @@ -1384,7 +1649,7 @@ lnet_cpt_of_nid_locked(lnet_nid_t nid, struct lnet_ni *ni) } int -lnet_cpt_of_nid(lnet_nid_t nid, struct lnet_ni *ni) +lnet_nid2cpt(struct lnet_nid *nid, struct lnet_ni *ni) { int cpt; int cpt2; @@ -1400,6 +1665,19 @@ lnet_cpt_of_nid(lnet_nid_t nid, struct lnet_ni *ni) return cpt2; } +EXPORT_SYMBOL(lnet_nid2cpt); + +int +lnet_cpt_of_nid(lnet_nid_t nid4, struct lnet_ni *ni) +{ + struct lnet_nid nid; + + if (LNET_CPT_NUMBER == 1) + return 0; /* the only one */ + + lnet_nid4_to_nid(nid4, &nid); + return lnet_nid2cpt(&nid, ni); +} EXPORT_SYMBOL(lnet_cpt_of_nid); int @@ -1431,16 +1709,16 @@ lnet_islocalnet(__u32 net_id) } struct lnet_ni * -lnet_nid2ni_locked(lnet_nid_t nid, int cpt) +lnet_nid_to_ni_locked(struct lnet_nid *nid, int cpt) { struct lnet_net *net; - struct lnet_ni *ni; + struct lnet_ni *ni; LASSERT(cpt != LNET_LOCK_EX); list_for_each_entry(net, &the_lnet.ln_nets, net_list) { list_for_each_entry(ni, &net->net_ni_list, ni_netlist) { - if (ni->ni_nid == nid) + if (nid_same(&ni->ni_nid, nid)) return ni; } } @@ -1448,13 +1726,25 @@ lnet_nid2ni_locked(lnet_nid_t nid, int cpt) return NULL; } +struct lnet_ni * +lnet_nid2ni_locked(lnet_nid_t nid4, int cpt) +{ + struct lnet_nid nid; + + lnet_nid4_to_nid(nid4, &nid); + return lnet_nid_to_ni_locked(&nid, cpt); +} + struct lnet_ni * -lnet_nid2ni_addref(lnet_nid_t nid) +lnet_nid2ni_addref(lnet_nid_t nid4) { struct lnet_ni *ni; + struct lnet_nid nid; + + lnet_nid4_to_nid(nid4, &nid); lnet_net_lock(0); - ni = lnet_nid2ni_locked(nid, 0); + ni = lnet_nid_to_ni_locked(&nid, 0); if (ni) lnet_ni_addref_locked(ni, 0); lnet_net_unlock(0); @@ -1463,14 +1753,29 @@ lnet_nid2ni_addref(lnet_nid_t nid) } EXPORT_SYMBOL(lnet_nid2ni_addref); +struct lnet_ni * +lnet_nid_to_ni_addref(struct lnet_nid *nid) +{ + struct lnet_ni *ni; + + lnet_net_lock(0); + ni = lnet_nid_to_ni_locked(nid, 0); + if (ni) + lnet_ni_addref_locked(ni, 0); + lnet_net_unlock(0); + + return ni; +} +EXPORT_SYMBOL(lnet_nid_to_ni_addref); + int -lnet_islocalnid(lnet_nid_t nid) +lnet_islocalnid(struct lnet_nid *nid) { struct lnet_ni *ni; int cpt; cpt = lnet_net_lock_current(); - ni = lnet_nid2ni_locked(nid, cpt); + ni = lnet_nid_to_ni_locked(nid, cpt); lnet_net_unlock(cpt); return ni != NULL; @@ -1582,23 +1887,6 @@ lnet_get_ni_count(void) return count; } -int -lnet_get_net_count(void) -{ - struct lnet_net *net; - int count = 0; - - lnet_net_lock(0); - - list_for_each_entry(net, &the_lnet.ln_nets, net_list) { - count++; - } - - lnet_net_unlock(0); - - return count; -} - void lnet_swap_pinginfo(struct lnet_ping_buffer *pbuf) { @@ -1673,8 +1961,8 @@ lnet_ping_target_setup(struct lnet_ping_buffer **ppbuf, struct lnet_handle_md *ping_mdh, int ni_count, bool set_eq) { - struct lnet_process_id id = { - .nid = LNET_NID_ANY, + struct lnet_processid id = { + .nid = LNET_ANY_NID, .pid = LNET_PID_ANY }; struct lnet_me *me; @@ -1692,7 +1980,7 @@ lnet_ping_target_setup(struct lnet_ping_buffer **ppbuf, } /* Ping target ME/MD */ - me = LNetMEAttach(LNET_RESERVED_PORTAL, id, + me = LNetMEAttach(LNET_RESERVED_PORTAL, &id, LNET_PROTO_PING_MATCHBITS, 0, LNET_UNLINK, LNET_INS_AFTER); if (IS_ERR(me)) { @@ -1714,14 +2002,12 @@ lnet_ping_target_setup(struct lnet_ping_buffer **ppbuf, rc = LNetMDAttach(me, &md, LNET_RETAIN, ping_mdh); if (rc != 0) { CERROR("Can't attach ping target MD: %d\n", rc); - goto fail_unlink_ping_me; + goto fail_decref_ping_buffer; } lnet_ping_buffer_addref(*ppbuf); return 0; -fail_unlink_ping_me: - LNetMEUnlink(me); fail_decref_ping_buffer: LASSERT(atomic_read(&(*ppbuf)->pb_refcnt) == 1); lnet_ping_buffer_decref(*ppbuf); @@ -1759,12 +2045,12 @@ lnet_ping_target_install_locked(struct lnet_ping_buffer *pbuf) ns = &pbuf->pb_info.pi_ni[i]; - ns->ns_nid = ni->ni_nid; + if (!nid_is_nid4(&ni->ni_nid)) + continue; + ns->ns_nid = lnet_nid_to_nid4(&ni->ni_nid); lnet_ni_lock(ni); - ns->ns_status = (ni->ni_status != NULL) ? - ni->ni_status->ns_status : - LNET_NI_STATUS_UP; + ns->ns_status = lnet_ni_get_status_locked(ni); ni->ni_status = ns; lnet_ni_unlock(ni); @@ -1892,12 +2178,12 @@ again: int lnet_push_target_post(struct lnet_ping_buffer *pbuf, struct lnet_handle_md *mdhp) { - struct lnet_process_id id = { LNET_NID_ANY, LNET_PID_ANY }; + struct lnet_processid id = { LNET_ANY_NID, LNET_PID_ANY }; struct lnet_md md = { NULL }; struct lnet_me *me; int rc; - me = LNetMEAttach(LNET_RESERVED_PORTAL, id, + me = LNetMEAttach(LNET_RESERVED_PORTAL, &id, LNET_PROTO_PING_MATCHBITS, 0, LNET_UNLINK, LNET_INS_AFTER); if (IS_ERR(me)) { @@ -1923,7 +2209,6 @@ int lnet_push_target_post(struct lnet_ping_buffer *pbuf, rc = LNetMDAttach(me, &md, LNET_UNLINK, mdhp); if (rc) { CERROR("Can't attach push MD: %d\n", rc); - LNetMEUnlink(me); lnet_ping_buffer_decref(pbuf); pbuf->pb_needs_post = true; return rc; @@ -2047,12 +2332,12 @@ lnet_clear_zombies_nis_locked(struct lnet_net *net) * list and shut them down in guaranteed thread context */ i = 2; - while (!list_empty(zombie_list)) { - int *ref; - int j; + while ((ni = list_first_entry_or_null(zombie_list, + struct lnet_ni, + ni_netlist)) != NULL) { + int *ref; + int j; - ni = list_entry(zombie_list->next, - struct lnet_ni, ni_netlist); list_del_init(&ni->ni_netlist); /* the ni should be in deleting state. If it's not it's * a bug */ @@ -2066,14 +2351,22 @@ lnet_clear_zombies_nis_locked(struct lnet_net *net) } if (!list_empty(&ni->ni_netlist)) { + /* Unlock mutex while waiting to allow other + * threads to read the LNet state and fall through + * to avoid deadlock + */ lnet_net_unlock(LNET_LOCK_EX); + mutex_unlock(&the_lnet.ln_api_mutex); + ++i; if ((i & (-i)) == i) { CDEBUG(D_WARNING, "Waiting for zombie LNI %s\n", - libcfs_nid2str(ni->ni_nid)); + libcfs_nidstr(&ni->ni_nid)); } schedule_timeout_uninterruptible(cfs_time_seconds(1)); + + mutex_lock(&the_lnet.ln_api_mutex); lnet_net_lock(LNET_LOCK_EX); continue; } @@ -2083,18 +2376,20 @@ lnet_clear_zombies_nis_locked(struct lnet_net *net) islo = ni->ni_net->net_lnd->lnd_type == LOLND; LASSERT(!in_interrupt()); - /* Holding the mutex makes it safe for lnd_shutdown + /* Holding the LND mutex makes it safe for lnd_shutdown * to call module_put(). Module unload cannot finish * until lnet_unregister_lnd() completes, and that - * requires the mutex. + * requires the LND mutex. */ + mutex_unlock(&the_lnet.ln_api_mutex); mutex_lock(&the_lnet.ln_lnd_mutex); (net->net_lnd->lnd_shutdown)(ni); mutex_unlock(&the_lnet.ln_lnd_mutex); + mutex_lock(&the_lnet.ln_api_mutex); if (!islo) CDEBUG(D_LNI, "Removed LNI %s\n", - libcfs_nid2str(ni->ni_nid)); + libcfs_nidstr(&ni->ni_nid)); lnet_ni_free(ni); i = 2; @@ -2135,9 +2430,9 @@ lnet_shutdown_lndnet(struct lnet_net *net) list_del_init(&net->net_list); - while (!list_empty(&net->net_ni_list)) { - ni = list_entry(net->net_ni_list.next, - struct lnet_ni, ni_netlist); + while ((ni = list_first_entry_or_null(&net->net_ni_list, + struct lnet_ni, + ni_netlist)) != NULL) { lnet_net_unlock(LNET_LOCK_EX); lnet_shutdown_lndni(ni); lnet_net_lock(LNET_LOCK_EX); @@ -2161,7 +2456,8 @@ lnet_shutdown_lndnets(void) /* NB called holding the global mutex */ /* All quiet on the API front */ - LASSERT(the_lnet.ln_state == LNET_STATE_RUNNING); + LASSERT(the_lnet.ln_state == LNET_STATE_RUNNING || + the_lnet.ln_state == LNET_STATE_STOPPING); LASSERT(the_lnet.ln_refcount == 0); lnet_net_lock(LNET_LOCK_EX); @@ -2182,11 +2478,10 @@ lnet_shutdown_lndnets(void) lnet_net_unlock(LNET_LOCK_EX); /* iterate through the net zombie list and delete each net */ - while (!list_empty(&the_lnet.ln_net_zombie)) { - net = list_entry(the_lnet.ln_net_zombie.next, - struct lnet_net, net_list); + while ((net = list_first_entry_or_null(&the_lnet.ln_net_zombie, + struct lnet_net, + net_list)) != NULL) lnet_shutdown_lndnet(net); - } spin_lock(&the_lnet.ln_msg_resend_lock); list_splice(&the_lnet.ln_msg_resend, &resend); @@ -2267,8 +2562,13 @@ lnet_startup_lndni(struct lnet_ni *ni, struct lnet_lnd_tunables *tun) lnet_ni_tq_credits(ni) * ni->ni_ncpts); atomic_set(&ni->ni_healthv, LNET_MAX_HEALTH_VALUE); + /* Nodes with small feet have little entropy. The NID for this + * node gives the most entropy in the low bits. + */ + add_device_randomness(&ni->ni_nid, sizeof(ni->ni_nid)); + CDEBUG(D_LNI, "Added LNI %s [%d/%d/%d/%d]\n", - libcfs_nid2str(ni->ni_nid), + libcfs_nidstr(&ni->ni_nid), ni->ni_net->net_tunables.lct_peer_tx_credits, lnet_ni_tq_credits(ni) * LNET_CPT_NUMBER, ni->ni_net->net_tunables.lct_peer_rtr_credits, @@ -2359,28 +2659,15 @@ lnet_startup_lndnet(struct lnet_net *net, struct lnet_lnd_tunables *tun) * After than we want to delete the network being added, * to avoid a memory leak. */ - - /* - * When a network uses TCP bonding then all its interfaces - * must be specified when the network is first defined: the - * TCP bonding code doesn't allow for interfaces to be added - * or removed. - */ - if (net_l != net && net_l != NULL && use_tcp_bonding && - LNET_NETTYP(net_l->net_id) == SOCKLND) { - rc = -EINVAL; - goto failed0; - } - - while (!list_empty(&net->net_ni_added)) { - ni = list_entry(net->net_ni_added.next, struct lnet_ni, - ni_netlist); + while ((ni = list_first_entry_or_null(&net->net_ni_added, + struct lnet_ni, + ni_netlist)) != NULL) { list_del_init(&ni->ni_netlist); /* make sure that the the NI we're about to start * up is actually unique. if it's not fail. */ if (!lnet_ni_unique_net(&net_l->net_ni_list, - ni->ni_interfaces[0])) { + ni->ni_interface)) { rc = -EEXIST; goto failed1; } @@ -2431,9 +2718,6 @@ lnet_startup_lndnet(struct lnet_net *net, struct lnet_lnd_tunables *tun) lnet_net_unlock(LNET_LOCK_EX); } - /* update net count */ - lnet_current_net_count = lnet_get_net_count(); - return ni_count; failed1: @@ -2441,12 +2725,10 @@ failed1: * shutdown the new NIs that are being started up * free the NET being started */ - while (!list_empty(&local_ni_list)) { - ni = list_entry(local_ni_list.next, struct lnet_ni, - ni_netlist); - + while ((ni = list_first_entry_or_null(&local_ni_list, + struct lnet_ni, + ni_netlist)) != NULL) lnet_shutdown_lndni(ni); - } failed0: lnet_net_free(net); @@ -2470,8 +2752,9 @@ lnet_startup_lndnets(struct list_head *netlist) the_lnet.ln_state = LNET_STATE_RUNNING; lnet_net_unlock(LNET_LOCK_EX); - while (!list_empty(netlist)) { - net = list_entry(netlist->next, struct lnet_net, net_list); + while ((net = list_first_entry_or_null(netlist, + struct lnet_net, + net_list)) != NULL) { list_del_init(&net->net_list); rc = lnet_startup_lndnet(net, NULL); @@ -2489,6 +2772,86 @@ failed: return rc; } +static int lnet_genl_parse_list(struct sk_buff *msg, + const struct ln_key_list *data[], u16 idx) +{ + const struct ln_key_list *list = data[idx]; + const struct ln_key_props *props; + struct nlattr *node; + u16 count; + + if (!list) + return 0; + + if (!list->lkl_maxattr) + return -ERANGE; + + props = list->lkl_list; + if (!props) + return -EINVAL; + + node = nla_nest_start(msg, LN_SCALAR_ATTR_LIST); + if (!node) + return -ENOBUFS; + + for (count = 1; count <= list->lkl_maxattr; count++) { + struct nlattr *key = nla_nest_start(msg, count); + + if (count == 1) + nla_put_u16(msg, LN_SCALAR_ATTR_LIST_SIZE, + list->lkl_maxattr); + + nla_put_u16(msg, LN_SCALAR_ATTR_INDEX, count); + if (props[count].lkp_value) + nla_put_string(msg, LN_SCALAR_ATTR_VALUE, + props[count].lkp_value); + if (props[count].lkp_key_format) + nla_put_u16(msg, LN_SCALAR_ATTR_KEY_FORMAT, + props[count].lkp_key_format); + nla_put_u16(msg, LN_SCALAR_ATTR_NLA_TYPE, + props[count].lkp_data_type); + if (props[count].lkp_data_type == NLA_NESTED) { + int rc; + + rc = lnet_genl_parse_list(msg, data, ++idx); + if (rc < 0) + return rc; + idx = rc; + } + + nla_nest_end(msg, key); + } + + nla_nest_end(msg, node); + return idx; +} + +int lnet_genl_send_scalar_list(struct sk_buff *msg, u32 portid, u32 seq, + const struct genl_family *family, int flags, + u8 cmd, const struct ln_key_list *data[]) +{ + int rc = 0; + void *hdr; + + if (!data[0]) + return -EINVAL; + + hdr = genlmsg_put(msg, portid, seq, family, flags, cmd); + if (!hdr) + GOTO(canceled, rc = -EMSGSIZE); + + rc = lnet_genl_parse_list(msg, data, 0); + if (rc < 0) + GOTO(canceled, rc); + + genlmsg_end(msg, hdr); +canceled: + if (rc < 0) + genlmsg_cancel(msg, hdr); + return rc > 0 ? 0 : rc; +} +EXPORT_SYMBOL(lnet_genl_send_scalar_list); + /** * Initialize LNet library. * @@ -2598,6 +2961,11 @@ LNetNIInit(lnet_pid_t requested_pid) CDEBUG(D_OTHER, "refs %d\n", the_lnet.ln_refcount); + if (the_lnet.ln_state == LNET_STATE_STOPPING) { + mutex_unlock(&the_lnet.ln_api_mutex); + return -ESHUTDOWN; + } + if (the_lnet.ln_refcount > 0) { rc = the_lnet.ln_refcount++; mutex_unlock(&the_lnet.ln_api_mutex); @@ -2623,6 +2991,9 @@ LNetNIInit(lnet_pid_t requested_pid) goto err_empty_list; } + if (use_tcp_bonding) + CWARN("use_tcp_bonding has been removed. Use Multi-Rail and Dynamic Discovery instead, see LU-13641\n"); + /* If LNet is being initialized via DLC it is possible * that the user requests not to load module parameters (ones which * are supported by DLC) on initialization. Therefore, make sure not @@ -2630,8 +3001,7 @@ LNetNIInit(lnet_pid_t requested_pid) * in this case. On cleanup in case of failure only clean up * routes if it has been loaded */ if (!the_lnet.ln_nis_from_mod_params) { - rc = lnet_parse_networks(&net_head, lnet_get_networks(), - use_tcp_bonding); + rc = lnet_parse_networks(&net_head, lnet_get_networks()); if (rc < 0) goto err_empty_list; } @@ -2709,10 +3079,9 @@ err_empty_list: lnet_unprepare(); LASSERT(rc < 0); mutex_unlock(&the_lnet.ln_api_mutex); - while (!list_empty(&net_head)) { - struct lnet_net *net; - - net = list_entry(net_head.next, struct lnet_net, net_list); + while ((net = list_first_entry_or_null(&net_head, + struct lnet_net, + net_list)) != NULL) { list_del_init(&net->net_list); lnet_net_free(net); } @@ -2741,6 +3110,10 @@ LNetNIFini(void) } else { LASSERT(!the_lnet.ln_niinit_self); + lnet_net_lock(LNET_LOCK_EX); + the_lnet.ln_state = LNET_STATE_STOPPING; + lnet_net_unlock(LNET_LOCK_EX); + lnet_fault_fini(); lnet_router_debugfs_fini(); @@ -2780,25 +3153,17 @@ lnet_fill_ni_info(struct lnet_ni *ni, struct lnet_ioctl_config_ni *cfg_ni, size_t min_size = 0; int i; - if (!ni || !cfg_ni || !tun) + if (!ni || !cfg_ni || !tun || !nid_is_nid4(&ni->ni_nid)) return; - if (ni->ni_interfaces[0] != NULL) { - for (i = 0; i < ARRAY_SIZE(ni->ni_interfaces); i++) { - if (ni->ni_interfaces[i] != NULL) { - strncpy(cfg_ni->lic_ni_intf[i], - ni->ni_interfaces[i], - sizeof(cfg_ni->lic_ni_intf[i])); - } - } + if (ni->ni_interface != NULL) { + strncpy(cfg_ni->lic_ni_intf, + ni->ni_interface, + sizeof(cfg_ni->lic_ni_intf)); } - cfg_ni->lic_nid = ni->ni_nid; - if (ni->ni_nid == LNET_NID_LO_0) - cfg_ni->lic_status = LNET_NI_STATUS_UP; - else - cfg_ni->lic_status = ni->ni_status->ns_status; - cfg_ni->lic_tcp_bonding = use_tcp_bonding; + cfg_ni->lic_nid = lnet_nid_to_nid4(&ni->ni_nid); + cfg_ni->lic_status = lnet_ni_get_status_locked(ni); cfg_ni->lic_dev_cpt = ni->ni_dev_cpt; memcpy(&tun->lt_cmn, &ni->ni_net->net_tunables, sizeof(tun->lt_cmn)); @@ -2857,26 +3222,21 @@ lnet_fill_ni_info_legacy(struct lnet_ni *ni, size_t min_size, tunable_size = 0; int i; - if (!ni || !config) + if (!ni || !config || !nid_is_nid4(&ni->ni_nid)) return; net_config = (struct lnet_ioctl_net_config *) config->cfg_bulk; if (!net_config) return; - BUILD_BUG_ON(ARRAY_SIZE(ni->ni_interfaces) != - ARRAY_SIZE(net_config->ni_interfaces)); - - for (i = 0; i < ARRAY_SIZE(ni->ni_interfaces); i++) { - if (!ni->ni_interfaces[i]) - break; + if (!ni->ni_interface) + return; - strncpy(net_config->ni_interfaces[i], - ni->ni_interfaces[i], - sizeof(net_config->ni_interfaces[i])); - } + strncpy(net_config->ni_interface, + ni->ni_interface, + sizeof(net_config->ni_interface)); - config->cfg_nid = ni->ni_nid; + config->cfg_nid = lnet_nid_to_nid4(&ni->ni_nid); config->cfg_config_u.cfg_net.net_peer_timeout = ni->ni_net->net_tunables.lct_peer_timeout; config->cfg_config_u.cfg_net.net_max_tx_credits = @@ -2886,10 +3246,7 @@ lnet_fill_ni_info_legacy(struct lnet_ni *ni, config->cfg_config_u.cfg_net.net_peer_rtr_credits = ni->ni_net->net_tunables.lct_peer_rtr_credits; - if (ni->ni_nid == LNET_NID_LO_0) - net_config->ni_status = LNET_NI_STATUS_UP; - else - net_config->ni_status = ni->ni_status->ns_status; + net_config->ni_status = lnet_ni_get_status_locked(ni); if (ni->ni_cpts) { int num_cpts = min(ni->ni_ncpts, LNET_MAX_SHOW_NUM_CPT); @@ -2941,6 +3298,22 @@ lnet_get_ni_idx_locked(int idx) return NULL; } +int lnet_get_net_healthv_locked(struct lnet_net *net) +{ + struct lnet_ni *ni; + int best_healthv = 0; + int healthv, ni_fatal; + + list_for_each_entry(ni, &net->net_ni_list, ni_netlist) { + healthv = atomic_read(&ni->ni_healthv); + ni_fatal = atomic_read(&ni->ni_fatal_error_on); + if (!ni_fatal && healthv > best_healthv) + best_healthv = healthv; + } + + return best_healthv; +} + struct lnet_ni * lnet_get_next_ni_locked(struct lnet_net *mynet, struct lnet_ni *prev) { @@ -2952,14 +3325,15 @@ lnet_get_next_ni_locked(struct lnet_net *mynet, struct lnet_ni *prev) * a message being sent. This function accessed the net without * checking if the list is empty */ - if (prev == NULL) { - if (net == NULL) - net = list_entry(the_lnet.ln_nets.next, struct lnet_net, - net_list); + if (!prev) { + if (!net) + net = list_first_entry(&the_lnet.ln_nets, + struct lnet_net, + net_list); if (list_empty(&net->net_ni_list)) return NULL; - ni = list_entry(net->net_ni_list.next, struct lnet_ni, - ni_netlist); + ni = list_first_entry(&net->net_ni_list, struct lnet_ni, + ni_netlist); return ni; } @@ -2977,13 +3351,13 @@ lnet_get_next_ni_locked(struct lnet_net *mynet, struct lnet_ni *prev) return NULL; /* get the next net */ - net = list_entry(prev->ni_net->net_list.next, struct lnet_net, - net_list); + net = list_first_entry(&prev->ni_net->net_list, struct lnet_net, + net_list); if (list_empty(&net->net_ni_list)) return NULL; /* get the ni on it */ - ni = list_entry(net->net_ni_list.next, struct lnet_ni, - ni_netlist); + ni = list_first_entry(&net->net_ni_list, struct lnet_ni, + ni_netlist); return ni; } @@ -2992,7 +3366,7 @@ lnet_get_next_ni_locked(struct lnet_net *mynet, struct lnet_ni *prev) return NULL; /* there are more nis left */ - ni = list_entry(prev->ni_netlist.next, struct lnet_ni, ni_netlist); + ni = list_first_entry(&prev->ni_netlist, struct lnet_ni, ni_netlist); return ni; } @@ -3074,12 +3448,13 @@ int lnet_get_ni_stats(struct lnet_ioctl_element_msg_stats *msg_stats) static int lnet_add_net_common(struct lnet_net *net, struct lnet_ioctl_config_lnd_tunables *tun) { - __u32 net_id; + struct lnet_handle_md ping_mdh; struct lnet_ping_buffer *pbuf; - struct lnet_handle_md ping_mdh; - int rc; struct lnet_remotenet *rnet; - int net_ni_count; + struct lnet_ni *ni; + int net_ni_count; + __u32 net_id; + int rc; lnet_net_lock(LNET_LOCK_EX); rnet = lnet_find_rnet_locked(net->net_id); @@ -3129,10 +3504,25 @@ static int lnet_add_net_common(struct lnet_net *net, lnet_net_lock(LNET_LOCK_EX); net = lnet_get_net_locked(net_id); - lnet_net_unlock(LNET_LOCK_EX); - LASSERT(net); + /* apply the UDSPs */ + rc = lnet_udsp_apply_policies_on_net(net); + if (rc) + CERROR("Failed to apply UDSPs on local net %s\n", + libcfs_net2str(net->net_id)); + + /* At this point we lost track of which NI was just added, so we + * just re-apply the policies on all of the NIs on this net + */ + list_for_each_entry(ni, &net->net_ni_list, ni_netlist) { + rc = lnet_udsp_apply_policies_on_ni(ni); + if (rc) + CERROR("Failed to apply UDSPs on ni %s\n", + libcfs_nidstr(&ni->ni_nid)); + } + lnet_net_unlock(LNET_LOCK_EX); + /* * Start the acceptor thread if this is the first network * being added that requires the thread. @@ -3161,6 +3551,19 @@ failed: return rc; } +static void +lnet_set_tune_defaults(struct lnet_ioctl_config_lnd_tunables *tun) +{ + if (tun) { + if (!tun->lt_cmn.lct_peer_timeout) + tun->lt_cmn.lct_peer_timeout = DEFAULT_PEER_TIMEOUT; + if (!tun->lt_cmn.lct_peer_tx_credits) + tun->lt_cmn.lct_peer_tx_credits = DEFAULT_PEER_CREDITS; + if (!tun->lt_cmn.lct_max_tx_credits) + tun->lt_cmn.lct_max_tx_credits = DEFAULT_CREDITS; + } +} + static int lnet_handle_legacy_ip2nets(char *ip2nets, struct lnet_ioctl_config_lnd_tunables *tun) { @@ -3173,13 +3576,21 @@ static int lnet_handle_legacy_ip2nets(char *ip2nets, if (rc < 0) return rc; - rc = lnet_parse_networks(&net_head, nets, use_tcp_bonding); + rc = lnet_parse_networks(&net_head, nets); if (rc < 0) return rc; + lnet_set_tune_defaults(tun); + mutex_lock(&the_lnet.ln_api_mutex); - while (!list_empty(&net_head)) { - net = list_entry(net_head.next, struct lnet_net, net_list); + if (the_lnet.ln_state != LNET_STATE_RUNNING) { + rc = -ESHUTDOWN; + goto out; + } + + while ((net = list_first_entry_or_null(&net_head, + struct lnet_net, + net_list)) != NULL) { list_del_init(&net->net_list); rc = lnet_add_net_common(net, tun); if (rc < 0) @@ -3189,8 +3600,9 @@ static int lnet_handle_legacy_ip2nets(char *ip2nets, out: mutex_unlock(&the_lnet.ln_api_mutex); - while (!list_empty(&net_head)) { - net = list_entry(net_head.next, struct lnet_net, net_list); + while ((net = list_first_entry_or_null(&net_head, + struct lnet_net, + net_list)) != NULL) { list_del_init(&net->net_list); lnet_net_free(net); } @@ -3234,13 +3646,17 @@ int lnet_dyn_add_ni(struct lnet_ioctl_config_ni *conf) } ni = lnet_ni_alloc_w_cpt_array(net, conf->lic_cpts, conf->lic_ncpts, - conf->lic_ni_intf[0]); + conf->lic_ni_intf); if (!ni) return -ENOMEM; - mutex_lock(&the_lnet.ln_api_mutex); + lnet_set_tune_defaults(tun); - rc = lnet_add_net_common(net, tun); + mutex_lock(&the_lnet.ln_api_mutex); + if (the_lnet.ln_state != LNET_STATE_RUNNING) + rc = -ESHUTDOWN; + else + rc = lnet_add_net_common(net, tun); mutex_unlock(&the_lnet.ln_api_mutex); @@ -3263,6 +3679,10 @@ int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf) return -EINVAL; mutex_lock(&the_lnet.ln_api_mutex); + if (the_lnet.ln_state != LNET_STATE_RUNNING) { + rc = -ESHUTDOWN; + goto unlock_api_mutex; + } lnet_net_lock(0); @@ -3351,18 +3771,22 @@ lnet_dyn_add_net(struct lnet_ioctl_config_data *conf) const char *nets = conf->cfg_config_u.cfg_net.net_intf; /* Create a net/ni structures for the network string */ - rc = lnet_parse_networks(&net_head, nets, use_tcp_bonding); + rc = lnet_parse_networks(&net_head, nets); if (rc <= 0) return rc == 0 ? -EINVAL : rc; mutex_lock(&the_lnet.ln_api_mutex); + if (the_lnet.ln_state != LNET_STATE_RUNNING) { + rc = -ESHUTDOWN; + goto out_unlock_clean; + } if (rc > 1) { rc = -EINVAL; /* only add one network per call */ goto out_unlock_clean; } - net = list_entry(net_head.next, struct lnet_net, net_list); + net = list_first_entry(&net_head, struct lnet_net, net_list); list_del_init(&net->net_list); LASSERT(lnet_net_unique(net->net_id, &the_lnet.ln_nets, NULL)); @@ -3370,21 +3794,25 @@ lnet_dyn_add_net(struct lnet_ioctl_config_data *conf) memset(&tun, 0, sizeof(tun)); tun.lt_cmn.lct_peer_timeout = - conf->cfg_config_u.cfg_net.net_peer_timeout; + (!conf->cfg_config_u.cfg_net.net_peer_timeout) ? DEFAULT_PEER_TIMEOUT : + conf->cfg_config_u.cfg_net.net_peer_timeout; tun.lt_cmn.lct_peer_tx_credits = - conf->cfg_config_u.cfg_net.net_peer_tx_credits; + (!conf->cfg_config_u.cfg_net.net_peer_tx_credits) ? DEFAULT_PEER_CREDITS : + conf->cfg_config_u.cfg_net.net_peer_tx_credits; tun.lt_cmn.lct_peer_rtr_credits = conf->cfg_config_u.cfg_net.net_peer_rtr_credits; tun.lt_cmn.lct_max_tx_credits = - conf->cfg_config_u.cfg_net.net_max_tx_credits; + (!conf->cfg_config_u.cfg_net.net_max_tx_credits) ? DEFAULT_CREDITS : + conf->cfg_config_u.cfg_net.net_max_tx_credits; rc = lnet_add_net_common(net, &tun); out_unlock_clean: mutex_unlock(&the_lnet.ln_api_mutex); - while (!list_empty(&net_head)) { - /* net_head list is empty in success case */ - net = list_entry(net_head.next, struct lnet_net, net_list); + /* net_head list is empty in success case */ + while ((net = list_first_entry_or_null(&net_head, + struct lnet_net, + net_list)) != NULL) { list_del_init(&net->net_list); lnet_net_free(net); } @@ -3405,6 +3833,10 @@ lnet_dyn_del_net(__u32 net_id) return -EINVAL; mutex_lock(&the_lnet.ln_api_mutex); + if (the_lnet.ln_state != LNET_STATE_RUNNING) { + rc = -ESHUTDOWN; + goto out; + } lnet_net_lock(0); @@ -3456,12 +3888,13 @@ lnet_ni_set_healthv(lnet_nid_t nid, int value, bool all) lnet_net_lock(LNET_LOCK_EX); list_for_each_entry(net, &the_lnet.ln_nets, net_list) { list_for_each_entry(ni, &net->net_ni_list, ni_netlist) { - if (ni->ni_nid == nid || all) { + if (all || (nid_is_nid4(&ni->ni_nid) && + lnet_nid_to_nid4(&ni->ni_nid) == nid)) { atomic_set(&ni->ni_healthv, value); if (list_empty(&ni->ni_recovery) && value < LNET_MAX_HEALTH_VALUE) { CERROR("manually adding local NI %s to recovery\n", - libcfs_nid2str(ni->ni_nid)); + libcfs_nidstr(&ni->ni_nid)); list_add_tail(&ni->ni_recovery, &the_lnet.ln_mt_localNIRecovq); lnet_ni_addref_locked(ni, 0); @@ -3476,6 +3909,30 @@ lnet_ni_set_healthv(lnet_nid_t nid, int value, bool all) lnet_net_unlock(LNET_LOCK_EX); } +static void +lnet_ni_set_conns_per_peer(lnet_nid_t nid, int value, bool all) +{ + struct lnet_net *net; + struct lnet_ni *ni; + + lnet_net_lock(LNET_LOCK_EX); + list_for_each_entry(net, &the_lnet.ln_nets, net_list) { + list_for_each_entry(ni, &net->net_ni_list, ni_netlist) { + if (lnet_nid_to_nid4(&ni->ni_nid) != nid && !all) + continue; + if (LNET_NETTYP(net->net_id) == SOCKLND) + ni->ni_lnd_tunables.lnd_tun_u.lnd_sock.lnd_conns_per_peer = value; + else if (LNET_NETTYP(net->net_id) == O2IBLND) + ni->ni_lnd_tunables.lnd_tun_u.lnd_o2ib.lnd_conns_per_peer = value; + if (!all) { + lnet_net_unlock(LNET_LOCK_EX); + return; + } + } + } + lnet_net_unlock(LNET_LOCK_EX); +} + static int lnet_get_local_ni_hstats(struct lnet_ioctl_local_ni_hstats *stats) { @@ -3497,7 +3954,10 @@ lnet_get_local_ni_hstats(struct lnet_ioctl_local_ni_hstats *stats) stats->hlni_local_no_route = atomic_read(&ni->ni_hstats.hlt_local_no_route); stats->hlni_local_timeout = atomic_read(&ni->ni_hstats.hlt_local_timeout); stats->hlni_local_error = atomic_read(&ni->ni_hstats.hlt_local_error); + stats->hlni_fatal_error = atomic_read(&ni->ni_fatal_error_on); stats->hlni_health_value = atomic_read(&ni->ni_healthv); + stats->hlni_ping_count = ni->ni_ping_count; + stats->hlni_next_ping = ni->ni_next_ping; unlock: lnet_net_unlock(cpt); @@ -3513,7 +3973,9 @@ lnet_get_local_ni_recovery_list(struct lnet_ioctl_recovery_list *list) lnet_net_lock(LNET_LOCK_EX); list_for_each_entry(ni, &the_lnet.ln_mt_localNIRecovq, ni_recovery) { - list->rlst_nid_array[i] = ni->ni_nid; + if (!nid_is_nid4(&ni->ni_nid)) + continue; + list->rlst_nid_array[i] = lnet_nid_to_nid4(&ni->ni_nid); i++; if (i >= LNET_MAX_SHOW_NUM_NID) break; @@ -3532,7 +3994,7 @@ lnet_get_peer_ni_recovery_list(struct lnet_ioctl_recovery_list *list) lnet_net_lock(LNET_LOCK_EX); list_for_each_entry(lpni, &the_lnet.ln_mt_peerNIRecovq, lpni_recovery) { - list->rlst_nid_array[i] = lpni->lpni_nid; + list->rlst_nid_array[i] = lnet_nid_to_nid4(&lpni->lpni_nid); i++; if (i >= LNET_MAX_SHOW_NUM_NID) break; @@ -3552,8 +4014,10 @@ LNetCtl(unsigned int cmd, void *arg) { struct libcfs_ioctl_data *data = arg; struct lnet_ioctl_config_data *config; - struct lnet_process_id id = {0}; + struct lnet_process_id id4 = {}; + struct lnet_processid id = {}; struct lnet_ni *ni; + struct lnet_nid nid; int rc; BUILD_BUG_ON(sizeof(struct lnet_ioctl_net_config) + @@ -3562,7 +4026,7 @@ LNetCtl(unsigned int cmd, void *arg) switch (cmd) { case IOC_LIBCFS_GET_NI: rc = LNetGetId(data->ioc_count, &id); - data->ioc_nid = id.nid; + data->ioc_nid = lnet_nid_to_nid4(&id.nid); return rc; case IOC_LIBCFS_FAIL_NID: @@ -3581,10 +4045,11 @@ LNetCtl(unsigned int cmd, void *arg) config->cfg_config_u.cfg_route.rtr_sensitivity; } + lnet_nid4_to_nid(config->cfg_nid, &nid); mutex_lock(&the_lnet.ln_api_mutex); rc = lnet_add_route(config->cfg_net, config->cfg_config_u.cfg_route.rtr_hop, - config->cfg_nid, + &nid, config->cfg_config_u.cfg_route. rtr_priority, sensitivity); mutex_unlock(&the_lnet.ln_api_mutex); @@ -3597,8 +4062,9 @@ LNetCtl(unsigned int cmd, void *arg) if (config->cfg_hdr.ioc_len < sizeof(*config)) return -EINVAL; + lnet_nid4_to_nid(config->cfg_nid, &nid); mutex_lock(&the_lnet.ln_api_mutex); - rc = lnet_del_route(config->cfg_net, config->cfg_nid); + rc = lnet_del_route(config->cfg_net, &nid); mutex_unlock(&the_lnet.ln_api_mutex); return rc; @@ -3683,7 +4149,15 @@ LNetCtl(unsigned int cmd, void *arg) return -EINVAL; mutex_lock(&the_lnet.ln_api_mutex); - lnet_counters_get(&lnet_stats->st_cntrs); + rc = lnet_counters_get(&lnet_stats->st_cntrs); + mutex_unlock(&the_lnet.ln_api_mutex); + return rc; + } + + case IOC_LIBCFS_RESET_LNET_STATS: + { + mutex_lock(&the_lnet.ln_api_mutex); + lnet_counters_reset(); mutex_unlock(&the_lnet.ln_api_mutex); return 0; } @@ -3786,27 +4260,31 @@ LNetCtl(unsigned int cmd, void *arg) case IOC_LIBCFS_ADD_PEER_NI: { struct lnet_ioctl_peer_cfg *cfg = arg; + struct lnet_nid prim_nid; if (cfg->prcfg_hdr.ioc_len < sizeof(*cfg)) return -EINVAL; mutex_lock(&the_lnet.ln_api_mutex); - rc = lnet_add_peer_ni(cfg->prcfg_prim_nid, - cfg->prcfg_cfg_nid, - cfg->prcfg_mr); + lnet_nid4_to_nid(cfg->prcfg_prim_nid, &prim_nid); + lnet_nid4_to_nid(cfg->prcfg_cfg_nid, &nid); + rc = lnet_add_peer_ni(&prim_nid, &nid, cfg->prcfg_mr, false); mutex_unlock(&the_lnet.ln_api_mutex); return rc; } case IOC_LIBCFS_DEL_PEER_NI: { struct lnet_ioctl_peer_cfg *cfg = arg; + struct lnet_nid prim_nid; if (cfg->prcfg_hdr.ioc_len < sizeof(*cfg)) return -EINVAL; mutex_lock(&the_lnet.ln_api_mutex); - rc = lnet_del_peer_ni(cfg->prcfg_prim_nid, - cfg->prcfg_cfg_nid); + lnet_nid4_to_nid(cfg->prcfg_prim_nid, &prim_nid); + lnet_nid4_to_nid(cfg->prcfg_cfg_nid, &nid); + rc = lnet_del_peer_ni(&prim_nid, + &nid); mutex_unlock(&the_lnet.ln_api_mutex); return rc; } @@ -3883,6 +4361,25 @@ LNetCtl(unsigned int cmd, void *arg) return 0; } + case IOC_LIBCFS_SET_CONNS_PER_PEER: { + struct lnet_ioctl_reset_conns_per_peer_cfg *cfg = arg; + int value; + + if (cfg->rcpp_hdr.ioc_len < sizeof(*cfg)) + return -EINVAL; + if (cfg->rcpp_value < 0) + value = 1; + else + value = cfg->rcpp_value; + CDEBUG(D_NET, + "Setting conns_per_peer to %d for %s. all = %d\n", + value, libcfs_nid2str(cfg->rcpp_nid), cfg->rcpp_all); + mutex_lock(&the_lnet.ln_api_mutex); + lnet_ni_set_conns_per_peer(cfg->rcpp_nid, value, cfg->rcpp_all); + mutex_unlock(&the_lnet.ln_api_mutex); + return 0; + } + case IOC_LIBCFS_NOTIFY_ROUTER: { time64_t deadline = ktime_get_real_seconds() - data->ioc_u64[0]; @@ -3896,10 +4393,12 @@ LNetCtl(unsigned int cmd, void *arg) } case IOC_LIBCFS_LNET_DIST: - rc = LNetDist(data->ioc_nid, &data->ioc_nid, &data->ioc_u32[1]); + lnet_nid4_to_nid(data->ioc_nid, &nid); + rc = LNetDist(&nid, &nid, &data->ioc_u32[1]); if (rc < 0 && rc != -EHOSTUNREACH) return rc; + data->ioc_nid = lnet_nid_to_nid4(&nid); data->ioc_u32[0] = rc; return 0; @@ -3913,8 +4412,8 @@ LNetCtl(unsigned int cmd, void *arg) case IOC_LIBCFS_PING: { signed long timeout; - id.nid = data->ioc_nid; - id.pid = data->ioc_u32[0]; + id4.nid = data->ioc_nid; + id4.pid = data->ioc_u32[0]; /* If timeout is negative then set default of 3 minutes */ if (((s32)data->ioc_u32[1] <= 0) || @@ -3923,7 +4422,7 @@ LNetCtl(unsigned int cmd, void *arg) else timeout = nsecs_to_jiffies(data->ioc_u32[1] * NSEC_PER_MSEC); - rc = lnet_ping(id, timeout, data->ioc_pbuf1, + rc = lnet_ping(id4, &LNET_ANY_NID, timeout, data->ioc_pbuf1, data->ioc_plen1 / sizeof(struct lnet_process_id)); if (rc < 0) @@ -3935,9 +4434,21 @@ LNetCtl(unsigned int cmd, void *arg) case IOC_LIBCFS_PING_PEER: { struct lnet_ioctl_ping_data *ping = arg; + struct lnet_nid src_nid = LNET_ANY_NID; struct lnet_peer *lp; signed long timeout; + /* Check if the supplied ping data supports source nid + * NB: This check is sufficient if lnet_ioctl_ping_data has + * additional fields added, but if they are re-ordered or + * fields removed then this will break. It is expected that + * these ioctls will be replaced with netlink implementation, so + * it is probably not worth coming up with a more robust version + * compatibility scheme. + */ + if (ping->ping_hdr.ioc_len >= sizeof(struct lnet_ioctl_ping_data)) + lnet_nid4_to_nid(ping->ping_src, &src_nid); + /* If timeout is negative then set default of 3 minutes */ if (((s32)ping->op_param) <= 0 || ping->op_param > (DEFAULT_PEER_TIMEOUT * MSEC_PER_SEC)) @@ -3945,16 +4456,18 @@ LNetCtl(unsigned int cmd, void *arg) else timeout = nsecs_to_jiffies(ping->op_param * NSEC_PER_MSEC); - rc = lnet_ping(ping->ping_id, timeout, + rc = lnet_ping(ping->ping_id, &src_nid, timeout, ping->ping_buf, ping->ping_count); if (rc < 0) return rc; mutex_lock(&the_lnet.ln_api_mutex); - lp = lnet_find_peer(ping->ping_id.nid); + lnet_nid4_to_nid(ping->ping_id.nid, &nid); + lp = lnet_find_peer(&nid); if (lp) { - ping->ping_id.nid = lp->lp_primary_nid; + ping->ping_id.nid = + lnet_nid_to_nid4(&lp->lp_primary_nid); ping->mr_info = lnet_peer_is_multi_rail(lp); lnet_peer_decref_locked(lp); } @@ -3975,9 +4488,11 @@ LNetCtl(unsigned int cmd, void *arg) return rc; mutex_lock(&the_lnet.ln_api_mutex); - lp = lnet_find_peer(discover->ping_id.nid); + lnet_nid4_to_nid(discover->ping_id.nid, &nid); + lp = lnet_find_peer(&nid); if (lp) { - discover->ping_id.nid = lp->lp_primary_nid; + discover->ping_id.nid = + lnet_nid_to_nid4(&lp->lp_primary_nid); discover->mr_info = lnet_peer_is_multi_rail(lp); lnet_peer_decref_locked(lp); } @@ -3987,6 +4502,106 @@ LNetCtl(unsigned int cmd, void *arg) return 0; } + case IOC_LIBCFS_ADD_UDSP: { + struct lnet_ioctl_udsp *ioc_udsp = arg; + __u32 bulk_size = ioc_udsp->iou_hdr.ioc_len; + + mutex_lock(&the_lnet.ln_api_mutex); + rc = lnet_udsp_demarshal_add(arg, bulk_size); + if (!rc) { + rc = lnet_udsp_apply_policies(NULL, false); + CDEBUG(D_NET, "policy application returned %d\n", rc); + rc = 0; + } + mutex_unlock(&the_lnet.ln_api_mutex); + + return rc; + } + + case IOC_LIBCFS_DEL_UDSP: { + struct lnet_ioctl_udsp *ioc_udsp = arg; + int idx = ioc_udsp->iou_idx; + + if (ioc_udsp->iou_hdr.ioc_len < sizeof(*ioc_udsp)) + return -EINVAL; + + mutex_lock(&the_lnet.ln_api_mutex); + rc = lnet_udsp_del_policy(idx); + if (!rc) { + rc = lnet_udsp_apply_policies(NULL, false); + CDEBUG(D_NET, "policy re-application returned %d\n", + rc); + rc = 0; + } + mutex_unlock(&the_lnet.ln_api_mutex); + + return rc; + } + + case IOC_LIBCFS_GET_UDSP_SIZE: { + struct lnet_ioctl_udsp *ioc_udsp = arg; + struct lnet_udsp *udsp; + + if (ioc_udsp->iou_hdr.ioc_len < sizeof(*ioc_udsp)) + return -EINVAL; + + rc = 0; + + mutex_lock(&the_lnet.ln_api_mutex); + udsp = lnet_udsp_get_policy(ioc_udsp->iou_idx); + if (!udsp) { + rc = -ENOENT; + } else { + /* coming in iou_idx will hold the idx of the udsp + * to get the size of. going out the iou_idx will + * hold the size of the UDSP found at the passed + * in index. + */ + ioc_udsp->iou_idx = lnet_get_udsp_size(udsp); + if (ioc_udsp->iou_idx < 0) + rc = -EINVAL; + } + mutex_unlock(&the_lnet.ln_api_mutex); + + return rc; + } + + case IOC_LIBCFS_GET_UDSP: { + struct lnet_ioctl_udsp *ioc_udsp = arg; + struct lnet_udsp *udsp; + + if (ioc_udsp->iou_hdr.ioc_len < sizeof(*ioc_udsp)) + return -EINVAL; + + rc = 0; + + mutex_lock(&the_lnet.ln_api_mutex); + udsp = lnet_udsp_get_policy(ioc_udsp->iou_idx); + if (!udsp) + rc = -ENOENT; + else + rc = lnet_udsp_marshal(udsp, ioc_udsp); + mutex_unlock(&the_lnet.ln_api_mutex); + + return rc; + } + + case IOC_LIBCFS_GET_CONST_UDSP_INFO: { + struct lnet_ioctl_construct_udsp_info *info = arg; + + if (info->cud_hdr.ioc_len < sizeof(*info)) + return -EINVAL; + + CDEBUG(D_NET, "GET_UDSP_INFO for %s\n", + libcfs_nid2str(info->cud_nid)); + + mutex_lock(&the_lnet.ln_api_mutex); + lnet_udsp_get_construct_info(info); + mutex_unlock(&the_lnet.ln_api_mutex); + + return 0; + } + default: ni = lnet_net2ni_addref(data->ioc_net); if (ni == NULL) @@ -4004,9 +4619,9 @@ LNetCtl(unsigned int cmd, void *arg) } EXPORT_SYMBOL(LNetCtl); -void LNetDebugPeer(struct lnet_process_id id) +void LNetDebugPeer(struct lnet_processid *id) { - lnet_debug_peer(id.nid); + lnet_debug_peer(lnet_nid_to_nid4(&id->nid)); } EXPORT_SYMBOL(LNetDebugPeer); @@ -4018,7 +4633,7 @@ EXPORT_SYMBOL(LNetDebugPeer); * \retval true If peer NID is on the local node. * \retval false If peer NID is not on the local node. */ -bool LNetIsPeerLocal(lnet_nid_t nid) +bool LNetIsPeerLocal(struct lnet_nid *nid) { struct lnet_net *net; struct lnet_ni *ni; @@ -4027,7 +4642,7 @@ bool LNetIsPeerLocal(lnet_nid_t nid) cpt = lnet_net_lock_current(); list_for_each_entry(net, &the_lnet.ln_nets, net_list) { list_for_each_entry(ni, &net->net_ni_list, ni_netlist) { - if (ni->ni_nid == nid) { + if (nid_same(&ni->ni_nid, nid)) { lnet_net_unlock(cpt); return true; } @@ -4051,7 +4666,7 @@ EXPORT_SYMBOL(LNetIsPeerLocal); * \retval -ENOENT If no interface has been found. */ int -LNetGetId(unsigned int index, struct lnet_process_id *id) +LNetGetId(unsigned int index, struct lnet_processid *id) { struct lnet_ni *ni; struct lnet_net *net; @@ -4064,6 +4679,9 @@ LNetGetId(unsigned int index, struct lnet_process_id *id) list_for_each_entry(net, &the_lnet.ln_nets, net_list) { list_for_each_entry(ni, &net->net_ni_list, ni_netlist) { + if (!nid_is_nid4(&ni->ni_nid)) + /* FIXME this needs to be handled */ + continue; if (index-- != 0) continue; @@ -4106,20 +4724,22 @@ lnet_ping_event_handler(struct lnet_event *event) complete(&pd->completion); } -static int lnet_ping(struct lnet_process_id id, signed long timeout, - struct lnet_process_id __user *ids, int n_ids) +static int lnet_ping(struct lnet_process_id id4, struct lnet_nid *src_nid, + signed long timeout, struct lnet_process_id __user *ids, + int n_ids) { struct lnet_md md = { NULL }; struct ping_data pd = { 0 }; struct lnet_ping_buffer *pbuf; struct lnet_process_id tmpid; + struct lnet_processid id; int i; int nob; int rc; int rc2; /* n_ids limit is arbitrary */ - if (n_ids <= 0 || id.nid == LNET_NID_ANY) + if (n_ids <= 0 || id4.nid == LNET_NID_ANY) return -EINVAL; /* @@ -4129,8 +4749,8 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, if (n_ids > lnet_interfaces_max) n_ids = lnet_interfaces_max; - if (id.pid == LNET_PID_ANY) - id.pid = LNET_PID_LUSTRE; + if (id4.pid == LNET_PID_ANY) + id4.pid = LNET_PID_LUSTRE; pbuf = lnet_ping_buffer_alloc(n_ids, GFP_NOFS); if (!pbuf) @@ -4153,8 +4773,8 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, goto fail_ping_buffer_decref; } - rc = LNetGet(LNET_NID_ANY, pd.mdh, id, - LNET_RESERVED_PORTAL, + lnet_pid4_to_pid(id4, &id); + rc = LNetGet(src_nid, pd.mdh, &id, LNET_RESERVED_PORTAL, LNET_PROTO_PING_MATCHBITS, 0, false); if (rc != 0) { @@ -4182,7 +4802,7 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, if (nob < 8) { CERROR("%s: ping info too short %d\n", - libcfs_id2str(id), nob); + libcfs_idstr(&id), nob); goto fail_ping_buffer_decref; } @@ -4190,19 +4810,19 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, lnet_swap_pinginfo(pbuf); } else if (pbuf->pb_info.pi_magic != LNET_PROTO_PING_MAGIC) { CERROR("%s: Unexpected magic %08x\n", - libcfs_id2str(id), pbuf->pb_info.pi_magic); + libcfs_idstr(&id), pbuf->pb_info.pi_magic); goto fail_ping_buffer_decref; } if ((pbuf->pb_info.pi_features & LNET_PING_FEAT_NI_STATUS) == 0) { CERROR("%s: ping w/o NI status: 0x%x\n", - libcfs_id2str(id), pbuf->pb_info.pi_features); + libcfs_idstr(&id), pbuf->pb_info.pi_features); goto fail_ping_buffer_decref; } if (nob < LNET_PING_INFO_SIZE(0)) { CERROR("%s: Short reply %d(%d min)\n", - libcfs_id2str(id), + libcfs_idstr(&id), nob, (int)LNET_PING_INFO_SIZE(0)); goto fail_ping_buffer_decref; } @@ -4212,7 +4832,7 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, if (nob < LNET_PING_INFO_SIZE(n_ids)) { CERROR("%s: Short reply %d(%d expected)\n", - libcfs_id2str(id), + libcfs_idstr(&id), nob, (int)LNET_PING_INFO_SIZE(n_ids)); goto fail_ping_buffer_decref; } @@ -4234,21 +4854,23 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, } static int -lnet_discover(struct lnet_process_id id, __u32 force, +lnet_discover(struct lnet_process_id id4, __u32 force, struct lnet_process_id __user *ids, int n_ids) { struct lnet_peer_ni *lpni; struct lnet_peer_ni *p; struct lnet_peer *lp; struct lnet_process_id *buf; + struct lnet_processid id; int cpt; int i; int rc; if (n_ids <= 0 || - id.nid == LNET_NID_ANY) + id4.nid == LNET_NID_ANY) return -EINVAL; + lnet_pid4_to_pid(id4, &id); if (id.pid == LNET_PID_ANY) id.pid = LNET_PID_LUSTRE; @@ -4264,7 +4886,7 @@ lnet_discover(struct lnet_process_id id, __u32 force, return -ENOMEM; cpt = lnet_net_lock_current(); - lpni = lnet_nid2peerni_locked(id.nid, LNET_NID_ANY, cpt); + lpni = lnet_peerni_by_nid_locked(&id.nid, NULL, cpt); if (IS_ERR(lpni)) { rc = PTR_ERR(lpni); goto out; @@ -4285,11 +4907,23 @@ lnet_discover(struct lnet_process_id id, __u32 force, if (rc) goto out_decref; + /* The lpni (or lp) for this NID may have changed and our ref is + * the only thing keeping the old one around. Release the ref + * and lookup the lpni again + */ + lnet_peer_ni_decref_locked(lpni); + lpni = lnet_peer_ni_find_locked(&id.nid); + if (!lpni) { + rc = -ENOENT; + goto out; + } + lp = lpni->lpni_peer_net->lpn_peer; + i = 0; p = NULL; while ((p = lnet_get_next_peer_ni_locked(lp, NULL, p)) != NULL) { buf[i].pid = id.pid; - buf[i].nid = p->lpni_nid; + buf[i].nid = lnet_nid_to_nid4(&p->lpni_nid); if (++i >= n_ids) break; }