}
struct lnet_ping_buffer *
-lnet_ping_buffer_alloc(int nnis, gfp_t gfp)
+lnet_ping_buffer_alloc(int nbytes, gfp_t gfp)
{
struct lnet_ping_buffer *pbuf;
- LIBCFS_ALLOC_GFP(pbuf, LNET_PING_BUFFER_SIZE(nnis), gfp);
+ LIBCFS_ALLOC_GFP(pbuf, LNET_PING_BUFFER_SIZE(nbytes), gfp);
if (pbuf) {
- pbuf->pb_nnis = nnis;
+ pbuf->pb_nbytes = nbytes; /* sizeof of pb_info */
pbuf->pb_needs_post = false;
atomic_set(&pbuf->pb_refcnt, 1);
}
lnet_ping_buffer_free(struct lnet_ping_buffer *pbuf)
{
LASSERT(atomic_read(&pbuf->pb_refcnt) == 0);
- LIBCFS_FREE(pbuf, LNET_PING_BUFFER_SIZE(pbuf->pb_nnis));
+ LIBCFS_FREE(pbuf, LNET_PING_BUFFER_SIZE(pbuf->pb_nbytes));
}
static struct lnet_ping_buffer *
-lnet_ping_target_create(int nnis)
+lnet_ping_target_create(int nbytes)
{
struct lnet_ping_buffer *pbuf;
- pbuf = lnet_ping_buffer_alloc(nnis, GFP_NOFS);
+ pbuf = lnet_ping_buffer_alloc(nbytes, GFP_NOFS);
if (pbuf == NULL) {
- CERROR("Can't allocate ping source [%d]\n", nnis);
+ CERROR("Can't allocate ping source [%d]\n", nbytes);
return NULL;
}
- pbuf->pb_info.pi_nnis = nnis;
+ pbuf->pb_info.pi_nnis = 0;
pbuf->pb_info.pi_pid = the_lnet.ln_pid;
pbuf->pb_info.pi_magic = LNET_PROTO_PING_MAGIC;
pbuf->pb_info.pi_features =
}
static inline int
-lnet_get_net_ni_count_locked(struct lnet_net *net)
+lnet_get_net_ni_bytes_locked(struct lnet_net *net)
{
- struct lnet_ni *ni;
- int count = 0;
+ struct lnet_ni *ni;
+ int bytes = 0;
list_for_each_entry(ni, &net->net_ni_list, ni_netlist)
- count++;
+ if (nid_is_nid4(&ni->ni_nid))
+ bytes += sizeof(struct lnet_ni_status);
- return count;
+ return bytes;
}
static inline int
-lnet_get_net_ni_count_pre(struct lnet_net *net)
+lnet_get_net_ni_bytes_pre(struct lnet_net *net)
{
- struct lnet_ni *ni;
- int count = 0;
+ struct lnet_ni *ni;
+ int bytes = 0;
list_for_each_entry(ni, &net->net_ni_added, ni_netlist)
- count++;
+ if (nid_is_nid4(&ni->ni_nid))
+ bytes += sizeof(struct lnet_ni_status);
- return count;
+ return bytes;
}
static inline int
-lnet_get_ni_count(void)
+lnet_get_ni_bytes(void)
{
- struct lnet_ni *ni;
+ struct lnet_ni *ni;
struct lnet_net *net;
- int count = 0;
+ int bytes = 0;
lnet_net_lock(0);
list_for_each_entry(net, &the_lnet.ln_nets, net_list) {
list_for_each_entry(ni, &net->net_ni_list, ni_netlist)
- count++;
+ if (nid_is_nid4(&ni->ni_nid))
+ bytes += sizeof(struct lnet_ni_status);
}
lnet_net_unlock(0);
- return count;
+ return bytes;
}
void
lnet_swap_pinginfo(struct lnet_ping_buffer *pbuf)
{
- struct lnet_ni_status *stat;
+ struct lnet_ni_status *stat, *end;
int nnis;
int i;
__swab32s(&pbuf->pb_info.pi_pid);
__swab32s(&pbuf->pb_info.pi_nnis);
nnis = pbuf->pb_info.pi_nnis;
- if (nnis > pbuf->pb_nnis)
- nnis = pbuf->pb_nnis;
- for (i = 0; i < nnis; i++) {
- stat = &pbuf->pb_info.pi_ni[i];
+ stat = &pbuf->pb_info.pi_ni[0];
+ end = (void *)&pbuf->pb_info + pbuf->pb_nbytes;
+ for (i = 0; i < nnis && stat + 1 <= end; i++, stat++) {
__swab64s(&stat->ns_nid);
__swab32s(&stat->ns_status);
}
static int
lnet_ping_target_setup(struct lnet_ping_buffer **ppbuf,
struct lnet_handle_md *ping_mdh,
- int ni_count, bool set_eq)
+ int ni_bytes, bool set_eq)
{
struct lnet_processid id = {
.nid = LNET_ANY_NID,
the_lnet.ln_ping_target_handler =
lnet_ping_target_event_handler;
- *ppbuf = lnet_ping_target_create(ni_count);
+ *ppbuf = lnet_ping_target_create(ni_bytes);
if (*ppbuf == NULL) {
rc = -ENOMEM;
goto fail_free_eq;
/* initialize md content */
md.start = &(*ppbuf)->pb_info;
- md.length = LNET_PING_INFO_SIZE((*ppbuf)->pb_nnis);
+ md.length = (*ppbuf)->pb_nbytes;
md.threshold = LNET_MD_THRESH_INF;
md.max_size = 0;
md.options = LNET_MD_OP_GET | LNET_MD_TRUNCATE |
static void
lnet_ping_target_install_locked(struct lnet_ping_buffer *pbuf)
{
- struct lnet_ni *ni;
- struct lnet_net *net;
- struct lnet_ni_status *ns;
- int i;
- int rc;
+ struct lnet_ni *ni;
+ struct lnet_net *net;
+ struct lnet_ni_status *ns, *end;
+ int rc;
- i = 0;
+ pbuf->pb_info.pi_nnis = 0;
+ ns = &pbuf->pb_info.pi_ni[0];
+ end = (void *)&pbuf->pb_info + pbuf->pb_nbytes;
list_for_each_entry(net, &the_lnet.ln_nets, net_list) {
list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
- LASSERT(i < pbuf->pb_nnis);
-
- ns = &pbuf->pb_info.pi_ni[i];
-
if (!nid_is_nid4(&ni->ni_nid))
continue;
+ LASSERT(ns + 1 <= end);
ns->ns_nid = lnet_nid_to_nid4(&ni->ni_nid);
lnet_ni_lock(ni);
ni->ni_status = &ns->ns_status;
lnet_ni_unlock(ni);
- i++;
+ pbuf->pb_info.pi_nnis++;
+ ns++;
}
}
- /*
- * We (ab)use the ns_status of the loopback interface to
+
+ /* We (ab)use the ns_status of the loopback interface to
* transmit the sequence number. The first interface listed
* must be the loopback interface.
*/
struct lnet_handle_md old_mdh;
struct lnet_ping_buffer *pbuf;
struct lnet_ping_buffer *old_pbuf;
- int nnis;
+ int nbytes;
int rc;
again:
- nnis = the_lnet.ln_push_target_nnis;
- if (nnis <= 0) {
- CDEBUG(D_NET, "Invalid nnis %d\n", nnis);
+ nbytes = the_lnet.ln_push_target_nbytes;
+ if (nbytes <= 0) {
+ CDEBUG(D_NET, "Invalid nbytes %d\n", nbytes);
return -EINVAL;
}
* dropped when we need to resize again (see "old_pbuf" below) or when
* LNet is shutdown (see lnet_push_target_fini())
*/
- pbuf = lnet_ping_buffer_alloc(nnis, GFP_NOFS);
+ pbuf = lnet_ping_buffer_alloc(nbytes, GFP_NOFS);
if (!pbuf) {
- CDEBUG(D_NET, "Can't allocate pbuf for nnis %d\n", nnis);
+ CDEBUG(D_NET, "Can't allocate pbuf for nbytes %d\n", nbytes);
return -ENOMEM;
}
}
/* Received another push or reply that requires a larger buffer */
- if (nnis < the_lnet.ln_push_target_nnis)
+ if (nbytes < the_lnet.ln_push_target_nbytes)
goto again;
- CDEBUG(D_NET, "nnis %d success\n", nnis);
+ CDEBUG(D_NET, "nbytes %d success\n", nbytes);
return 0;
}
/* initialize md content */
md.start = &pbuf->pb_info;
- md.length = LNET_PING_INFO_SIZE(pbuf->pb_nnis);
+ md.length = pbuf->pb_nbytes;
md.threshold = 1;
md.max_size = 0;
md.options = LNET_MD_OP_PUT | LNET_MD_TRUNCATE;
LASSERT(rc == 0);
/* Start at the required minimum, we'll enlarge if required. */
- the_lnet.ln_push_target_nnis = LNET_INTERFACES_MIN;
+ the_lnet.ln_push_target_nbytes = LNET_PING_INFO_MIN_SIZE;
rc = lnet_push_target_resize();
-
if (rc) {
LNetClearLazyPortal(LNET_RESERVED_PORTAL);
the_lnet.ln_push_target_handler = NULL;
/* Drop ref set by lnet_ping_buffer_alloc() */
lnet_ping_buffer_decref(the_lnet.ln_push_target);
the_lnet.ln_push_target = NULL;
- the_lnet.ln_push_target_nnis = 0;
+ the_lnet.ln_push_target_nbytes = 0;
LNetClearLazyPortal(LNET_RESERVED_PORTAL);
lnet_assert_handler_unused(the_lnet.ln_push_target_handler);
int
LNetNIInit(lnet_pid_t requested_pid)
{
- int im_a_router = 0;
- int rc;
- int ni_count;
+ int im_a_router = 0;
+ int rc;
+ int ni_bytes;
struct lnet_ping_buffer *pbuf;
- struct lnet_handle_md ping_mdh;
+ struct lnet_handle_md ping_mdh;
LIST_HEAD(net_head);
- struct lnet_net *net;
+ struct lnet_net *net;
mutex_lock(&the_lnet.ln_api_mutex);
goto err_empty_list;
}
- ni_count = lnet_startup_lndnets(&net_head);
- if (ni_count < 0) {
- rc = ni_count;
+ rc = lnet_startup_lndnets(&net_head);
+ if (rc < 0)
goto err_empty_list;
- }
if (!the_lnet.ln_nis_from_mod_params) {
rc = lnet_parse_routes(lnet_get_routes(), &im_a_router);
the_lnet.ln_refcount = 1;
/* Now I may use my own API functions... */
- rc = lnet_ping_target_setup(&pbuf, &ping_mdh, ni_count, true);
+ ni_bytes = LNET_PING_INFO_HDR_SIZE;
+ list_for_each_entry(net, &the_lnet.ln_nets, net_list)
+ ni_bytes += lnet_get_net_ni_bytes_locked(net);
+
+ rc = lnet_ping_target_setup(&pbuf, &ping_mdh, ni_bytes, true);
if (rc != 0)
goto err_acceptor_stop;
struct lnet_ping_buffer *pbuf;
struct lnet_remotenet *rnet;
struct lnet_ni *ni;
- int net_ni_count;
+ int net_ni_bytes;
__u32 net_id;
int rc;
* which will be added.
*
* since ni hasn't been configured yet, use
- * lnet_get_net_ni_count_pre() which checks the net_ni_added list
+ * lnet_get_net_ni_bytes_pre() which checks the net_ni_added list
*/
- net_ni_count = lnet_get_net_ni_count_pre(net);
+ net_ni_bytes = lnet_get_net_ni_bytes_pre(net);
rc = lnet_ping_target_setup(&pbuf, &ping_mdh,
- net_ni_count + lnet_get_ni_count(),
+ LNET_PING_INFO_HDR_SIZE +
+ net_ni_bytes + lnet_get_ni_bytes(),
false);
if (rc < 0) {
lnet_net_free(net);
int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf)
{
- struct lnet_net *net;
+ struct lnet_net *net;
struct lnet_ni *ni;
__u32 net_id = LNET_NIDNET(conf->lic_nid);
struct lnet_ping_buffer *pbuf;
- struct lnet_handle_md ping_mdh;
- int rc;
- int net_count;
- __u32 addr;
+ struct lnet_handle_md ping_mdh;
+ int net_bytes, rc;
+ bool net_empty;
+ u32 addr;
/* don't allow userspace to shutdown the LOLND */
if (LNET_NETTYP(net_id) == LOLND)
addr = LNET_NIDADDR(conf->lic_nid);
if (addr == 0) {
/* remove the entire net */
- net_count = lnet_get_net_ni_count_locked(net);
+ net_bytes = lnet_get_net_ni_bytes_locked(net);
lnet_net_unlock(0);
/* create and link a new ping info, before removing the old one */
rc = lnet_ping_target_setup(&pbuf, &ping_mdh,
- lnet_get_ni_count() - net_count,
- false);
+ LNET_PING_INFO_HDR_SIZE +
+ lnet_get_ni_bytes() - net_bytes,
+ false);
if (rc != 0)
goto unlock_api_mutex;
goto unlock_net;
}
- net_count = lnet_get_net_ni_count_locked(net);
+ net_bytes = lnet_get_net_ni_bytes_locked(net);
+ net_empty = list_is_singular(&net->net_ni_list);
lnet_net_unlock(0);
/* create and link a new ping info, before removing the old one */
rc = lnet_ping_target_setup(&pbuf, &ping_mdh,
- lnet_get_ni_count() - 1, false);
+ (LNET_PING_INFO_HDR_SIZE +
+ lnet_get_ni_bytes() -
+ sizeof(pbuf->pb_info.pi_ni[0])),
+ false);
if (rc != 0)
goto unlock_api_mutex;
lnet_ping_target_update(pbuf, ping_mdh);
/* check if the net is empty and remove it if it is */
- if (net_count == 1)
+ if (net_empty)
lnet_shutdown_lndnet(net);
goto unlock_api_mutex;
}
int
-lnet_dyn_del_net(__u32 net_id)
+lnet_dyn_del_net(u32 net_id)
{
- struct lnet_net *net;
+ struct lnet_net *net;
struct lnet_ping_buffer *pbuf;
struct lnet_handle_md ping_mdh;
- int rc;
- int net_ni_count;
+ int net_ni_bytes, rc;
/* don't allow userspace to shutdown the LOLND */
if (LNET_NETTYP(net_id) == LOLND)
goto out;
}
- net_ni_count = lnet_get_net_ni_count_locked(net);
+ net_ni_bytes = lnet_get_net_ni_bytes_locked(net);
lnet_net_unlock(0);
/* create and link a new ping info, before removing the old one */
rc = lnet_ping_target_setup(&pbuf, &ping_mdh,
- lnet_get_ni_count() - net_ni_count, false);
+ LNET_PING_INFO_HDR_SIZE +
+ lnet_get_ni_bytes() - net_ni_bytes,
+ false);
if (rc != 0)
goto out;
complete(&pd->completion);
}
+/* lnet_ping() only works with nid4 nids, so we can calculate
+ * size from number of nids
+ */
+#define LNET_PING_INFO_SIZE(NNIDS) \
+ offsetof(struct lnet_ping_info, pi_ni[NNIDS])
+
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_ping_buffer *pbuf;
struct lnet_process_id tmpid;
struct lnet_processid id;
+ int id_bytes;
int i;
int nob;
int rc;
if (id4.pid == LNET_PID_ANY)
id4.pid = LNET_PID_LUSTRE;
- pbuf = lnet_ping_buffer_alloc(n_ids, GFP_NOFS);
+ id_bytes = LNET_PING_INFO_SIZE(n_ids);
+ pbuf = lnet_ping_buffer_alloc(id_bytes, GFP_NOFS);
if (!pbuf)
return -ENOMEM;
/* initialize md content */
md.start = &pbuf->pb_info;
- md.length = LNET_PING_INFO_SIZE(n_ids);
+ md.length = id_bytes;
md.threshold = 2; /* GET/REPLY */
md.max_size = 0;
md.options = LNET_MD_TRUNCATE;
}
nob = pd.rc;
- LASSERT(nob >= 0 && nob <= LNET_PING_INFO_SIZE(n_ids));
+ LASSERT(nob >= 0 && nob <= id_bytes);
rc = -EPROTO; /* if I can't parse... */
goto fail_ping_buffer_decref;
}
- if (nob < LNET_PING_INFO_SIZE(0)) {
- CERROR("%s: Short reply %d(%d min)\n",
- libcfs_idstr(&id),
- nob, (int)LNET_PING_INFO_SIZE(0));
+ /* Test if smaller than lnet_pinginfo with no pi_ni status info */
+ if (nob < LNET_PING_INFO_HDR_SIZE) {
+ CERROR("%s: Short reply %d(%lu min)\n",
+ libcfs_idstr(&id), nob, LNET_PING_INFO_HDR_SIZE);
goto fail_ping_buffer_decref;
}
- if (pbuf->pb_info.pi_nnis < n_ids)
+ if (pbuf->pb_info.pi_nnis < n_ids) {
n_ids = pbuf->pb_info.pi_nnis;
+ id_bytes = lnet_ping_info_size(&pbuf->pb_info);
+ }
- if (nob < LNET_PING_INFO_SIZE(n_ids)) {
+ if (nob < id_bytes) {
CERROR("%s: Short reply %d(%d expected)\n",
- libcfs_idstr(&id),
- nob, (int)LNET_PING_INFO_SIZE(n_ids));
+ libcfs_idstr(&id), nob, id_bytes);
goto fail_ping_buffer_decref;
}
lnet_ping_buffer_decref(pbuf);
return rc;
}
+#undef LNET_PING_INFO_SIZE
static int
lnet_discover(struct lnet_process_id id4, __u32 force,
{
struct lnet_ping_buffer *pbuf;
struct lnet_peer *lp;
+ int infobytes;
pbuf = LNET_PING_INFO_TO_BUFFER(ev->md_start + ev->offset);
goto out;
}
- /*
- * Make sure we'll allocate the correct size ping buffer when
+ /* Make sure we'll allocate the correct size ping buffer when
* pinging the peer.
*/
- if (lp->lp_data_nnis < pbuf->pb_info.pi_nnis)
- lp->lp_data_nnis = pbuf->pb_info.pi_nnis;
+ infobytes = lnet_ping_info_size(&pbuf->pb_info);
+ if (lp->lp_data_bytes < infobytes)
+ lp->lp_data_bytes = infobytes;
/*
* A non-Multi-Rail peer is not supposed to be capable of
lnet_peer_clr_non_mr_pref_nids(lp);
}
- /*
- * Check for truncation of the Put message. Clear the
+ /* Check for truncation of the Put message. Clear the
* NIDS_UPTODATE flag and set FORCE_PING to trigger a ping,
* and tell discovery to allocate a bigger buffer.
*/
if (ev->mlength < ev->rlength) {
- if (the_lnet.ln_push_target_nnis < pbuf->pb_info.pi_nnis)
- the_lnet.ln_push_target_nnis = pbuf->pb_info.pi_nnis;
+ if (the_lnet.ln_push_target_nbytes < infobytes)
+ the_lnet.ln_push_target_nbytes = infobytes;
lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE;
lp->lp_state |= LNET_PEER_FORCE_PING;
- CDEBUG(D_NET, "Truncated Push from %s (%d nids)\n",
- libcfs_nidstr(&lp->lp_primary_nid),
- pbuf->pb_info.pi_nnis);
+ CDEBUG(D_NET, "Truncated Push from %s (%d bytes)\n",
+ libcfs_nidstr(&lp->lp_primary_nid), infobytes);
goto out;
}
lp->lp_peer_seqno = LNET_PING_BUFFER_SEQNO(pbuf);
lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE;
- /*
- * If there is data present that hasn't been processed yet,
+ /* If there is data present that hasn't been processed yet,
* we'll replace it if the Put contained newer data and it
* fits. We're racing with a Ping or earlier Push in this
* case.
if (lp->lp_state & LNET_PEER_DATA_PRESENT) {
if (LNET_PING_BUFFER_SEQNO(pbuf) >
LNET_PING_BUFFER_SEQNO(lp->lp_data) &&
- pbuf->pb_info.pi_nnis <= lp->lp_data->pb_nnis) {
+ infobytes <= lp->lp_data->pb_nbytes) {
memcpy(&lp->lp_data->pb_info, &pbuf->pb_info,
- LNET_PING_INFO_SIZE(pbuf->pb_info.pi_nnis));
+ infobytes);
CDEBUG(D_NET, "Ping/Push race from %s: %u vs %u\n",
libcfs_nidstr(&lp->lp_primary_nid),
LNET_PING_BUFFER_SEQNO(pbuf),
* the Push and set FORCE_PING to force the discovery
* thread to fix the problem by pinging the peer.
*/
- lp->lp_data = lnet_ping_buffer_alloc(lp->lp_data_nnis, GFP_ATOMIC);
+ lp->lp_data = lnet_ping_buffer_alloc(lp->lp_data_bytes, GFP_ATOMIC);
if (!lp->lp_data) {
lp->lp_state |= LNET_PEER_FORCE_PING;
CDEBUG(D_NET, "Cannot allocate Push buffer for %s %u\n",
}
/* Success */
- memcpy(&lp->lp_data->pb_info, &pbuf->pb_info,
- LNET_PING_INFO_SIZE(pbuf->pb_info.pi_nnis));
+ memcpy(&lp->lp_data->pb_info, &pbuf->pb_info, infobytes);
lp->lp_state |= LNET_PEER_DATA_PRESENT;
CDEBUG(D_NET, "Received Push %s %u\n",
libcfs_nidstr(&lp->lp_primary_nid),
lnet_discovery_event_reply(struct lnet_peer *lp, struct lnet_event *ev)
{
struct lnet_ping_buffer *pbuf;
+ int infobytes;
int rc;
spin_lock(&lp->lp_lock);
}
}
+ infobytes = lnet_ping_info_size(&pbuf->pb_info);
/*
* Make sure we'll allocate the correct size ping buffer when
* pinging the peer.
*/
- if (lp->lp_data_nnis < pbuf->pb_info.pi_nnis)
- lp->lp_data_nnis = pbuf->pb_info.pi_nnis;
+ if (lp->lp_data_bytes < infobytes)
+ lp->lp_data_bytes = infobytes;
- /*
- * Check for truncation of the Reply. Clear PING_SENT and set
+ /* Check for truncation of the Reply. Clear PING_SENT and set
* PING_FAILED to trigger a retry.
*/
- if (pbuf->pb_nnis < pbuf->pb_info.pi_nnis) {
- if (the_lnet.ln_push_target_nnis < pbuf->pb_info.pi_nnis)
- the_lnet.ln_push_target_nnis = pbuf->pb_info.pi_nnis;
+ if (pbuf->pb_nbytes < infobytes) {
+ if (the_lnet.ln_push_target_nbytes < infobytes)
+ the_lnet.ln_push_target_nbytes = infobytes;
lp->lp_state |= LNET_PEER_PING_FAILED;
lp->lp_ping_error = 0;
- CDEBUG(D_NET, "Truncated Reply from %s (%d nids)\n",
- libcfs_nidstr(&lp->lp_primary_nid),
- pbuf->pb_info.pi_nnis);
+ CDEBUG(D_NET, "Truncated Reply from %s (%d bytes)\n",
+ libcfs_nidstr(&lp->lp_primary_nid), infobytes);
goto out;
}
static int lnet_peer_send_ping(struct lnet_peer *lp)
__must_hold(&lp->lp_lock)
{
- int nnis;
+ int bytes;
int rc;
int cpt;
lnet_peer_addref_locked(lp);
lnet_net_unlock(cpt);
- nnis = max(lp->lp_data_nnis, LNET_INTERFACES_MIN);
+ bytes = max_t(int, lp->lp_data_bytes, LNET_PING_INFO_MIN_SIZE);
- rc = lnet_send_ping(&lp->lp_primary_nid, &lp->lp_ping_mdh, nnis, lp,
+ rc = lnet_send_ping(&lp->lp_primary_nid, &lp->lp_ping_mdh, bytes, lp,
the_lnet.ln_dc_handler, false);
-
- /*
- * if LNetMDBind in lnet_send_ping fails we need to decrement the
+ /* if LNetMDBind in lnet_send_ping fails we need to decrement the
* refcount on the peer, otherwise LNetMDUnlink will be called
* which will eventually do that.
*/
/* Push source MD */
md.start = &pbuf->pb_info;
- md.length = LNET_PING_INFO_SIZE(pbuf->pb_nnis);
+ md.length = pbuf->pb_nbytes;
md.threshold = 2; /* Put/Ack */
md.max_size = 0;
md.options = LNET_MD_TRACK_RESPONSE;