All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jason Gunthorpe <jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
To: Sean Hefty <sean.hefty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>,
	Linux RDMA list
	<linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: [PATCH libibrdmacm] Return errors from the library consistently
Date: Tue, 20 Oct 2009 12:41:57 -0600	[thread overview]
Message-ID: <20091020184157.GG14520@obsidianresearch.com> (raw)

Remove the return of -errno and always return codes via errno.
As documented in librdmacm, these libraries are already documented
to return -1 to indicate the code is in errno.

Update rping to show a correct error reporting methodology.

Also fix an errant return of 0 if the read/write syscalls return 0.

Signed-off-by: Jason Gunthorpe <jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
---
 examples/rping.c |   22 ++++++-------
 man/rdma_cm.7    |   16 ++++----
 src/cma.c        |   94 ++++++++++++++++++++++++++++-------------------------
 3 files changed, 68 insertions(+), 64 deletions(-)

I think the changes to rping show why the old approach is so
dangerous, only 2 error reports in rping were actually able to show
errno from the kernel.

I haven't been able to do more than compile test this one though..

diff --git a/examples/rping.c b/examples/rping.c
index e45cfb6..91952e7 100644
--- a/examples/rping.c
+++ b/examples/rping.c
@@ -174,7 +174,7 @@ static int rping_cma_event_handler(struct rdma_cm_id *cma_id,
 		ret = rdma_resolve_route(cma_id, 2000);
 		if (ret) {
 			cb->state = ERROR;
-			fprintf(stderr, "rdma_resolve_route error %d\n", ret);
+			perror("rdma_resolve_route");
 			sem_post(&cb->sem);
 		}
 		break;
@@ -352,7 +352,7 @@ static int rping_accept(struct rping_cb *cb)
 
 	ret = rdma_accept(cb->child_cm_id, &conn_param);
 	if (ret) {
-		fprintf(stderr, "rdma_accept error: %d\n", ret);
+		perror("rdma_accept");
 		return ret;
 	}
 
@@ -546,7 +546,7 @@ static int rping_setup_qp(struct rping_cb *cb, struct rdma_cm_id *cm_id)
 
 	ret = rping_create_qp(cb);
 	if (ret) {
-		fprintf(stderr, "rping_create_qp failed: %d\n", ret);
+		perror("rdma_create_qp");
 		goto err3;
 	}
 	DEBUG_LOG("created qp %p\n", cb->qp);
@@ -570,7 +570,7 @@ static void *cm_thread(void *arg)
 	while (1) {
 		ret = rdma_get_cm_event(cb->cm_channel, &event);
 		if (ret) {
-			fprintf(stderr, "rdma_get_cm_event err %d\n", ret);
+			perror("rdma_get_cm_event");
 			exit(ret);
 		}
 		ret = rping_cma_event_handler(event->id, event);
@@ -736,7 +736,7 @@ static int rping_bind_server(struct rping_cb *cb)
 
 	ret = rdma_bind_addr(cb->cm_id, (struct sockaddr *) &cb->sin);
 	if (ret) {
-		fprintf(stderr, "rdma_bind_addr error %d\n", ret);
+		perror("rdma_bind_addr");
 		return ret;
 	}
 	DEBUG_LOG("rdma_bind_addr successful\n");
@@ -744,7 +744,7 @@ static int rping_bind_server(struct rping_cb *cb)
 	DEBUG_LOG("rdma_listen\n");
 	ret = rdma_listen(cb->cm_id, 3);
 	if (ret) {
-		fprintf(stderr, "rdma_listen failed: %d\n", ret);
+		perror("rdma_listen");
 		return ret;
 	}
 
@@ -978,7 +978,7 @@ static int rping_connect_client(struct rping_cb *cb)
 
 	ret = rdma_connect(cb->cm_id, &conn_param);
 	if (ret) {
-		fprintf(stderr, "rdma_connect error %d\n", ret);
+		perror("rdma_connect");
 		return ret;
 	}
 
@@ -1003,7 +1003,7 @@ static int rping_bind_client(struct rping_cb *cb)
 
 	ret = rdma_resolve_addr(cb->cm_id, NULL, (struct sockaddr *) &cb->sin, 2000);
 	if (ret) {
-		fprintf(stderr, "rdma_resolve_addr error %d\n", ret);
+		perror("rdma_resolve_addr");
 		return ret;
 	}
 
@@ -1191,15 +1191,13 @@ int main(int argc, char *argv[])
 
 	cb->cm_channel = rdma_create_event_channel();
 	if (!cb->cm_channel) {
-		ret = errno;
-		fprintf(stderr, "rdma_create_event_channel error %d\n", ret);
+		perror("rdma_create_event_channel");
 		goto out;
 	}
 
 	ret = rdma_create_id(cb->cm_channel, &cb->cm_id, cb, RDMA_PS_TCP);
 	if (ret) {
-		ret = errno;
-		fprintf(stderr, "rdma_create_id error %d\n", ret);
+		perror("rdma_create_id");
 		goto out2;
 	}
 	DEBUG_LOG("created cm_id %p\n", cb->cm_id);
diff --git a/man/rdma_cm.7 b/man/rdma_cm.7
index 23571b2..fd04959 100644
--- a/man/rdma_cm.7
+++ b/man/rdma_cm.7
@@ -108,18 +108,18 @@ release the event channel
 success
 .IP "= -1"
 error - see errno for more details
-.IP "< -1"
-error - see include/asm-generic/errno*.h for more details
 .P
-Librdmacm functions return 0 to indicate success, and a negative return value
+Librdmacm functions return 0 to indicate success, and a -1 return value
 to indicate failure.  If a function operates asynchronously, a return value of 0
 means that the operation was successfully started.  The operation could still
 complete in error; users should check the status of the related event.  If the
-return value is -1, then errno can be examined for additional information
-regarding the reason for the failure.  If the return value is < -1, then
-additional error reasons can be obtained by comparing the returned value with
-the values listed in include/asm-generic/errno-base.h and
-include/asm-generic/errno.h.
+return value is -1, then errno will contain additional information
+regarding the reason for the failure.
+.P
+Prior versions of the library would return -errno and not set errno for some cases
+related to ENOMEM, ENODEV, ENODATA, EINVAL, and EADDRNOTAVAIL codes. Applications
+that want to check these codes and have compatability with prior library versions
+must manually set errno to the negative of the return code if it is < -1.
 .SH "SEE ALSO"
 rdma_create_event_channel(3), rdma_get_cm_event(3), rdma_create_id(3),
 rdma_resolve_addr(3), rdma_bind_addr(3), rdma_create_qp(3),
diff --git a/src/cma.c b/src/cma.c
index 70dbe1c..9fe2599 100644
--- a/src/cma.c
+++ b/src/cma.c
@@ -76,6 +76,12 @@ static inline uint64_t htonll(uint64_t x) { return x; }
 static inline uint64_t ntohll(uint64_t x) { return x; }
 #endif
 
+static inline int ERR(int err)
+{
+	errno = err;
+	return -1;
+}
+
 #define CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, type, size) \
 do {                                        \
 	struct ucma_abi_cmd_hdr *hdr;         \
@@ -83,7 +89,7 @@ do {                                        \
 	size = sizeof(*hdr) + sizeof(*cmd); \
 	msg = alloca(size);                 \
 	if (!msg)                           \
-		return -ENOMEM;             \
+		return ERR(ENOMEM);         \
 	hdr = msg;                          \
 	cmd = msg + sizeof(*hdr);           \
 	hdr->cmd = type;                    \
@@ -92,18 +98,18 @@ do {                                        \
 	memset(cmd, 0, sizeof(*cmd));       \
 	resp = alloca(sizeof(*resp));       \
 	if (!resp)                          \
-		return -ENOMEM;             \
+		return ERR(ENOMEM);         \
 	cmd->response = (uintptr_t)resp;\
 } while (0)
 
 #define CMA_CREATE_MSG_CMD(msg, cmd, type, size) \
 do {                                        \
-	struct ucma_abi_cmd_hdr *hdr;         \
+	struct ucma_abi_cmd_hdr *hdr;       \
                                             \
 	size = sizeof(*hdr) + sizeof(*cmd); \
 	msg = alloca(size);                 \
 	if (!msg)                           \
-		return -ENOMEM;             \
+		return ERR(ENOMEM);         \
 	hdr = msg;                          \
 	cmd = msg + sizeof(*hdr);           \
 	hdr->cmd = type;                    \
@@ -218,13 +224,13 @@ static int ucma_init(void)
 	dev_list = ibv_get_device_list(&cma_dev_cnt);
 	if (!dev_list) {
 		printf("CMA: unable to get RDMA device list\n");
-		ret = -ENODEV;
+		ret = ERR(ENODEV);
 		goto err;
 	}
 
 	cma_dev_array = malloc(sizeof *cma_dev * cma_dev_cnt);
 	if (!cma_dev_array) {
-		ret = -ENOMEM;
+		ret = ERR(ENOMEM);
 		goto err;
 	}
 
@@ -235,7 +241,7 @@ static int ucma_init(void)
 		cma_dev->verbs = ibv_open_device(dev_list[i]);
 		if (!cma_dev->verbs) {
 			printf("CMA: unable to open RDMA device\n");
-			ret = -ENODEV;
+			ret = ERR(ENODEV);
 			goto err;
 		}
 
@@ -334,7 +340,7 @@ static int ucma_get_device(struct cma_id_private *id_priv, uint64_t guid)
 		}
 	}
 
-	return -ENODEV;
+	return ERR(ENODEV);
 }
 
 static void ucma_free_id(struct cma_id_private *id_priv)
@@ -386,7 +392,7 @@ int rdma_create_id(struct rdma_event_channel *channel,
 
 	id_priv = ucma_alloc_id(channel, context, ps);
 	if (!id_priv)
-		return -ENOMEM;
+		return ERR(ENOMEM);
 
 	CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_CREATE_ID, size);
 	cmd->uid = (uintptr_t) id_priv;
@@ -418,7 +424,7 @@ static int ucma_destroy_kern_id(int fd, uint32_t handle)
 
 	ret = write(fd, msg, size);
 	if (ret != size)
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 
 	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
 
@@ -473,7 +479,7 @@ static int ucma_query_route(struct rdma_cm_id *id)
 
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size)
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 
 	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
 
@@ -481,7 +487,7 @@ static int ucma_query_route(struct rdma_cm_id *id)
 		id->route.path_rec = malloc(sizeof *id->route.path_rec *
 					    resp->num_paths);
 		if (!id->route.path_rec)
-			return -ENOMEM;
+			return ERR(ENOMEM);
 
 		id->route.num_paths = resp->num_paths;
 		for (i = 0; i < resp->num_paths; i++)
@@ -518,7 +524,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
 	
 	addrlen = ucma_addrlen(addr);
 	if (!addrlen)
-		return -EINVAL;
+		return ERR(EINVAL);
 
 	CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_BIND_ADDR, size);
 	id_priv = container_of(id, struct cma_id_private, id);
@@ -527,7 +533,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
 
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size)
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 
 	return ucma_query_route(id);
 }
@@ -542,7 +548,7 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
 	
 	daddrlen = ucma_addrlen(dst_addr);
 	if (!daddrlen)
-		return -EINVAL;
+		return ERR(EINVAL);
 
 	CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_RESOLVE_ADDR, size);
 	id_priv = container_of(id, struct cma_id_private, id);
@@ -554,7 +560,7 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
 
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size)
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 
 	memcpy(&id->route.addr.dst_addr, dst_addr, daddrlen);
 	return 0;
@@ -574,7 +580,7 @@ int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
 
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size)
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 
 	return 0;
 }
@@ -600,7 +606,7 @@ static int rdma_init_qp_attr(struct rdma_cm_id *id, struct ibv_qp_attr *qp_attr,
 
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size)
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 
 	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
 
@@ -616,7 +622,7 @@ static int ucma_modify_qp_rtr(struct rdma_cm_id *id,
 	int qp_attr_mask, ret;
 
 	if (!id->qp)
-		return -EINVAL;
+		return ERR(EINVAL);
 
 	/* Need to update QP attributes from default values. */
 	qp_attr.qp_state = IBV_QPS_INIT;
@@ -686,7 +692,7 @@ static int ucma_find_pkey(struct cma_device *cma_dev, uint8_t port_num,
 			return 0;
 		}
 	}
-	return -EINVAL;
+	return ERR(EINVAL);
 }
 
 static int ucma_init_conn_qp3(struct cma_id_private *id_priv, struct ibv_qp *qp)
@@ -790,11 +796,11 @@ int rdma_create_qp(struct rdma_cm_id *id, struct ibv_pd *pd,
 
 	id_priv = container_of(id, struct cma_id_private, id);
 	if (id->verbs != pd->context)
-		return -EINVAL;
+		return ERR(EINVAL);
 
 	qp = ibv_create_qp(pd, qp_init_attr);
 	if (!qp)
-		return -ENOMEM;
+		return ERR(ENOMEM);
 
 	if (ucma_is_ud_ps(id->ps))
 		ret = ucma_init_ud_qp(id_priv, qp);
@@ -825,7 +831,7 @@ static int ucma_valid_param(struct cma_id_private *id_priv,
 	     id_priv->cma_dev->max_responder_resources) ||
 	    (conn_param->initiator_depth >
 	     id_priv->cma_dev->max_initiator_depth))
-		return -EINVAL;
+		return ERR(EINVAL);
 
 	return 0;
 }
@@ -875,7 +881,7 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
 
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size)
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 
 	return 0;
 }
@@ -894,7 +900,7 @@ int rdma_listen(struct rdma_cm_id *id, int backlog)
 
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size)
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 
 	return ucma_query_route(id);
 }
@@ -932,7 +938,7 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size) {
 		ucma_modify_qp_err(id);
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 	}
 
 	return 0;
@@ -958,7 +964,7 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data,
 
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size)
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 
 	return 0;
 }
@@ -977,7 +983,7 @@ int rdma_notify(struct rdma_cm_id *id, enum ibv_event_type event)
 	cmd->event = event;
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size)
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 
 	return 0;
 }
@@ -997,7 +1003,7 @@ int rdma_disconnect(struct rdma_cm_id *id)
 		ret = ucma_modify_qp_sqd(id);
 		break;
 	default:
-		ret = -EINVAL;
+		ret = ERR(EINVAL);
 	}
 	if (ret)
 		return ret;
@@ -1008,7 +1014,7 @@ int rdma_disconnect(struct rdma_cm_id *id)
 
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size)
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 
 	return 0;
 }
@@ -1026,11 +1032,11 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
 	id_priv = container_of(id, struct cma_id_private, id);
 	addrlen = ucma_addrlen(addr);
 	if (!addrlen)
-		return -EINVAL;
+		return ERR(EINVAL);
 
 	mc = malloc(sizeof *mc);
 	if (!mc)
-		return -ENOMEM;
+		return ERR(ENOMEM);
 
 	memset(mc, 0, sizeof *mc);
 	mc->context = context;
@@ -1053,7 +1059,7 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
 
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size) {
-		ret = (ret > 0) ? -ENODATA : ret;
+		ret = (ret >= 0) ? ERR(ENODATA) : -1;
 		goto err2;
 	}
 
@@ -1083,7 +1089,7 @@ int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
 	
 	addrlen = ucma_addrlen(addr);
 	if (!addrlen)
-		return -EINVAL;
+		return ERR(EINVAL);
 
 	id_priv = container_of(id, struct cma_id_private, id);
 	pthread_mutex_lock(&id_priv->mut);
@@ -1096,7 +1102,7 @@ int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
 		*pos = mc->next;
 	pthread_mutex_unlock(&id_priv->mut);
 	if (!mc)
-		return -EADDRNOTAVAIL;
+		return ERR(EADDRNOTAVAIL);
 
 	if (id->qp)
 		ibv_detach_mcast(id->qp, &mc->mgid, mc->mlid);
@@ -1106,7 +1112,7 @@ int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
 
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size) {
-		ret = (ret > 0) ? -ENODATA : ret;
+		ret = (ret >= 0) ? ERR(ENODATA) : -1;
 		goto free;
 	}
 
@@ -1146,7 +1152,7 @@ int rdma_ack_cm_event(struct rdma_cm_event *event)
 	struct cma_event *evt;
 
 	if (!event)
-		return -EINVAL;
+		return ERR(EINVAL);
 
 	evt = container_of(event, struct cma_event, event);
 
@@ -1168,7 +1174,7 @@ static int ucma_process_conn_req(struct cma_event *evt,
 				evt->id_priv->id.context, evt->id_priv->id.ps);
 	if (!id_priv) {
 		ucma_destroy_kern_id(evt->id_priv->id.channel->fd, handle);
-		ret = -ENOMEM;
+		ret = ERR(ENOMEM);
 		goto err;
 	}
 
@@ -1207,7 +1213,7 @@ static int ucma_process_conn_resp(struct cma_id_private *id_priv)
 
 	ret = write(id_priv->id.channel->fd, msg, size);
 	if (ret != size) {
-		ret = (ret > 0) ? -ENODATA : ret;
+		ret = (ret >= 0) ? ERR(ENODATA) : -1;
 		goto err;
 	}
 
@@ -1292,11 +1298,11 @@ int rdma_get_cm_event(struct rdma_event_channel *channel,
 		return ret;
 
 	if (!event)
-		return -EINVAL;
+		return ERR(EINVAL);
 
 	evt = malloc(sizeof *evt);
 	if (!evt)
-		return -ENOMEM;
+		return ERR(ENOMEM);
 
 retry:
 	memset(evt, 0, sizeof *evt);
@@ -1304,7 +1310,7 @@ retry:
 	ret = write(channel->fd, msg, size);
 	if (ret != size) {
 		free(evt);
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 	}
 	
 	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
@@ -1463,7 +1469,7 @@ int rdma_set_option(struct rdma_cm_id *id, int level, int optname,
 
 	ret = write(id->channel->fd, msg, size);
 	if (ret != size)
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 
 	return 0;
 }
@@ -1483,7 +1489,7 @@ int rdma_migrate_id(struct rdma_cm_id *id, struct rdma_event_channel *channel)
 
 	ret = write(channel->fd, msg, size);
 	if (ret != size)
-		return (ret > 0) ? -ENODATA : ret;
+		return (ret >= 0) ? ERR(ENODATA) : -1;
 
 	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp);
 
-- 
1.6.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

             reply	other threads:[~2009-10-20 18:41 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-10-20 18:41 Jason Gunthorpe [this message]
     [not found] ` <20091020184157.GG14520-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
2009-10-21 18:25   ` [PATCH libibrdmacm] Return errors from the library consistently Sean Hefty

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20091020184157.GG14520@obsidianresearch.com \
    --to=jgunthorpe-epgobjl8dl3ta4ec/59zmfatqe2ktcn/@public.gmane.org \
    --cc=linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=sean.hefty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.