All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH] dma-buf: add a generic reclaim-priority hint
@ 2026-08-20 19:08 Ferran Duarri
  2026-08-20 19:14 ` sashiko-bot
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Ferran Duarri @ 2026-08-20 19:08 UTC (permalink / raw)
  To: Sumit Semwal, Christian König
  Cc: linux-media, dri-devel, linaro-mm-sig, linux-kernel,
	Ferran Duarri

dma-buf has no generic mechanism for a buffer's exporter, importer, or
a cooperating userspace agent to signal how eagerly a given buffer's
backing memory should be given up relative to other buffers when the
system is under memory pressure. Pages pinned via pin_user_pages()/
FOLL_LONGTERM sit outside the normal reclaim path by design, so any
subsystem that wants a "prefer to keep A over B under pressure" policy
for its pinned dma-buf allocations currently has to invent its own
private, driver-specific side channel to express it.

This is a real, recurring pattern: GPU drivers juggling foreground and
background clients want it, and it shows up concretely in large-model
AI/ML inference stacks that tier working sets across VRAM/system-RAM/
NVMe using their own dma-buf exporters -- e.g. an out-of-tree memory
tiering driver we've been using has its own gaming_mode sysfs flag and
a per-buffer "heat" score, moving its own DMA-BUF-backed allocations to
its own private LRU tail under a private IOCTL, purely because there is
nowhere generic to express "this buffer can go first."

Add one small, opt-in hint instead of another private channel:

  - struct dma_buf gains a `priority` field (atomic_t, plain hint, no
    new locking), defaulting to DMA_BUF_PRIORITY_DEFAULT (128) and
    ranging DMA_BUF_PRIORITY_MIN (0) to DMA_BUF_PRIORITY_MAX (255).
    Lower values should be reclaimed EARLIER under memory pressure.

  - dma_buf_set_priority()/dma_buf_get_priority(), exported under the
    DMA_BUF symbol namespace, so any dma-buf exporter (in-tree or an
    out-of-tree module) can set/read it directly.

  - DMA_BUF_IOCTL_SET_PRIORITY / DMA_BUF_IOCTL_GET_PRIORITY so
    userspace holding an fd can do the same, without needing a private
    driver ioctl.

  - The current value is reported via fdinfo (`priority:`) for
    debugging/accounting, next to the existing size/name/exp_name
    fields.

This is deliberately a hint only: dma-buf core stores and reports the
value, it implements no eviction policy of its own, and it changes no
behavior for any existing exporter or importer that doesn't opt in.
No existing dma_buf_ops callback is touched. Compile-tested: drivers/
dma-buf/ (incl. the selftest module) and drivers/gpu/drm/drm_prime.o
both build clean against this change.

Signed-off-by: Ferran Duarri <ferran.duarri@me.com>
---
 drivers/dma-buf/dma-buf.c    | 51 ++++++++++++++++++++++++++++++++++++
 include/linux/dma-buf.h      | 26 ++++++++++++++++++
 include/uapi/linux/dma-buf.h | 33 +++++++++++++++++++++++
 3 files changed, 110 insertions(+)

diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index d504c636dc29..1b1d3ee77f47 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -432,6 +432,39 @@ static long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf)
 	return 0;
 }
 
+/**
+ * dma_buf_set_priority - Set the reclaim-priority hint on a dma_buf.
+ * @dmabuf:   [in] buffer to update.
+ * @priority: [in] new priority, clamped to
+ *                 [DMA_BUF_PRIORITY_MIN, DMA_BUF_PRIORITY_MAX].
+ *
+ * Lower values should be reclaimed EARLIER under memory pressure. This is
+ * a hint only , dma-buf core stores and reports it, it implements no
+ * eviction policy itself. Safe to call at any time, from any context that
+ * can call dma_buf_get()/hold a reference (no locking required beyond
+ * that reference).
+ */
+void dma_buf_set_priority(struct dma_buf *dmabuf, unsigned int priority)
+{
+	if (priority > DMA_BUF_PRIORITY_MAX)
+		priority = DMA_BUF_PRIORITY_MAX;
+	atomic_set(&dmabuf->priority, priority);
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_set_priority, "DMA_BUF");
+
+/**
+ * dma_buf_get_priority - Read back the current reclaim-priority hint.
+ * @dmabuf: [in] buffer to query.
+ *
+ * Returns the value most recently set via dma_buf_set_priority() (or
+ * DMA_BUF_PRIORITY_DEFAULT if never set).
+ */
+unsigned int dma_buf_get_priority(struct dma_buf *dmabuf)
+{
+	return atomic_read(&dmabuf->priority);
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_get_priority, "DMA_BUF");
+
 #if IS_ENABLED(CONFIG_SYNC_FILE)
 static long dma_buf_export_sync_file(struct dma_buf *dmabuf,
 				     void __user *user_data)
@@ -542,6 +575,7 @@ static long dma_buf_ioctl(struct file *file,
 {
 	struct dma_buf *dmabuf;
 	struct dma_buf_sync sync;
+	struct dma_buf_priority prio;
 	enum dma_data_direction direction;
 	int ret;
 
@@ -580,6 +614,21 @@ static long dma_buf_ioctl(struct file *file,
 	case DMA_BUF_SET_NAME_B:
 		return dma_buf_set_name(dmabuf, (const char __user *)arg);
 
+	case DMA_BUF_IOCTL_SET_PRIORITY:
+		if (copy_from_user(&prio, (void __user *)arg, sizeof(prio)))
+			return -EFAULT;
+		if (prio.pad || prio.priority > DMA_BUF_PRIORITY_MAX)
+			return -EINVAL;
+		dma_buf_set_priority(dmabuf, prio.priority);
+		return 0;
+
+	case DMA_BUF_IOCTL_GET_PRIORITY:
+		memset(&prio, 0, sizeof(prio));
+		prio.priority = dma_buf_get_priority(dmabuf);
+		if (copy_to_user((void __user *)arg, &prio, sizeof(prio)))
+			return -EFAULT;
+		return 0;
+
 #if IS_ENABLED(CONFIG_SYNC_FILE)
 	case DMA_BUF_IOCTL_EXPORT_SYNC_FILE:
 		return dma_buf_export_sync_file(dmabuf, (void __user *)arg);
@@ -604,6 +653,7 @@ static void dma_buf_show_fdinfo(struct seq_file *m, struct file *file)
 	if (dmabuf->name)
 		seq_printf(m, "name:\t%s\n", dmabuf->name);
 	spin_unlock(&dmabuf->name_lock);
+	seq_printf(m, "priority:\t%u\n", dma_buf_get_priority(dmabuf));
 }
 
 static const struct file_operations dma_buf_fops = {
@@ -748,6 +798,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
 	dmabuf->exp_name = exp_info->exp_name;
 	dmabuf->owner = exp_info->owner;
 	spin_lock_init(&dmabuf->name_lock);
+	atomic_set(&dmabuf->priority, DMA_BUF_PRIORITY_DEFAULT);
 	init_waitqueue_head(&dmabuf->poll);
 	dmabuf->cb_in.poll = dmabuf->cb_out.poll = &dmabuf->poll;
 	dmabuf->cb_in.active = dmabuf->cb_out.active = 0;
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index d1203da56fc5..b3d3f2858704 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -354,6 +354,29 @@ struct dma_buf {
 	/** @name_lock: Spinlock to protect name access for read access. */
 	spinlock_t name_lock;
 
+	/**
+	 * @priority:
+	 *
+	 * Reclaim-priority hint for this buffer's backing memory, in the
+	 * range DMA_BUF_PRIORITY_MIN..DMA_BUF_PRIORITY_MAX (see
+	 * include/uapi/linux/dma-buf.h). Lower values should be reclaimed
+	 * EARLIER under memory pressure. Defaults to
+	 * DMA_BUF_PRIORITY_DEFAULT.
+	 *
+	 * This is a hint only: dma-buf core implements no eviction policy
+	 * of its own, it merely stores and reports the value so exporters
+	 * (and cooperating shrinkers) have one shared, generic place to
+	 * look instead of each inventing a private side channel. Read with
+	 * dma_buf_get_priority(), set with dma_buf_set_priority() , also
+	 * reachable from userspace via DMA_BUF_IOCTL_SET_PRIORITY /
+	 * DMA_BUF_IOCTL_GET_PRIORITY.
+	 *
+	 * Plain atomic_t rather than a lock: this is a coarse, racy-by-
+	 * design hint consulted opportunistically, not a value anything
+	 * synchronizes correctness on.
+	 */
+	atomic_t priority;
+
 	/**
 	 * @owner:
 	 *
@@ -566,6 +589,9 @@ void dma_buf_unpin(struct dma_buf_attachment *attach);
 
 struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info);
 
+void dma_buf_set_priority(struct dma_buf *dmabuf, unsigned int priority);
+unsigned int dma_buf_get_priority(struct dma_buf *dmabuf);
+
 int dma_buf_fd(struct dma_buf *dmabuf, int flags);
 struct dma_buf *dma_buf_get(int fd);
 void dma_buf_put(struct dma_buf *dmabuf);
diff --git a/include/uapi/linux/dma-buf.h b/include/uapi/linux/dma-buf.h
index e827c9d20c5d..4a1d26e0b0a0 100644
--- a/include/uapi/linux/dma-buf.h
+++ b/include/uapi/linux/dma-buf.h
@@ -168,6 +168,37 @@ struct dma_buf_import_sync_file {
 	__s32 fd;
 };
 
+/**
+ * struct dma_buf_priority - Reclaim-priority hint for a dma-buf
+ *
+ * dma-buf has no generic mechanism for a buffer's exporter, importer, or
+ * a cooperating userspace agent to signal how eagerly this buffer's
+ * backing memory should be given up relative to other buffers when the
+ * system is under memory pressure. Every subsystem that wants this today
+ * (GPU drivers juggling foreground/background clients, memory-tiering
+ * allocators for large ML/AI working sets, ...) has to build its own
+ * private, driver-specific side channel to express it.
+ *
+ * DMA_BUF_IOCTL_SET_PRIORITY / DMA_BUF_IOCTL_GET_PRIORITY add one shared,
+ * generic hint that any dma-buf exporter MAY consult. This is a hint
+ * only: the dma-buf core stores and reports the value, it implements no
+ * eviction policy of its own and by itself changes no behavior for any
+ * existing exporter.
+ */
+struct dma_buf_priority {
+	/**
+	 * @priority: DMA_BUF_PRIORITY_MIN..DMA_BUF_PRIORITY_MAX. Lower
+	 * values should be reclaimed EARLIER under memory pressure.
+	 */
+	__u32 priority;
+	/** @pad: must be zero, reserved for future use. */
+	__u32 pad;
+};
+
+#define DMA_BUF_PRIORITY_MIN		0
+#define DMA_BUF_PRIORITY_DEFAULT	128
+#define DMA_BUF_PRIORITY_MAX		255
+
 #define DMA_BUF_BASE		'b'
 #define DMA_BUF_IOCTL_SYNC	_IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
 
@@ -179,5 +210,7 @@ struct dma_buf_import_sync_file {
 #define DMA_BUF_SET_NAME_B	_IOW(DMA_BUF_BASE, 1, __u64)
 #define DMA_BUF_IOCTL_EXPORT_SYNC_FILE	_IOWR(DMA_BUF_BASE, 2, struct dma_buf_export_sync_file)
 #define DMA_BUF_IOCTL_IMPORT_SYNC_FILE	_IOW(DMA_BUF_BASE, 3, struct dma_buf_import_sync_file)
+#define DMA_BUF_IOCTL_SET_PRIORITY	_IOW(DMA_BUF_BASE, 4, struct dma_buf_priority)
+#define DMA_BUF_IOCTL_GET_PRIORITY	_IOR(DMA_BUF_BASE, 5, struct dma_buf_priority)
 
 #endif
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [RFC PATCH] dma-buf: add a generic reclaim-priority hint
  2026-08-20 19:08 [RFC PATCH] dma-buf: add a generic reclaim-priority hint Ferran Duarri
@ 2026-08-20 19:14 ` sashiko-bot
  2026-08-20 19:53 ` Ferran Duarri
  2026-08-20 20:04 ` Ferran Duarri
  2 siblings, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-08-20 19:14 UTC (permalink / raw)
  To: Ferran Duarri; +Cc: dri-devel, media-ci

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] UAPI extensibility flaw: DMA_BUF_IOCTL_GET_PRIORITY is defined as _IOR and does not validate the 'pad' field on input.
--

--- Patch [1]: [RFC PATCH] dma-buf: add a generic reclaim-priority hint ---
commit be79050598dd83ece044d5037692f147154efbe0
Author: Ferran Duarri <ferran.duarri@me.com>

dma-buf: add a generic reclaim-priority hint

This commit introduces a priority hint to dma-buf backing memory to help
subsystems decide eviction order under memory pressure. It adds the hint
field to struct dma_buf along with GET and SET ioctls to manage it from
userspace.

> diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> --- a/drivers/dma-buf/dma-buf.c
> +++ b/drivers/dma-buf/dma-buf.c
[ ... ]
> @@ -580,6 +614,21 @@ static long dma_buf_ioctl(struct file *file,
>  	case DMA_BUF_SET_NAME_B:
>  		return dma_buf_set_name(dmabuf, (const char __user *)arg);
>  
> +	case DMA_BUF_IOCTL_SET_PRIORITY:
> +		if (copy_from_user(&prio, (void __user *)arg, sizeof(prio)))
> +			return -EFAULT;
> +		if (prio.pad || prio.priority > DMA_BUF_PRIORITY_MAX)
> +			return -EINVAL;
> +		dma_buf_set_priority(dmabuf, prio.priority);
> +		return 0;
> +
> +	case DMA_BUF_IOCTL_GET_PRIORITY:
> +		memset(&prio, 0, sizeof(prio));
> +		prio.priority = dma_buf_get_priority(dmabuf);
> +		if (copy_to_user((void __user *)arg, &prio, sizeof(prio)))
> +			return -EFAULT;
> +		return 0;

[Severity: Medium]
Since the pad field in struct dma_buf_priority is documented as "must be
zero, reserved for future use", should we validate it in the GET ioctl as
well?

Because dma_buf_ioctl() does a memset() and copy_to_user() without first
calling copy_from_user() to check if the pad is zero, userspace isn't
forced to initialize it.

If we ever want to use the pad field for input flags or modifiers in the
future, we won't be able to do so without breaking existing userspace
applications that might be leaving it uninitialized.

> diff --git a/include/uapi/linux/dma-buf.h b/include/uapi/linux/dma-buf.h
> --- a/include/uapi/linux/dma-buf.h
> +++ b/include/uapi/linux/dma-buf.h
[ ... ]
> @@ -179,5 +210,7 @@ struct dma_buf_import_sync_file {
>  #define DMA_BUF_SET_NAME_B	_IOW(DMA_BUF_BASE, 1, __u64)
>  #define DMA_BUF_IOCTL_EXPORT_SYNC_FILE	_IOWR(DMA_BUF_BASE, 2, struct dma_buf_export_sync_file)
>  #define DMA_BUF_IOCTL_IMPORT_SYNC_FILE	_IOW(DMA_BUF_BASE, 3, struct dma_buf_import_sync_file)
> +#define DMA_BUF_IOCTL_SET_PRIORITY	_IOW(DMA_BUF_BASE, 4, struct dma_buf_priority)
> +#define DMA_BUF_IOCTL_GET_PRIORITY	_IOR(DMA_BUF_BASE, 5, struct dma_buf_priority)

[Severity: Medium]
If we want to validate the pad field as an input parameter to preserve future
extensibility, should this ioctl be defined as _IOWR instead of _IOR?

Using _IOR signifies an output-only operation, which dictates the ioctl
number and structurally discourages the kernel from reading inputs from the
structure.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260820190838.221435-1-ferran.duarri@me.com?part=1

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC PATCH] dma-buf: add a generic reclaim-priority hint
  2026-08-20 19:08 [RFC PATCH] dma-buf: add a generic reclaim-priority hint Ferran Duarri
  2026-08-20 19:14 ` sashiko-bot
@ 2026-08-20 19:53 ` Ferran Duarri
  2026-08-20 20:04 ` Ferran Duarri
  2 siblings, 0 replies; 4+ messages in thread
From: Ferran Duarri @ 2026-08-20 19:53 UTC (permalink / raw)
  To: Sumit Semwal, Christian König
  Cc: linux-media, dri-devel, linaro-mm-sig, linux-kernel,
	Ferran Duarri

Following up on my own patch to put its weak parts up front rather than
have them found in review.

The only consumer is out-of-tree, and it is mine. The commit message says
"an out-of-tree memory tiering driver we've been using", which undersells
the conflict of interest: the driver is greenboost.ko, I wrote it, and it
is the only thing anywhere that reads dma_buf_get_priority(). Nothing
in-tree constrains these semantics. Adding UAPI -- two ioctls, an fdinfo
field, and a DMA_BUF_PRIORITY_* range -- with no in-tree user is normally
declined, and I think that is the right default.

One claim in the commit message is not supported and I withdraw it. "GPU
drivers juggling foreground and background clients want it" -- I have no
thread or maintainer statement to cite for that and should not have
asserted it. What I can support is narrower: a driver that pins pages via
FOLL_LONGTERM has nowhere generic to express relative reclaim preference,
so it invents a private side channel. Mine did exactly that, a private
ioctl plus a gaming_mode sysfs flag, before this patch existed.

How the hint is actually consumed, so the semantics are judgeable rather
than hypothetical: greenboost.ko tiers a model's working set across VRAM,
system RAM and NVMe. Its T2 eviction sweep reads dma_buf_get_priority()
as a skip-on-threshold check that re-orders which already-eligible
buffers are reclaimed first. It never makes a buffer eligible that was
not already, and it never overrides the invariant that KV-cache buffers
are not evicted. The hint changes ordering within a set, not membership
of it.

A review bot on this thread has already found one thing that needs fixing,
and it is right. DMA_BUF_IOCTL_GET_PRIORITY is _IOR and never copies the
struct in from userspace, so the pad field that the UAPI documents as
"must be zero, reserved for future use" is enforced on SET and not on GET.
That makes the promise empty: nothing stops existing userspace leaving pad
uninitialised, and a later kernel wanting to use it as an input flag would
have to break them. v2 will make GET _IOWR, copy the struct in, and reject
a non-zero pad exactly as SET does. This is worth settling now rather than
later, because changing the direction bits changes the ioctl number, and
that is only free while there are no users.

I would rather hear the shape question below answered before posting that
v2, so the two rounds do not collide.

What I am asking for is a read on the shape, not a merge. If the answer
is "come back with an in-tree user", that is a useful answer and I will
take it. If the shape itself is wrong -- priority belongs on the
attachment rather than the dma_buf, the range should be smaller, a hint
with no in-core policy is the wrong abstraction -- that is more useful
still, because it is cheaper to hear now than after something is built on
it.

Thanks,
Ferran

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC PATCH] dma-buf: add a generic reclaim-priority hint
  2026-08-20 19:08 [RFC PATCH] dma-buf: add a generic reclaim-priority hint Ferran Duarri
  2026-08-20 19:14 ` sashiko-bot
  2026-08-20 19:53 ` Ferran Duarri
@ 2026-08-20 20:04 ` Ferran Duarri
  2 siblings, 0 replies; 4+ messages in thread
From: Ferran Duarri @ 2026-08-20 20:04 UTC (permalink / raw)
  To: Sumit Semwal, Christian König
  Cc: linux-media, dri-devel, linaro-mm-sig, linux-kernel,
	Ferran Duarri

Following up on my own patch to put its weak parts up front rather than
have them found in review.

The only consumer is out-of-tree, and it is mine. The commit message says
"an out-of-tree memory tiering driver we've been using", which undersells
the conflict of interest: the driver is greenboost.ko, I wrote it, and it
is the only thing anywhere that reads dma_buf_get_priority(). Nothing
in-tree constrains these semantics. Adding UAPI -- two ioctls, an fdinfo
field, and a DMA_BUF_PRIORITY_* range -- with no in-tree user is normally
declined, and I think that is the right default.

One claim in the commit message was not supported as written, and I withdraw
that wording. "GPU drivers juggling foreground and background clients want
it" cited no thread and no maintainer, and I should not have asserted what
other subsystems want on their behalf.

What I can point at instead is in-tree code. TTM keeps a per-BO priority
(TTM_MAX_BO_PRIORITY, four levels) with one LRU list per level, and its
eviction walk ascends those levels in order -- so TTM has already concluded
that per-buffer eviction ordering is worth having, and keeps it private to
TTM. At UAPI level the same question has been answered three times, once per
driver: DRM_IOCTL_PANFROST_MADVISE, DRM_IOCTL_MSM_GEM_MADVISE and
DRM_IOCTL_VC4_GEM_MADVISE each ship their own WILLNEED/DONTNEED. A driver
that pins pages via FOLL_LONGTERM has nowhere generic to express relative
reclaim preference, so it invents a private channel; my own out-of-tree
module invented one more, an ioctl plus a gaming_mode sysfs flag, before this
patch existed.

I want to be exact about what that does and does not show. None of those act
on an exported dma-buf -- they are all driver-internal. So they are evidence
that the need recurs, and that the kernel has already accepted the concept
including at UAPI level, but they are not an in-tree consumer of a
dma-buf-level hint. The blocker above stands unchanged.

How the hint is actually consumed, so the semantics are judgeable rather
than hypothetical: greenboost.ko tiers a model's working set across VRAM,
system RAM and NVMe. Its T2 eviction sweep reads dma_buf_get_priority()
as a skip-on-threshold check that re-orders which already-eligible
buffers are reclaimed first. It never makes a buffer eligible that was
not already, and it never overrides the invariant that KV-cache buffers
are not evicted. The hint changes ordering within a set, not membership
of it.

A review bot on this thread has already found one thing that needs fixing,
and it is right. DMA_BUF_IOCTL_GET_PRIORITY is _IOR and never copies the
struct in from userspace, so the pad field that the UAPI documents as
"must be zero, reserved for future use" is enforced on SET and not on GET.
That makes the promise empty: nothing stops existing userspace leaving pad
uninitialised, and a later kernel wanting to use it as an input flag would
have to break them. v2 will make GET _IOWR, copy the struct in, and reject
a non-zero pad exactly as SET does. This is worth settling now rather than
later, because changing the direction bits changes the ioctl number, and
that is only free while there are no users.

I would rather hear the shape question below answered before posting that
v2, so the two rounds do not collide.

What I am asking for is a read on the shape, not a merge. If the answer
is "come back with an in-tree user", that is a useful answer and I will
take it. If the shape itself is wrong -- priority belongs on the
attachment rather than the dma_buf, the range should be smaller, a hint
with no in-core policy is the wrong abstraction -- that is more useful
still, because it is cheaper to hear now than after something is built on
it.

Thanks,
Ferran

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-08-20 20:04 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-20 19:08 [RFC PATCH] dma-buf: add a generic reclaim-priority hint Ferran Duarri
2026-08-20 19:14 ` sashiko-bot
2026-08-20 19:53 ` Ferran Duarri
2026-08-20 20:04 ` Ferran Duarri

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.