CFS_INIT_LIST_HEAD(&the_lnet.ln_test_peers);
CFS_INIT_LIST_HEAD(&the_lnet.ln_nis);
+ CFS_INIT_LIST_HEAD(&the_lnet.ln_nis_cpt);
CFS_INIT_LIST_HEAD(&the_lnet.ln_nis_zombie);
CFS_INIT_LIST_HEAD(&the_lnet.ln_remote_nets);
CFS_INIT_LIST_HEAD(&the_lnet.ln_routers);
LASSERT(the_lnet.ln_refcount == 0);
LASSERT(cfs_list_empty(&the_lnet.ln_test_peers));
LASSERT(cfs_list_empty(&the_lnet.ln_nis));
+ LASSERT(cfs_list_empty(&the_lnet.ln_nis_cpt));
LASSERT(cfs_list_empty(&the_lnet.ln_nis_zombie));
lnet_portals_destroy();
return NULL;
}
-unsigned int
-lnet_nid_cpt_hash(lnet_nid_t nid)
+static unsigned int
+lnet_nid_cpt_hash(lnet_nid_t nid, unsigned int number)
{
__u64 key = nid;
unsigned int val;
+ LASSERT(number >= 1 && number <= LNET_CPT_NUMBER);
+
+ if (number == 1)
+ return 0;
+
val = cfs_hash_long(key, LNET_CPT_BITS);
/* NB: LNET_CP_NUMBER doesn't have to be PO2 */
- if (val < LNET_CPT_NUMBER)
+ if (val < number)
return val;
- return (unsigned int)((key + val + (val >> 1)) % LNET_CPT_NUMBER);
+ return (unsigned int)((key + val + (val >> 1)) % number);
+}
+
+int
+lnet_cpt_of_nid_locked(lnet_nid_t nid)
+{
+ struct lnet_ni *ni;
+
+ /* must called with hold of lnet_net_lock */
+ if (LNET_CPT_NUMBER == 1)
+ return 0; /* the only one */
+
+ /* take lnet_net_lock(any) would be OK */
+ if (!cfs_list_empty(&the_lnet.ln_nis_cpt)) {
+ cfs_list_for_each_entry(ni, &the_lnet.ln_nis_cpt, ni_cptlist) {
+ if (LNET_NIDNET(ni->ni_nid) != LNET_NIDNET(nid))
+ continue;
+
+ LASSERT(ni->ni_cpts != NULL);
+ return ni->ni_cpts[lnet_nid_cpt_hash
+ (nid, ni->ni_ncpts)];
+ }
+ }
+
+ return lnet_nid_cpt_hash(nid, LNET_CPT_NUMBER);
}
int
lnet_cpt_of_nid(lnet_nid_t nid)
{
+ int cpt;
+ int cpt2;
+
if (LNET_CPT_NUMBER == 1)
return 0; /* the only one */
- return lnet_nid_cpt_hash(nid);
+ if (cfs_list_empty(&the_lnet.ln_nis_cpt))
+ return lnet_nid_cpt_hash(nid, LNET_CPT_NUMBER);
+
+ cpt = lnet_net_lock_current();
+ cpt2 = lnet_cpt_of_nid_locked(nid);
+ lnet_net_unlock(cpt);
+
+ return cpt2;
}
EXPORT_SYMBOL(lnet_cpt_of_nid);
{
int credits;
- credits = ni->ni_maxtxcredits / LNET_CPT_NUMBER;
+ LASSERT(ni->ni_ncpts >= 1);
+
+ if (ni->ni_ncpts == 1)
+ return ni->ni_maxtxcredits;
+
+ credits = ni->ni_maxtxcredits / ni->ni_ncpts;
credits = max(credits, 8 * ni->ni_peertxcredits);
credits = min(credits, ni->ni_maxtxcredits);
/* move it to zombie list and nobody can find it anymore */
cfs_list_move(&ni->ni_list, &the_lnet.ln_nis_zombie);
lnet_ni_decref_locked(ni, 0); /* drop ln_nis' ref */
+
+ if (!cfs_list_empty(&ni->ni_cptlist)) {
+ cfs_list_del_init(&ni->ni_cptlist);
+ lnet_ni_decref_locked(ni, 0);
+ }
}
/* Drop the cached eqwait NI. */
/* refcount for ln_nis */
lnet_ni_addref_locked(ni, 0);
cfs_list_add_tail(&ni->ni_list, &the_lnet.ln_nis);
+ if (ni->ni_cpts != NULL) {
+ cfs_list_add_tail(&ni->ni_cptlist,
+ &the_lnet.ln_nis_cpt);
+ lnet_ni_addref_locked(ni, 0);
+ }
lnet_net_unlock(LNET_LOCK_EX);
if (ni->ni_tx_queues != NULL)
cfs_percpt_free(ni->ni_tx_queues);
+ if (ni->ni_cpts != NULL) {
+ LIBCFS_FREE(ni->ni_cpts,
+ sizeof(ni->ni_cpts[0] * ni->ni_ncpts));
+ }
+
#ifndef __KERNEL__
# ifdef HAVE_LIBPTHREAD
pthread_mutex_destroy(&ni->ni_lock);
}
lnet_ni_t *
-lnet_ni_alloc(__u32 net, cfs_list_t *nilist)
+lnet_ni_alloc(__u32 net, struct cfs_expr_list **el, cfs_list_t *nilist)
{
struct lnet_tx_queue *tq;
struct lnet_ni *ni;
+ int rc;
int i;
if (!lnet_net_unique(net, nilist)) {
pthread_mutex_init(&ni->ni_lock, NULL);
# endif
#endif
+ CFS_INIT_LIST_HEAD(&ni->ni_cptlist);
ni->ni_refs = cfs_percpt_alloc(lnet_cpt_table(),
sizeof(*ni->ni_refs[0]));
if (ni->ni_refs == NULL)
cfs_percpt_for_each(tq, i, ni->ni_tx_queues)
CFS_INIT_LIST_HEAD(&tq->tq_delayed);
+ if (el == NULL || *el == NULL) {
+ ni->ni_cpts = NULL;
+ ni->ni_ncpts = LNET_CPT_NUMBER;
+ } else {
+ rc = cfs_expr_list_values(*el, LNET_CPT_NUMBER, &ni->ni_cpts);
+ if (rc <= 0) {
+ CERROR("Failed to set CPTs for NI %s: %d\n",
+ libcfs_net2str(net), rc);
+ goto failed;
+ }
+
+ LASSERT(rc <= LNET_CPT_NUMBER);
+ if (rc == LNET_CPT_NUMBER) {
+ LIBCFS_FREE(ni->ni_cpts, rc * sizeof(ni->ni_cpts[0]));
+ ni->ni_cpts = NULL;
+ }
+
+ ni->ni_ncpts = rc;
+ cfs_expr_list_free(*el); /* consume it */
+ *el = NULL;
+ }
+
/* LND will fill in the address part of the NID */
ni->ni_nid = LNET_MKNID(net, 0);
ni->ni_last_alive = cfs_time_current();
int
lnet_parse_networks(cfs_list_t *nilist, char *networks)
{
- int tokensize = strlen(networks) + 1;
- char *tokens;
- char *str;
- lnet_ni_t *ni;
- __u32 net;
- int nnets = 0;
+ struct cfs_expr_list *el = NULL;
+ int tokensize = strlen(networks) + 1;
+ char *tokens;
+ char *str;
+ char *tmp;
+ struct lnet_ni *ni;
+ __u32 net;
+ int nnets = 0;
if (strlen(networks) > LNET_SINGLE_TEXTBUF_NOB) {
/* _WAY_ conservative */
the_lnet.ln_network_tokens = tokens;
the_lnet.ln_network_tokens_nob = tokensize;
memcpy (tokens, networks, tokensize);
- str = tokens;
+ str = tmp = tokens;
/* Add in the loopback network */
- ni = lnet_ni_alloc(LNET_MKNET(LOLND, 0), nilist);
+ ni = lnet_ni_alloc(LNET_MKNET(LOLND, 0), NULL, nilist);
if (ni == NULL)
goto failed;
- while (str != NULL && *str != 0) {
- char *comma = strchr(str, ',');
- char *bracket = strchr(str, '(');
- int niface;
- char *iface;
+ while (str != NULL && *str != 0) {
+ char *comma = strchr(str, ',');
+ char *bracket = strchr(str, '(');
+ char *square = strchr(str, '[');
+ char *iface;
+ int niface;
+ int rc;
+
+ /* NB we don't check interface conflicts here; it's the LNDs
+ * responsibility (if it cares at all) */
+
+ if (square != NULL && (comma == NULL || square < comma)) {
+ /* i.e: o2ib0(ib0)[1,2], number between square
+ * brackets are CPTs this NI needs to be bond */
+ if (bracket != NULL && bracket > square) {
+ tmp = square;
+ goto failed_syntax;
+ }
+
+ tmp = strchr(square, ']');
+ if (tmp == NULL) {
+ tmp = square;
+ goto failed_syntax;
+ }
+
+ rc = cfs_expr_list_parse(square, tmp - square + 1,
+ 0, LNET_CPT_NUMBER - 1, &el);
+ if (rc != 0) {
+ tmp = square;
+ goto failed_syntax;
+ }
- /* NB we don't check interface conflicts here; it's the LNDs
- * responsibility (if it cares at all) */
+ while (square <= tmp)
+ *square++ = ' ';
+ }
if (bracket == NULL ||
(comma != NULL && comma < bracket)) {
net = libcfs_str2net(cfs_trimwhite(str));
if (net == LNET_NIDNET(LNET_NID_ANY)) {
- lnet_syntax("networks", networks,
- (int)(str - tokens), strlen(str));
LCONSOLE_ERROR_MSG(0x113, "Unrecognised network"
" type\n");
- goto failed;
+ tmp = str;
+ goto failed_syntax;
}
if (LNET_NETTYP(net) != LOLND && /* LO is implicit */
- lnet_ni_alloc(net, nilist) == NULL)
+ lnet_ni_alloc(net, &el, nilist) == NULL)
goto failed;
str = comma;
*bracket = 0;
net = libcfs_str2net(cfs_trimwhite(str));
if (net == LNET_NIDNET(LNET_NID_ANY)) {
- lnet_syntax("networks", networks,
- (int)(str - tokens), strlen(str));
- goto failed;
+ tmp = str;
+ goto failed_syntax;
}
- nnets++;
- ni = lnet_ni_alloc(net, nilist);
+ nnets++;
+ ni = lnet_ni_alloc(net, &el, nilist);
if (ni == NULL)
goto failed;
bracket = strchr(iface, ')');
if (bracket == NULL) {
- lnet_syntax("networks", networks,
- (int)(iface - tokens), strlen(iface));
- goto failed;
+ tmp = iface;
+ goto failed_syntax;
}
*bracket = 0;
iface = cfs_trimwhite(iface);
if (*iface == 0) {
- lnet_syntax("networks", networks,
- (int)(iface - tokens),
- strlen(iface));
- goto failed;
+ tmp = iface;
+ goto failed_syntax;
}
if (niface == LNET_MAX_INTERFACES) {
*comma = 0;
str = cfs_trimwhite(str);
if (*str != 0) {
- lnet_syntax("networks", networks,
- (int)(str - tokens), strlen(str));
- goto failed;
+ tmp = str;
+ goto failed_syntax;
}
str = comma + 1;
continue;
str = cfs_trimwhite(str);
if (*str != 0) {
- lnet_syntax("networks", networks,
- (int)(str - tokens), strlen(str));
- goto failed;
- }
+ tmp = str;
+ goto failed_syntax;
+ }
}
- LASSERT (!cfs_list_empty(nilist));
- return 0;
+ LASSERT(!cfs_list_empty(nilist));
+ return 0;
+ failed_syntax:
+ lnet_syntax("networks", networks, (int)(tmp - tokens), strlen(tmp));
failed:
- while (!cfs_list_empty(nilist)) {
- ni = cfs_list_entry(nilist->next, lnet_ni_t, ni_list);
+ while (!cfs_list_empty(nilist)) {
+ ni = cfs_list_entry(nilist->next, lnet_ni_t, ni_list);
cfs_list_del(&ni->ni_list);
lnet_ni_free(ni);
}
+
+ if (el != NULL)
+ cfs_expr_list_free(el);
+
LIBCFS_FREE(tokens, tokensize);
the_lnet.ln_network_tokens = NULL;