* [LTP] [PATCH v4] mmap01: Convert to new API
@ 2024-12-10 21:38 Ricardo B. Marliere via ltp
2024-12-11 1:47 ` Petr Vorel
0 siblings, 1 reply; 5+ messages in thread
From: Ricardo B. Marliere via ltp @ 2024-12-10 21:38 UTC (permalink / raw)
To: ltp
From: Ricardo B. Marliere <rbm@suse.com>
Refactor the old mmap01 code into the new LTP API.
Signed-off-by: Ricardo B. Marliere <rbm@suse.com>
---
Changes in v4:
- Move file check logic into a new function check_file() instead of using a
system() call to grep.
- Link to v3: https://lore.kernel.org/r/20241118-convert_mmap01-v3-1-b275c90035f5@suse.com/
Changes in v3:
- Use SAFE_MMAP and SAFE_MUNMAP as suggested by Jan Stancek.
- Re-aligned a few comments.
- Link to v2: https://lore.kernel.org/r/20241114-convert_mmap01-v2-1-a8a1379dec89@suse.com
Changes in v2:
- Fixed metadata alignment.
- Link to v1: https://lore.kernel.org/r/20241113-convert_mmap01-v1-1-e7d60e7404c4@suse.com
---
testcases/kernel/syscalls/mmap/mmap01.c | 255 ++++++++++++--------------------
1 file changed, 97 insertions(+), 158 deletions(-)
diff --git a/testcases/kernel/syscalls/mmap/mmap01.c b/testcases/kernel/syscalls/mmap/mmap01.c
index 99266b57ffc16e6c3a0e31a2c87d0f8106f429e5..fff39d0ff6e1c271616d1391904f7011fbb2675e 100644
--- a/testcases/kernel/syscalls/mmap/mmap01.c
+++ b/testcases/kernel/syscalls/mmap/mmap01.c
@@ -1,194 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) International Business Machines Corp., 2001
+ * Copyright (c) 2024 Ricardo B. Marliere <rbm@suse.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * HISTORY
+ * 07/2001 Ported by Wayne Boyer
*/
-/*
- * Test Description:
- * Verify that, mmap() succeeds when used to map a file where size of the
- * file is not a multiple of the page size, the memory area beyond the end
- * of the file to the end of the page is accessible. Also, verify that
- * this area is all zeroed and the modifications done to this area are
- * not written to the file.
+/*\
+ * [Description]
*
- * Expected Result:
- * mmap() should succeed returning the address of the mapped region.
- * The memory area beyond the end of file to the end of page should be
- * filled with zero.
- * The changes beyond the end of file should not get written to the file.
+ * Verify that mmap() succeeds when used to map a file where size of the
+ * file is not a multiple of the page size, the memory area beyond the end
+ * of the file to the end of the page is accessible. Also, verify that
+ * this area is all zeroed and the modifications done to this area are
+ * not written to the file.
*
- * HISTORY
- * 07/2001 Ported by Wayne Boyer
+ * mmap() should succeed returning the address of the mapped region.
+ * The memory area beyond the end of file to the end of page should be
+ * filled with zero.
+ * The changes beyond the end of file should not get written to the file.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <signal.h>
-#include <stdint.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <sys/shm.h>
-
-#include "test.h"
-
-#define TEMPFILE "mmapfile"
-
-char *TCID = "mmap01";
-int TST_TOTAL = 1;
+
+#include "tst_test.h"
+
+#define TEMPFILE "mmapfile"
+#define STRING "hello world"
static char *addr;
static char *dummy;
static size_t page_sz;
static size_t file_sz;
static int fildes;
-static char cmd_buffer[BUFSIZ];
-static void setup(void);
-static void cleanup(void);
-
-int main(int ac, char **av)
+static void check_file(void)
{
- int lc;
-
- tst_parse_opts(ac, av, NULL, NULL);
-
- setup();
-
- for (lc = 0; TEST_LOOPING(lc); lc++) {
-
- tst_count = 0;
-
- /*
- * Call mmap to map the temporary file beyond EOF
- * with write access.
- */
- errno = 0;
- addr = mmap(NULL, page_sz, PROT_READ | PROT_WRITE,
- MAP_FILE | MAP_SHARED, fildes, 0);
-
- /* Check for the return value of mmap() */
- if (addr == MAP_FAILED) {
- tst_resm(TFAIL | TERRNO, "mmap of %s failed", TEMPFILE);
- continue;
- }
-
- /*
- * Check if mapped memory area beyond EOF are
- * zeros and changes beyond EOF are not written
- * to file.
- */
- if (memcmp(&addr[file_sz], dummy, page_sz - file_sz)) {
- tst_brkm(TFAIL, cleanup,
- "mapped memory area contains invalid "
- "data");
- }
-
- /*
- * Initialize memory beyond file size
- */
- addr[file_sz] = 'X';
- addr[file_sz + 1] = 'Y';
- addr[file_sz + 2] = 'Z';
-
- /*
- * Synchronize the mapped memory region
- * with the file.
- */
- if (msync(addr, page_sz, MS_SYNC) != 0) {
- tst_brkm(TFAIL | TERRNO, cleanup,
- "failed to synchronize mapped file");
- }
-
- /*
- * Now, Search for the pattern 'XYZ' in the
- * temporary file. The pattern should not be
- * found and the return value should be 1.
- */
- if (system(cmd_buffer) != 0) {
- tst_resm(TPASS,
- "Functionality of mmap() successful");
- } else {
- tst_resm(TFAIL,
- "Specified pattern found in file");
- }
-
- /* Clean up things in case we are looping */
- /* Unmap the mapped memory */
- if (munmap(addr, page_sz) != 0) {
- tst_brkm(TFAIL | TERRNO, NULL, "munmap failed");
- }
- }
+ int i, fildes, buf_len = sizeof(STRING) + 3;
+ char buf[buf_len];
+
+ fildes = SAFE_OPEN(TEMPFILE, O_RDONLY);
+ SAFE_READ(0, fildes, buf, sizeof(buf));
+
+ for (i = 0; i < buf_len; i++)
+ if (buf[i] == 'X' || buf[i] == 'Y' || buf[i] == 'Z')
+ break;
- cleanup();
- tst_exit();
+ if (i == buf_len)
+ tst_res(TPASS, "Functionality of mmap() successful");
+ else
+ tst_res(TFAIL, "Specified pattern found in file");
+
+ SAFE_CLOSE(fildes);
}
-static void setup(void)
+static void run(void)
{
- struct stat stat_buf;
- char Path_name[PATH_MAX];
- char write_buf[] = "hello world\n";
+ pid_t pid;
+
+ addr = SAFE_MMAP(NULL, page_sz, PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_SHARED, fildes, 0);
+
+ /*
+ * Check if mapped memory area beyond EOF are zeros and changes beyond
+ * EOF are not written to file.
+ */
+ if (memcmp(&addr[file_sz], dummy, page_sz - file_sz))
+ tst_brk(TFAIL, "mapped memory area contains invalid data");
+
+ /*
+ * Initialize memory beyond file size
+ */
+ addr[file_sz] = 'X';
+ addr[file_sz + 1] = 'Y';
+ addr[file_sz + 2] = 'Z';
+
+ /*
+ * Synchronize the mapped memory region with the file.
+ */
+ if (msync(addr, page_sz, MS_SYNC) != 0) {
+ tst_res(TFAIL | TERRNO, "failed to synchronize mapped file");
+ return;
+ }
- tst_sig(FORK, DEF_HANDLER, cleanup);
+ /*
+ * Now, search for the pattern 'XYZ' in the temporary file.
+ * The pattern should not be found and the return value should be 1.
+ */
+ pid = SAFE_FORK();
+ if (!pid) {
+ check_file();
+ exit(0);
+ }
- TEST_PAUSE;
+ SAFE_MUNMAP(addr, page_sz);
+}
- tst_tmpdir();
+static void cleanup(void)
+{
+ if (dummy)
+ free(dummy);
+ if (fildes > 0)
+ SAFE_CLOSE(fildes);
+}
- /* Get the path of temporary file to be created */
- if (getcwd(Path_name, sizeof(Path_name)) == NULL) {
- tst_brkm(TFAIL | TERRNO, cleanup,
- "getcwd failed to get current working directory");
- }
+static void setup(void)
+{
+ char *write_buf = STRING;
+ struct stat stat_buf;
- /* Creat a temporary file used for mapping */
- if ((fildes = open(TEMPFILE, O_RDWR | O_CREAT, 0666)) < 0) {
- tst_brkm(TFAIL, cleanup, "opening %s failed", TEMPFILE);
- }
+ /* Create a temporary file used for mapping */
+ fildes = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666);
/* Write some data into temporary file */
- if (write(fildes, write_buf, strlen(write_buf)) != (long)strlen(write_buf)) {
- tst_brkm(TFAIL, cleanup, "writing to %s", TEMPFILE);
- }
+ SAFE_WRITE(SAFE_WRITE_ALL, fildes, write_buf, strlen(write_buf));
/* Get the size of temporary file */
- if (stat(TEMPFILE, &stat_buf) < 0) {
- tst_brkm(TFAIL | TERRNO, cleanup, "stat of %s failed",
- TEMPFILE);
- }
+ SAFE_STAT(TEMPFILE, &stat_buf);
file_sz = stat_buf.st_size;
page_sz = getpagesize();
/* Allocate and initialize dummy string of system page size bytes */
- if ((dummy = calloc(page_sz, sizeof(char))) == NULL) {
- tst_brkm(TFAIL, cleanup, "calloc failed (dummy)");
- }
-
- /* Create the command which will be executed in the test */
- sprintf(cmd_buffer, "grep XYZ %s/%s > /dev/null", Path_name, TEMPFILE);
+ dummy = SAFE_CALLOC(page_sz, sizeof(char));
}
-static void cleanup(void)
-{
- close(fildes);
- free(dummy);
- tst_rmdir();
-}
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .needs_tmpdir = 1,
+ .test_all = run,
+ .forks_child = 1,
+};
---
base-commit: ad651beeed393121ee541e3d07990e9a3d14c0c0
change-id: 20241210-convert_mmap01-682f71beb58d
Best regards,
--
Ricardo B. Marliere <rbm@suse.com>
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [LTP] [PATCH v4] mmap01: Convert to new API
2024-12-10 21:38 [LTP] [PATCH v4] mmap01: Convert to new API Ricardo B. Marliere via ltp
@ 2024-12-11 1:47 ` Petr Vorel
2024-12-11 10:29 ` Ricardo B. Marliere via ltp
0 siblings, 1 reply; 5+ messages in thread
From: Petr Vorel @ 2024-12-11 1:47 UTC (permalink / raw)
To: Ricardo B. Marliere; +Cc: ltp
Hi Ricardo,
...
> +static void run(void)
> {
> + pid_t pid;
> +
> + addr = SAFE_MMAP(NULL, page_sz, PROT_READ | PROT_WRITE,
> + MAP_FILE | MAP_SHARED, fildes, 0);
> +
> + /*
> + * Check if mapped memory area beyond EOF are zeros and changes beyond
> + * EOF are not written to file.
> + */
> + if (memcmp(&addr[file_sz], dummy, page_sz - file_sz))
> + tst_brk(TFAIL, "mapped memory area contains invalid data");
FYI test fails when run more iterations (e.g. -i2)
Kind regards,
Petr
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [LTP] [PATCH v4] mmap01: Convert to new API
2024-12-11 1:47 ` Petr Vorel
@ 2024-12-11 10:29 ` Ricardo B. Marliere via ltp
2024-12-11 19:00 ` Petr Vorel
0 siblings, 1 reply; 5+ messages in thread
From: Ricardo B. Marliere via ltp @ 2024-12-11 10:29 UTC (permalink / raw)
To: Petr Vorel; +Cc: ltp
Hi Petr!
On 11 Dec 24 02:47, Petr Vorel wrote:
> Hi Ricardo,
>
> ...
> > +static void run(void)
> > {
> > + pid_t pid;
> > +
> > + addr = SAFE_MMAP(NULL, page_sz, PROT_READ | PROT_WRITE,
> > + MAP_FILE | MAP_SHARED, fildes, 0);
> > +
> > + /*
> > + * Check if mapped memory area beyond EOF are zeros and changes beyond
> > + * EOF are not written to file.
> > + */
> > + if (memcmp(&addr[file_sz], dummy, page_sz - file_sz))
> > + tst_brk(TFAIL, "mapped memory area contains invalid data");
> FYI test fails when run more iterations (e.g. -i2)
>
Thanks for taking a look, but I don't see the issue here:
# /opt/ltp/testcases/bin/mmap01 -i4
tst_tmpdir.c:316: TINFO: Using /tmp/LTP_mmaiVJsAq as tmpdir (fuse filesystem)
tst_test.c:1890: TINFO: LTP version: 20240930-73-g865be36ffce8
tst_test.c:1894: TINFO: Tested kernel: 6.11.0-virtme #1 SMP PREEMPT_DYNAMIC Fri Oct 4 13:39:48 -03 2024 x86_64
tst_test.c:1725: TINFO: Timeout per run is 0h 00m 30s
mmap01.c:49: TPASS: Functionality of mmap() successful YES
mmap01.c:49: TPASS: Functionality of mmap() successful YES
mmap01.c:49: TPASS: Functionality of mmap() successful YES
mmap01.c:49: TPASS: Functionality of mmap() successful YES
Summary:
passed 4
failed 0
broken 0
skipped 0
warnings 0
I appended the "YES" just to make sure I wasn't running some outdated
code, can you please provide more details?
Thanks!
- Ricardo.
> Kind regards,
> Petr
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [LTP] [PATCH v4] mmap01: Convert to new API
2024-12-11 10:29 ` Ricardo B. Marliere via ltp
@ 2024-12-11 19:00 ` Petr Vorel
2024-12-13 1:08 ` Ricardo B. Marliere via ltp
0 siblings, 1 reply; 5+ messages in thread
From: Petr Vorel @ 2024-12-11 19:00 UTC (permalink / raw)
To: Ricardo B. Marliere; +Cc: ltp
> Hi Petr!
> On 11 Dec 24 02:47, Petr Vorel wrote:
> > Hi Ricardo,
> > ...
> > > +static void run(void)
> > > {
> > > + pid_t pid;
> > > +
> > > + addr = SAFE_MMAP(NULL, page_sz, PROT_READ | PROT_WRITE,
> > > + MAP_FILE | MAP_SHARED, fildes, 0);
> > > +
> > > + /*
> > > + * Check if mapped memory area beyond EOF are zeros and changes beyond
> > > + * EOF are not written to file.
> > > + */
> > > + if (memcmp(&addr[file_sz], dummy, page_sz - file_sz))
> > > + tst_brk(TFAIL, "mapped memory area contains invalid data");
> > FYI test fails when run more iterations (e.g. -i2)
> Thanks for taking a look, but I don't see the issue here:
> # /opt/ltp/testcases/bin/mmap01 -i4
> tst_tmpdir.c:316: TINFO: Using /tmp/LTP_mmaiVJsAq as tmpdir (fuse filesystem)
> tst_test.c:1890: TINFO: LTP version: 20240930-73-g865be36ffce8
> tst_test.c:1894: TINFO: Tested kernel: 6.11.0-virtme #1 SMP PREEMPT_DYNAMIC Fri Oct 4 13:39:48 -03 2024 x86_64
> tst_test.c:1725: TINFO: Timeout per run is 0h 00m 30s
> mmap01.c:49: TPASS: Functionality of mmap() successful YES
> mmap01.c:49: TPASS: Functionality of mmap() successful YES
> mmap01.c:49: TPASS: Functionality of mmap() successful YES
> mmap01.c:49: TPASS: Functionality of mmap() successful YES
> Summary:
> passed 4
> failed 0
> broken 0
> skipped 0
> warnings 0
> I appended the "YES" just to make sure I wasn't running some outdated
> code, can you please provide more details?
I have no idea myself. I verified if I'm using v4 [1] and I really do.
Can you please push the code you're using?
Your code I'm testing is in my fork [2].
Tested on more systems:
# ./mmap01 -i4
tst_tmpdir.c:316: TINFO: Using /tmp/LTP_mmabiOth0 as tmpdir (tmpfs filesystem)
tst_test.c:1890: TINFO: LTP version: 20240930-116-g23f5a4447
tst_test.c:1894: TINFO: Tested kernel: 6.13.0-rc1-1.g492f944-default #1 SMP PREEMPT_DYNAMIC Mon Dec 2 08:55:00 UTC 2024 (492f944) x86_64
tst_test.c:1725: TINFO: Timeout per run is 0h 00m 30s
mmap01.c:49: TPASS: Functionality of mmap() successful
mmap01.c:68: TFAIL: mapped memory area contains invalid data
Summary:
passed 1
failed 1
broken 0
skipped 0
warnings 0
$ ./mmap01 -i4
tst_tmpdir.c:316: TINFO: Using /tmp/LTP_mmakqgzvS as tmpdir (tmpfs filesystem)
tst_test.c:1890: TINFO: LTP version: 20240930-115-g786b808eda
tst_test.c:1894: TINFO: Tested kernel: 6.11-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.11 (2024-11-23) x86_64
tst_test.c:1725: TINFO: Timeout per run is 0h 00m 30s
mmap01.c:49: TPASS: Functionality of mmap() successful
mmap01.c:68: TFAIL: mapped memory area contains invalid data
Summary:
passed 1
failed 1
broken 0
skipped 0
warnings 0
[1] https://patchwork.ozlabs.org/project/ltp/patch/20241210-convert_mmap01-v4-1-c2338a2ca071@suse.com/
[2] https://github.com/pevik/ltp/commit/a3c07097784088a679e77a4486bb10adfe03eea0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [LTP] [PATCH v4] mmap01: Convert to new API
2024-12-11 19:00 ` Petr Vorel
@ 2024-12-13 1:08 ` Ricardo B. Marliere via ltp
0 siblings, 0 replies; 5+ messages in thread
From: Ricardo B. Marliere via ltp @ 2024-12-13 1:08 UTC (permalink / raw)
To: Petr Vorel; +Cc: ltp
Hello!
On 11 Dec 24 20:00, Petr Vorel wrote:
> > Hi Petr!
>
> > On 11 Dec 24 02:47, Petr Vorel wrote:
> > > Hi Ricardo,
>
> > > ...
> > > > +static void run(void)
> > > > {
> > > > + pid_t pid;
> > > > +
> > > > + addr = SAFE_MMAP(NULL, page_sz, PROT_READ | PROT_WRITE,
> > > > + MAP_FILE | MAP_SHARED, fildes, 0);
> > > > +
> > > > + /*
> > > > + * Check if mapped memory area beyond EOF are zeros and changes beyond
> > > > + * EOF are not written to file.
> > > > + */
> > > > + if (memcmp(&addr[file_sz], dummy, page_sz - file_sz))
> > > > + tst_brk(TFAIL, "mapped memory area contains invalid data");
> > > FYI test fails when run more iterations (e.g. -i2)
>
>
> > Thanks for taking a look, but I don't see the issue here:
>
> > # /opt/ltp/testcases/bin/mmap01 -i4
> > tst_tmpdir.c:316: TINFO: Using /tmp/LTP_mmaiVJsAq as tmpdir (fuse filesystem)
> > tst_test.c:1890: TINFO: LTP version: 20240930-73-g865be36ffce8
> > tst_test.c:1894: TINFO: Tested kernel: 6.11.0-virtme #1 SMP PREEMPT_DYNAMIC Fri Oct 4 13:39:48 -03 2024 x86_64
> > tst_test.c:1725: TINFO: Timeout per run is 0h 00m 30s
> > mmap01.c:49: TPASS: Functionality of mmap() successful YES
> > mmap01.c:49: TPASS: Functionality of mmap() successful YES
> > mmap01.c:49: TPASS: Functionality of mmap() successful YES
> > mmap01.c:49: TPASS: Functionality of mmap() successful YES
>
> > Summary:
> > passed 4
> > failed 0
> > broken 0
> > skipped 0
> > warnings 0
>
> > I appended the "YES" just to make sure I wasn't running some outdated
> > code, can you please provide more details?
>
> I have no idea myself. I verified if I'm using v4 [1] and I really do.
> Can you please push the code you're using?
> Your code I'm testing is in my fork [2].
>
> Tested on more systems:
Many thanks! After a fresh build I started seeing those, too. The issue
is that run() changes the file and the second run uses this updated
file. I pushed a new revision with a new set_file to put it in a known
state before each run.
FWIW I pushed it here:
https://github.com/rbmarliere/ltp/tree/b4/convert_mmap01
Thanks,
- Ricardo.
>
> # ./mmap01 -i4
> tst_tmpdir.c:316: TINFO: Using /tmp/LTP_mmabiOth0 as tmpdir (tmpfs filesystem)
> tst_test.c:1890: TINFO: LTP version: 20240930-116-g23f5a4447
> tst_test.c:1894: TINFO: Tested kernel: 6.13.0-rc1-1.g492f944-default #1 SMP PREEMPT_DYNAMIC Mon Dec 2 08:55:00 UTC 2024 (492f944) x86_64
> tst_test.c:1725: TINFO: Timeout per run is 0h 00m 30s
> mmap01.c:49: TPASS: Functionality of mmap() successful
> mmap01.c:68: TFAIL: mapped memory area contains invalid data
>
> Summary:
> passed 1
> failed 1
> broken 0
> skipped 0
> warnings 0
>
> $ ./mmap01 -i4
> tst_tmpdir.c:316: TINFO: Using /tmp/LTP_mmakqgzvS as tmpdir (tmpfs filesystem)
> tst_test.c:1890: TINFO: LTP version: 20240930-115-g786b808eda
> tst_test.c:1894: TINFO: Tested kernel: 6.11-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.11 (2024-11-23) x86_64
> tst_test.c:1725: TINFO: Timeout per run is 0h 00m 30s
> mmap01.c:49: TPASS: Functionality of mmap() successful
> mmap01.c:68: TFAIL: mapped memory area contains invalid data
>
> Summary:
> passed 1
> failed 1
> broken 0
> skipped 0
> warnings 0
>
> [1] https://patchwork.ozlabs.org/project/ltp/patch/20241210-convert_mmap01-v4-1-c2338a2ca071@suse.com/
> [2] https://github.com/pevik/ltp/commit/a3c07097784088a679e77a4486bb10adfe03eea0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2024-12-13 1:08 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-10 21:38 [LTP] [PATCH v4] mmap01: Convert to new API Ricardo B. Marliere via ltp
2024-12-11 1:47 ` Petr Vorel
2024-12-11 10:29 ` Ricardo B. Marliere via ltp
2024-12-11 19:00 ` Petr Vorel
2024-12-13 1:08 ` Ricardo B. Marliere via ltp
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.