* [PATCH 0/2] xfs: optimise XBF_TRYLOCK buffer lookups
@ 2018-04-18 0:21 Dave Chinner
2018-04-18 0:21 ` [PATCH 1/2] xfs: make xfs_buf_incore out of line Dave Chinner
2018-04-18 0:21 ` [PATCH 2/2] xfs: don't retry xfs_buf_find on XBF_TRYLOCK failure Dave Chinner
0 siblings, 2 replies; 11+ messages in thread
From: Dave Chinner @ 2018-04-18 0:21 UTC (permalink / raw)
To: linux-xfs
Hi folks,
This is a cleaned up version of my original patch to avoid
unnecessary buffer lookups on locked buffers when XBF_TRYLOCK is
set. That patch can be found here:
https://marc.info/?l=linux-xfs&m=151994388115521&w=2
Version 2:
- split out changes to xfs_incore interface to make _xfs_buf_find
static and not externally visible
- fixed indenting issues in error handling switch statement
Cheers,
Dave.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] xfs: make xfs_buf_incore out of line
2018-04-18 0:21 [PATCH 0/2] xfs: optimise XBF_TRYLOCK buffer lookups Dave Chinner
@ 2018-04-18 0:21 ` Dave Chinner
2018-04-18 10:29 ` Christoph Hellwig
2018-04-18 11:46 ` Carlos Maiolino
2018-04-18 0:21 ` [PATCH 2/2] xfs: don't retry xfs_buf_find on XBF_TRYLOCK failure Dave Chinner
1 sibling, 2 replies; 11+ messages in thread
From: Dave Chinner @ 2018-04-18 0:21 UTC (permalink / raw)
To: linux-xfs
From: Dave Chinner <dchinner@redhat.com>
Move xfs_buf_incore out of line and make it the only way to look up
a buffer in the buffer cache from outside the buffer cache. Convert
the external users of _xfs_buf_find() to xfs_buf_incore() and make
_xfs_buf_find() static.
Signed-Off-By: Dave Chinner <dchinner@redhat.com>
---
fs/xfs/xfs_buf.c | 21 ++++++++++++++++-----
fs/xfs/xfs_buf.h | 17 +++--------------
fs/xfs/xfs_qm.c | 5 ++---
3 files changed, 21 insertions(+), 22 deletions(-)
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 55661cbdb51b..2ca8e2c7fbc4 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -549,17 +549,17 @@ xfs_buf_hash_destroy(
}
/*
- * Look up, and creates if absent, a lockable buffer for
- * a given range of an inode. The buffer is returned
- * locked. No I/O is implied by this call.
+ * Look up (and insert if absent), a lockable buffer for a given
+ * range of an inode. The buffer is returned locked. No I/O is
+ * implied by this call.
*/
-xfs_buf_t *
+static struct xfs_buf *
_xfs_buf_find(
struct xfs_buftarg *btp,
struct xfs_buf_map *map,
int nmaps,
xfs_buf_flags_t flags,
- xfs_buf_t *new_bp)
+ struct xfs_buf *new_bp)
{
struct xfs_perag *pag;
xfs_buf_t *bp;
@@ -649,6 +649,17 @@ _xfs_buf_find(
return bp;
}
+struct xfs_buf *
+xfs_incore(
+ struct xfs_buftarg *target,
+ xfs_daddr_t blkno,
+ size_t numblks,
+ xfs_buf_flags_t flags)
+{
+ DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
+ return _xfs_buf_find(target, &map, 1, flags, NULL);
+}
+
/*
* Assembles a buffer covering the specified range. The code is optimised for
* cache hits, as metadata intensive workloads will see 3 orders of magnitude
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
index edced162a674..e8947c1adac0 100644
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -218,20 +218,9 @@ typedef struct xfs_buf {
} xfs_buf_t;
/* Finding and Reading Buffers */
-struct xfs_buf *_xfs_buf_find(struct xfs_buftarg *target,
- struct xfs_buf_map *map, int nmaps,
- xfs_buf_flags_t flags, struct xfs_buf *new_bp);
-
-static inline struct xfs_buf *
-xfs_incore(
- struct xfs_buftarg *target,
- xfs_daddr_t blkno,
- size_t numblks,
- xfs_buf_flags_t flags)
-{
- DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
- return _xfs_buf_find(target, &map, 1, flags, NULL);
-}
+struct xfs_buf *xfs_incore(struct xfs_buftarg *target,
+ xfs_daddr_t blkno, size_t numblks,
+ xfs_buf_flags_t flags);
struct xfs_buf *_xfs_buf_alloc(struct xfs_buftarg *target,
struct xfs_buf_map *map, int nmaps,
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index ec39ae274c78..aff4924f637f 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -1247,9 +1247,8 @@ xfs_qm_flush_one(
*/
if (!xfs_dqflock_nowait(dqp)) {
/* buf is pinned in-core by delwri list */
- DEFINE_SINGLE_BUF_MAP(map, dqp->q_blkno,
- mp->m_quotainfo->qi_dqchunklen);
- bp = _xfs_buf_find(mp->m_ddev_targp, &map, 1, 0, NULL);
+ bp = xfs_incore(mp->m_ddev_targp, dqp->q_blkno,
+ mp->m_quotainfo->qi_dqchunklen, 0);
if (!bp) {
error = -EINVAL;
goto out_unlock;
--
2.16.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/2] xfs: don't retry xfs_buf_find on XBF_TRYLOCK failure
2018-04-18 0:21 [PATCH 0/2] xfs: optimise XBF_TRYLOCK buffer lookups Dave Chinner
2018-04-18 0:21 ` [PATCH 1/2] xfs: make xfs_buf_incore out of line Dave Chinner
@ 2018-04-18 0:21 ` Dave Chinner
2018-04-18 10:30 ` Christoph Hellwig
` (2 more replies)
1 sibling, 3 replies; 11+ messages in thread
From: Dave Chinner @ 2018-04-18 0:21 UTC (permalink / raw)
To: linux-xfs
From: Dave Chinner <dchinner@redhat.com>
When looking at an event trace recently, I noticed that non-blocking
buffer lookup attempts would fail on cached locked buffers and then
run the slow cache-miss path. This means we are doing an xfs_buf
allocation, lookup and free unnecessarily every time we avoid
blocking on a locked buffer.
Fix this by changing _xfs_buf_find() to return an error status to
the caller to indicate that we failed the lock attempt rather than
just returning a NULL. This allows the higher level code to
discriminate between a cache miss and an cache hit that we failed to
lock.
This also allows us to return a -EFSCORRUPTED state if we are asked
to look up a block number outside the range of the filesystem in
_xfs_buf_find(), which moves us one step closer to being able to
handle such errors in a more graceful manner at the higher levels.
Signed-Off-By: Dave Chinner <dchinner@redhat.com>
---
fs/xfs/xfs_buf.c | 93 +++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 65 insertions(+), 28 deletions(-)
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 2ca8e2c7fbc4..41b386c26582 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -549,17 +549,31 @@ xfs_buf_hash_destroy(
}
/*
- * Look up (and insert if absent), a lockable buffer for a given
- * range of an inode. The buffer is returned locked. No I/O is
- * implied by this call.
+ * Look up a buffer in the buffer cache and return it referenced and locked
+ * in @found_bp.
+ *
+ * If @new_bp is supplied and we have a lookup miss, insert @new_bp into the
+ * cache.
+ *
+ * If XBF_TRYLOCK is set in @flags, only try to lock the buffer and return
+ * -EAGAIN if we fail to lock it.
+ *
+ * Return values are:
+ * -EFSCORRUPTED if have been supplied with an invalid address
+ * -EAGAIN on trylock failure
+ * -ENOENT if we fail to find a match and @new_bp was NULL
+ * 0, with @found_bp:
+ * - @new_bp if we inserted it into the cache
+ * - the buffer we found and locked.
*/
-static struct xfs_buf *
-_xfs_buf_find(
+static int
+xfs_buf_find(
struct xfs_buftarg *btp,
struct xfs_buf_map *map,
int nmaps,
xfs_buf_flags_t flags,
- struct xfs_buf *new_bp)
+ struct xfs_buf *new_bp,
+ struct xfs_buf **found_bp)
{
struct xfs_perag *pag;
xfs_buf_t *bp;
@@ -567,6 +581,8 @@ _xfs_buf_find(
xfs_daddr_t eofs;
int i;
+ *found_bp = NULL;
+
for (i = 0; i < nmaps; i++)
cmap.bm_len += map[i].bm_len;
@@ -580,16 +596,11 @@ _xfs_buf_find(
*/
eofs = XFS_FSB_TO_BB(btp->bt_mount, btp->bt_mount->m_sb.sb_dblocks);
if (cmap.bm_bn < 0 || cmap.bm_bn >= eofs) {
- /*
- * XXX (dgc): we should really be returning -EFSCORRUPTED here,
- * but none of the higher level infrastructure supports
- * returning a specific error on buffer lookup failures.
- */
xfs_alert(btp->bt_mount,
"%s: daddr 0x%llx out of range, EOFS 0x%llx",
__func__, cmap.bm_bn, eofs);
WARN_ON(1);
- return NULL;
+ return -EFSCORRUPTED;
}
pag = xfs_perag_get(btp->bt_mount,
@@ -604,19 +615,20 @@ _xfs_buf_find(
}
/* No match found */
- if (new_bp) {
- /* the buffer keeps the perag reference until it is freed */
- new_bp->b_pag = pag;
- rhashtable_insert_fast(&pag->pag_buf_hash,
- &new_bp->b_rhash_head,
- xfs_buf_hash_params);
- spin_unlock(&pag->pag_buf_lock);
- } else {
+ if (!new_bp) {
XFS_STATS_INC(btp->bt_mount, xb_miss_locked);
spin_unlock(&pag->pag_buf_lock);
xfs_perag_put(pag);
+ return -ENOENT;
}
- return new_bp;
+
+ /* the buffer keeps the perag reference until it is freed */
+ new_bp->b_pag = pag;
+ rhashtable_insert_fast(&pag->pag_buf_hash, &new_bp->b_rhash_head,
+ xfs_buf_hash_params);
+ spin_unlock(&pag->pag_buf_lock);
+ *found_bp = new_bp;
+ return 0;
found:
spin_unlock(&pag->pag_buf_lock);
@@ -626,7 +638,7 @@ _xfs_buf_find(
if (flags & XBF_TRYLOCK) {
xfs_buf_rele(bp);
XFS_STATS_INC(btp->bt_mount, xb_busy_locked);
- return NULL;
+ return -EAGAIN;
}
xfs_buf_lock(bp);
XFS_STATS_INC(btp->bt_mount, xb_get_locked_waited);
@@ -646,7 +658,8 @@ _xfs_buf_find(
trace_xfs_buf_find(bp, flags, _RET_IP_);
XFS_STATS_INC(btp->bt_mount, xb_get_locked);
- return bp;
+ *found_bp = bp;
+ return 0;
}
struct xfs_buf *
@@ -656,8 +669,14 @@ xfs_incore(
size_t numblks,
xfs_buf_flags_t flags)
{
+ struct xfs_buf *bp;
+ int error;
DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
- return _xfs_buf_find(target, &map, 1, flags, NULL);
+
+ error = xfs_buf_find(target, &map, 1, flags, NULL, &bp);
+ if (error)
+ return NULL;
+ return bp;
}
/*
@@ -676,9 +695,27 @@ xfs_buf_get_map(
struct xfs_buf *new_bp;
int error = 0;
- bp = _xfs_buf_find(target, map, nmaps, flags, NULL);
- if (likely(bp))
+ error = xfs_buf_find(target, map, nmaps, flags, NULL, &bp);
+
+ switch (error) {
+ case 0:
+ /* cache hit */
goto found;
+ case -EAGAIN:
+ /* cache hit, trylock failure, caller handles failure */
+ ASSERT(flags & XBF_TRYLOCK);
+ return NULL;
+ case -ENOENT:
+ /* cache miss, go for insert */
+ break;
+ case -EFSCORRUPTED:
+ default:
+ /*
+ * None of the higher layers understand failure types
+ * yet, so return NULL to signal a fatal lookup error.
+ */
+ return NULL;
+ }
new_bp = _xfs_buf_alloc(target, map, nmaps, flags);
if (unlikely(!new_bp))
@@ -690,8 +727,8 @@ xfs_buf_get_map(
return NULL;
}
- bp = _xfs_buf_find(target, map, nmaps, flags, new_bp);
- if (!bp) {
+ error = xfs_buf_find(target, map, nmaps, flags, new_bp, &bp);
+ if (error) {
xfs_buf_free(new_bp);
return NULL;
}
--
2.16.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] xfs: make xfs_buf_incore out of line
2018-04-18 0:21 ` [PATCH 1/2] xfs: make xfs_buf_incore out of line Dave Chinner
@ 2018-04-18 10:29 ` Christoph Hellwig
2018-04-18 11:46 ` Carlos Maiolino
1 sibling, 0 replies; 11+ messages in thread
From: Christoph Hellwig @ 2018-04-18 10:29 UTC (permalink / raw)
To: Dave Chinner; +Cc: linux-xfs
On Wed, Apr 18, 2018 at 10:21:10AM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> Move xfs_buf_incore out of line and make it the only way to look up
> a buffer in the buffer cache from outside the buffer cache. Convert
> the external users of _xfs_buf_find() to xfs_buf_incore() and make
> _xfs_buf_find() static.
>
> Signed-Off-By: Dave Chinner <dchinner@redhat.com>
Looks good,
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] xfs: don't retry xfs_buf_find on XBF_TRYLOCK failure
2018-04-18 0:21 ` [PATCH 2/2] xfs: don't retry xfs_buf_find on XBF_TRYLOCK failure Dave Chinner
@ 2018-04-18 10:30 ` Christoph Hellwig
2018-04-18 11:53 ` Carlos Maiolino
2018-04-18 15:24 ` Darrick J. Wong
2 siblings, 0 replies; 11+ messages in thread
From: Christoph Hellwig @ 2018-04-18 10:30 UTC (permalink / raw)
To: Dave Chinner; +Cc: linux-xfs
Looks good,
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] xfs: make xfs_buf_incore out of line
2018-04-18 0:21 ` [PATCH 1/2] xfs: make xfs_buf_incore out of line Dave Chinner
2018-04-18 10:29 ` Christoph Hellwig
@ 2018-04-18 11:46 ` Carlos Maiolino
2018-04-18 15:24 ` Darrick J. Wong
1 sibling, 1 reply; 11+ messages in thread
From: Carlos Maiolino @ 2018-04-18 11:46 UTC (permalink / raw)
To: Dave Chinner; +Cc: linux-xfs
On Wed, Apr 18, 2018 at 10:21:10AM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> Move xfs_buf_incore out of line and make it the only way to look up
> a buffer in the buffer cache from outside the buffer cache. Convert
> the external users of _xfs_buf_find() to xfs_buf_incore() and make
> _xfs_buf_find() static.
>
Looks good, but shouldn't it be xfs_incore() instead of xfs_buf_incore() in the
Subject/description?
Otherwise
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
> Signed-Off-By: Dave Chinner <dchinner@redhat.com>
> ---
> fs/xfs/xfs_buf.c | 21 ++++++++++++++++-----
> fs/xfs/xfs_buf.h | 17 +++--------------
> fs/xfs/xfs_qm.c | 5 ++---
> 3 files changed, 21 insertions(+), 22 deletions(-)
>
> diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
> index 55661cbdb51b..2ca8e2c7fbc4 100644
> --- a/fs/xfs/xfs_buf.c
> +++ b/fs/xfs/xfs_buf.c
> @@ -549,17 +549,17 @@ xfs_buf_hash_destroy(
> }
>
> /*
> - * Look up, and creates if absent, a lockable buffer for
> - * a given range of an inode. The buffer is returned
> - * locked. No I/O is implied by this call.
> + * Look up (and insert if absent), a lockable buffer for a given
> + * range of an inode. The buffer is returned locked. No I/O is
> + * implied by this call.
> */
> -xfs_buf_t *
> +static struct xfs_buf *
> _xfs_buf_find(
> struct xfs_buftarg *btp,
> struct xfs_buf_map *map,
> int nmaps,
> xfs_buf_flags_t flags,
> - xfs_buf_t *new_bp)
> + struct xfs_buf *new_bp)
> {
> struct xfs_perag *pag;
> xfs_buf_t *bp;
> @@ -649,6 +649,17 @@ _xfs_buf_find(
> return bp;
> }
>
> +struct xfs_buf *
> +xfs_incore(
> + struct xfs_buftarg *target,
> + xfs_daddr_t blkno,
> + size_t numblks,
> + xfs_buf_flags_t flags)
> +{
> + DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
> + return _xfs_buf_find(target, &map, 1, flags, NULL);
> +}
> +
> /*
> * Assembles a buffer covering the specified range. The code is optimised for
> * cache hits, as metadata intensive workloads will see 3 orders of magnitude
> diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
> index edced162a674..e8947c1adac0 100644
> --- a/fs/xfs/xfs_buf.h
> +++ b/fs/xfs/xfs_buf.h
> @@ -218,20 +218,9 @@ typedef struct xfs_buf {
> } xfs_buf_t;
>
> /* Finding and Reading Buffers */
> -struct xfs_buf *_xfs_buf_find(struct xfs_buftarg *target,
> - struct xfs_buf_map *map, int nmaps,
> - xfs_buf_flags_t flags, struct xfs_buf *new_bp);
> -
> -static inline struct xfs_buf *
> -xfs_incore(
> - struct xfs_buftarg *target,
> - xfs_daddr_t blkno,
> - size_t numblks,
> - xfs_buf_flags_t flags)
> -{
> - DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
> - return _xfs_buf_find(target, &map, 1, flags, NULL);
> -}
> +struct xfs_buf *xfs_incore(struct xfs_buftarg *target,
> + xfs_daddr_t blkno, size_t numblks,
> + xfs_buf_flags_t flags);
>
> struct xfs_buf *_xfs_buf_alloc(struct xfs_buftarg *target,
> struct xfs_buf_map *map, int nmaps,
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index ec39ae274c78..aff4924f637f 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -1247,9 +1247,8 @@ xfs_qm_flush_one(
> */
> if (!xfs_dqflock_nowait(dqp)) {
> /* buf is pinned in-core by delwri list */
> - DEFINE_SINGLE_BUF_MAP(map, dqp->q_blkno,
> - mp->m_quotainfo->qi_dqchunklen);
> - bp = _xfs_buf_find(mp->m_ddev_targp, &map, 1, 0, NULL);
> + bp = xfs_incore(mp->m_ddev_targp, dqp->q_blkno,
> + mp->m_quotainfo->qi_dqchunklen, 0);
> if (!bp) {
> error = -EINVAL;
> goto out_unlock;
> --
> 2.16.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Carlos
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] xfs: don't retry xfs_buf_find on XBF_TRYLOCK failure
2018-04-18 0:21 ` [PATCH 2/2] xfs: don't retry xfs_buf_find on XBF_TRYLOCK failure Dave Chinner
2018-04-18 10:30 ` Christoph Hellwig
@ 2018-04-18 11:53 ` Carlos Maiolino
2018-04-18 15:24 ` Darrick J. Wong
2 siblings, 0 replies; 11+ messages in thread
From: Carlos Maiolino @ 2018-04-18 11:53 UTC (permalink / raw)
To: Dave Chinner; +Cc: linux-xfs
On Wed, Apr 18, 2018 at 10:21:11AM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> When looking at an event trace recently, I noticed that non-blocking
> buffer lookup attempts would fail on cached locked buffers and then
> run the slow cache-miss path. This means we are doing an xfs_buf
> allocation, lookup and free unnecessarily every time we avoid
> blocking on a locked buffer.
>
> Fix this by changing _xfs_buf_find() to return an error status to
> the caller to indicate that we failed the lock attempt rather than
> just returning a NULL. This allows the higher level code to
> discriminate between a cache miss and an cache hit that we failed to
> lock.
>
> This also allows us to return a -EFSCORRUPTED state if we are asked
> to look up a block number outside the range of the filesystem in
> _xfs_buf_find(), which moves us one step closer to being able to
> handle such errors in a more graceful manner at the higher levels.
>
> Signed-Off-By: Dave Chinner <dchinner@redhat.com>
Looks good
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
> ---
> fs/xfs/xfs_buf.c | 93 +++++++++++++++++++++++++++++++++++++++-----------------
> 1 file changed, 65 insertions(+), 28 deletions(-)
>
> diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
> index 2ca8e2c7fbc4..41b386c26582 100644
> --- a/fs/xfs/xfs_buf.c
> +++ b/fs/xfs/xfs_buf.c
> @@ -549,17 +549,31 @@ xfs_buf_hash_destroy(
> }
>
> /*
> - * Look up (and insert if absent), a lockable buffer for a given
> - * range of an inode. The buffer is returned locked. No I/O is
> - * implied by this call.
> + * Look up a buffer in the buffer cache and return it referenced and locked
> + * in @found_bp.
> + *
> + * If @new_bp is supplied and we have a lookup miss, insert @new_bp into the
> + * cache.
> + *
> + * If XBF_TRYLOCK is set in @flags, only try to lock the buffer and return
> + * -EAGAIN if we fail to lock it.
> + *
> + * Return values are:
> + * -EFSCORRUPTED if have been supplied with an invalid address
> + * -EAGAIN on trylock failure
> + * -ENOENT if we fail to find a match and @new_bp was NULL
> + * 0, with @found_bp:
> + * - @new_bp if we inserted it into the cache
> + * - the buffer we found and locked.
> */
> -static struct xfs_buf *
> -_xfs_buf_find(
> +static int
> +xfs_buf_find(
> struct xfs_buftarg *btp,
> struct xfs_buf_map *map,
> int nmaps,
> xfs_buf_flags_t flags,
> - struct xfs_buf *new_bp)
> + struct xfs_buf *new_bp,
> + struct xfs_buf **found_bp)
> {
> struct xfs_perag *pag;
> xfs_buf_t *bp;
> @@ -567,6 +581,8 @@ _xfs_buf_find(
> xfs_daddr_t eofs;
> int i;
>
> + *found_bp = NULL;
> +
> for (i = 0; i < nmaps; i++)
> cmap.bm_len += map[i].bm_len;
>
> @@ -580,16 +596,11 @@ _xfs_buf_find(
> */
> eofs = XFS_FSB_TO_BB(btp->bt_mount, btp->bt_mount->m_sb.sb_dblocks);
> if (cmap.bm_bn < 0 || cmap.bm_bn >= eofs) {
> - /*
> - * XXX (dgc): we should really be returning -EFSCORRUPTED here,
> - * but none of the higher level infrastructure supports
> - * returning a specific error on buffer lookup failures.
> - */
> xfs_alert(btp->bt_mount,
> "%s: daddr 0x%llx out of range, EOFS 0x%llx",
> __func__, cmap.bm_bn, eofs);
> WARN_ON(1);
> - return NULL;
> + return -EFSCORRUPTED;
> }
>
> pag = xfs_perag_get(btp->bt_mount,
> @@ -604,19 +615,20 @@ _xfs_buf_find(
> }
>
> /* No match found */
> - if (new_bp) {
> - /* the buffer keeps the perag reference until it is freed */
> - new_bp->b_pag = pag;
> - rhashtable_insert_fast(&pag->pag_buf_hash,
> - &new_bp->b_rhash_head,
> - xfs_buf_hash_params);
> - spin_unlock(&pag->pag_buf_lock);
> - } else {
> + if (!new_bp) {
> XFS_STATS_INC(btp->bt_mount, xb_miss_locked);
> spin_unlock(&pag->pag_buf_lock);
> xfs_perag_put(pag);
> + return -ENOENT;
> }
> - return new_bp;
> +
> + /* the buffer keeps the perag reference until it is freed */
> + new_bp->b_pag = pag;
> + rhashtable_insert_fast(&pag->pag_buf_hash, &new_bp->b_rhash_head,
> + xfs_buf_hash_params);
> + spin_unlock(&pag->pag_buf_lock);
> + *found_bp = new_bp;
> + return 0;
>
> found:
> spin_unlock(&pag->pag_buf_lock);
> @@ -626,7 +638,7 @@ _xfs_buf_find(
> if (flags & XBF_TRYLOCK) {
> xfs_buf_rele(bp);
> XFS_STATS_INC(btp->bt_mount, xb_busy_locked);
> - return NULL;
> + return -EAGAIN;
> }
> xfs_buf_lock(bp);
> XFS_STATS_INC(btp->bt_mount, xb_get_locked_waited);
> @@ -646,7 +658,8 @@ _xfs_buf_find(
>
> trace_xfs_buf_find(bp, flags, _RET_IP_);
> XFS_STATS_INC(btp->bt_mount, xb_get_locked);
> - return bp;
> + *found_bp = bp;
> + return 0;
> }
>
> struct xfs_buf *
> @@ -656,8 +669,14 @@ xfs_incore(
> size_t numblks,
> xfs_buf_flags_t flags)
> {
> + struct xfs_buf *bp;
> + int error;
> DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
> - return _xfs_buf_find(target, &map, 1, flags, NULL);
> +
> + error = xfs_buf_find(target, &map, 1, flags, NULL, &bp);
> + if (error)
> + return NULL;
> + return bp;
> }
>
> /*
> @@ -676,9 +695,27 @@ xfs_buf_get_map(
> struct xfs_buf *new_bp;
> int error = 0;
>
> - bp = _xfs_buf_find(target, map, nmaps, flags, NULL);
> - if (likely(bp))
> + error = xfs_buf_find(target, map, nmaps, flags, NULL, &bp);
> +
> + switch (error) {
> + case 0:
> + /* cache hit */
> goto found;
> + case -EAGAIN:
> + /* cache hit, trylock failure, caller handles failure */
> + ASSERT(flags & XBF_TRYLOCK);
> + return NULL;
> + case -ENOENT:
> + /* cache miss, go for insert */
> + break;
> + case -EFSCORRUPTED:
> + default:
> + /*
> + * None of the higher layers understand failure types
> + * yet, so return NULL to signal a fatal lookup error.
> + */
> + return NULL;
> + }
>
> new_bp = _xfs_buf_alloc(target, map, nmaps, flags);
> if (unlikely(!new_bp))
> @@ -690,8 +727,8 @@ xfs_buf_get_map(
> return NULL;
> }
>
> - bp = _xfs_buf_find(target, map, nmaps, flags, new_bp);
> - if (!bp) {
> + error = xfs_buf_find(target, map, nmaps, flags, new_bp, &bp);
> + if (error) {
> xfs_buf_free(new_bp);
> return NULL;
> }
> --
> 2.16.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Carlos
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] xfs: make xfs_buf_incore out of line
2018-04-18 11:46 ` Carlos Maiolino
@ 2018-04-18 15:24 ` Darrick J. Wong
2018-04-18 23:34 ` Dave Chinner
0 siblings, 1 reply; 11+ messages in thread
From: Darrick J. Wong @ 2018-04-18 15:24 UTC (permalink / raw)
To: Dave Chinner, linux-xfs
On Wed, Apr 18, 2018 at 01:46:58PM +0200, Carlos Maiolino wrote:
> On Wed, Apr 18, 2018 at 10:21:10AM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> >
> > Move xfs_buf_incore out of line and make it the only way to look up
> > a buffer in the buffer cache from outside the buffer cache. Convert
> > the external users of _xfs_buf_find() to xfs_buf_incore() and make
> > _xfs_buf_find() static.
> >
>
> Looks good, but shouldn't it be xfs_incore() instead of xfs_buf_incore() in the
> Subject/description?
I wonder if this function really should be named xfs_buf_incore because
xfs maintains a lot of incore state besides buffers, but as far as this
patch goes I'll fix the commit message on the way in.
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
--D
> Otherwise
>
> Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
>
>
> > Signed-Off-By: Dave Chinner <dchinner@redhat.com>
> > ---
> > fs/xfs/xfs_buf.c | 21 ++++++++++++++++-----
> > fs/xfs/xfs_buf.h | 17 +++--------------
> > fs/xfs/xfs_qm.c | 5 ++---
> > 3 files changed, 21 insertions(+), 22 deletions(-)
> >
> > diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
> > index 55661cbdb51b..2ca8e2c7fbc4 100644
> > --- a/fs/xfs/xfs_buf.c
> > +++ b/fs/xfs/xfs_buf.c
> > @@ -549,17 +549,17 @@ xfs_buf_hash_destroy(
> > }
> >
> > /*
> > - * Look up, and creates if absent, a lockable buffer for
> > - * a given range of an inode. The buffer is returned
> > - * locked. No I/O is implied by this call.
> > + * Look up (and insert if absent), a lockable buffer for a given
> > + * range of an inode. The buffer is returned locked. No I/O is
> > + * implied by this call.
> > */
> > -xfs_buf_t *
> > +static struct xfs_buf *
> > _xfs_buf_find(
> > struct xfs_buftarg *btp,
> > struct xfs_buf_map *map,
> > int nmaps,
> > xfs_buf_flags_t flags,
> > - xfs_buf_t *new_bp)
> > + struct xfs_buf *new_bp)
> > {
> > struct xfs_perag *pag;
> > xfs_buf_t *bp;
> > @@ -649,6 +649,17 @@ _xfs_buf_find(
> > return bp;
> > }
> >
> > +struct xfs_buf *
> > +xfs_incore(
> > + struct xfs_buftarg *target,
> > + xfs_daddr_t blkno,
> > + size_t numblks,
> > + xfs_buf_flags_t flags)
> > +{
> > + DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
> > + return _xfs_buf_find(target, &map, 1, flags, NULL);
> > +}
> > +
> > /*
> > * Assembles a buffer covering the specified range. The code is optimised for
> > * cache hits, as metadata intensive workloads will see 3 orders of magnitude
> > diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
> > index edced162a674..e8947c1adac0 100644
> > --- a/fs/xfs/xfs_buf.h
> > +++ b/fs/xfs/xfs_buf.h
> > @@ -218,20 +218,9 @@ typedef struct xfs_buf {
> > } xfs_buf_t;
> >
> > /* Finding and Reading Buffers */
> > -struct xfs_buf *_xfs_buf_find(struct xfs_buftarg *target,
> > - struct xfs_buf_map *map, int nmaps,
> > - xfs_buf_flags_t flags, struct xfs_buf *new_bp);
> > -
> > -static inline struct xfs_buf *
> > -xfs_incore(
> > - struct xfs_buftarg *target,
> > - xfs_daddr_t blkno,
> > - size_t numblks,
> > - xfs_buf_flags_t flags)
> > -{
> > - DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
> > - return _xfs_buf_find(target, &map, 1, flags, NULL);
> > -}
> > +struct xfs_buf *xfs_incore(struct xfs_buftarg *target,
> > + xfs_daddr_t blkno, size_t numblks,
> > + xfs_buf_flags_t flags);
> >
> > struct xfs_buf *_xfs_buf_alloc(struct xfs_buftarg *target,
> > struct xfs_buf_map *map, int nmaps,
> > diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> > index ec39ae274c78..aff4924f637f 100644
> > --- a/fs/xfs/xfs_qm.c
> > +++ b/fs/xfs/xfs_qm.c
> > @@ -1247,9 +1247,8 @@ xfs_qm_flush_one(
> > */
> > if (!xfs_dqflock_nowait(dqp)) {
> > /* buf is pinned in-core by delwri list */
> > - DEFINE_SINGLE_BUF_MAP(map, dqp->q_blkno,
> > - mp->m_quotainfo->qi_dqchunklen);
> > - bp = _xfs_buf_find(mp->m_ddev_targp, &map, 1, 0, NULL);
> > + bp = xfs_incore(mp->m_ddev_targp, dqp->q_blkno,
> > + mp->m_quotainfo->qi_dqchunklen, 0);
> > if (!bp) {
> > error = -EINVAL;
> > goto out_unlock;
> > --
> > 2.16.1
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
>
> --
> Carlos
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] xfs: don't retry xfs_buf_find on XBF_TRYLOCK failure
2018-04-18 0:21 ` [PATCH 2/2] xfs: don't retry xfs_buf_find on XBF_TRYLOCK failure Dave Chinner
2018-04-18 10:30 ` Christoph Hellwig
2018-04-18 11:53 ` Carlos Maiolino
@ 2018-04-18 15:24 ` Darrick J. Wong
2 siblings, 0 replies; 11+ messages in thread
From: Darrick J. Wong @ 2018-04-18 15:24 UTC (permalink / raw)
To: Dave Chinner; +Cc: linux-xfs
On Wed, Apr 18, 2018 at 10:21:11AM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> When looking at an event trace recently, I noticed that non-blocking
> buffer lookup attempts would fail on cached locked buffers and then
> run the slow cache-miss path. This means we are doing an xfs_buf
> allocation, lookup and free unnecessarily every time we avoid
> blocking on a locked buffer.
>
> Fix this by changing _xfs_buf_find() to return an error status to
> the caller to indicate that we failed the lock attempt rather than
> just returning a NULL. This allows the higher level code to
> discriminate between a cache miss and an cache hit that we failed to
> lock.
>
> This also allows us to return a -EFSCORRUPTED state if we are asked
> to look up a block number outside the range of the filesystem in
> _xfs_buf_find(), which moves us one step closer to being able to
> handle such errors in a more graceful manner at the higher levels.
>
> Signed-Off-By: Dave Chinner <dchinner@redhat.com>
Looks ok,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
--D
> ---
> fs/xfs/xfs_buf.c | 93 +++++++++++++++++++++++++++++++++++++++-----------------
> 1 file changed, 65 insertions(+), 28 deletions(-)
>
> diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
> index 2ca8e2c7fbc4..41b386c26582 100644
> --- a/fs/xfs/xfs_buf.c
> +++ b/fs/xfs/xfs_buf.c
> @@ -549,17 +549,31 @@ xfs_buf_hash_destroy(
> }
>
> /*
> - * Look up (and insert if absent), a lockable buffer for a given
> - * range of an inode. The buffer is returned locked. No I/O is
> - * implied by this call.
> + * Look up a buffer in the buffer cache and return it referenced and locked
> + * in @found_bp.
> + *
> + * If @new_bp is supplied and we have a lookup miss, insert @new_bp into the
> + * cache.
> + *
> + * If XBF_TRYLOCK is set in @flags, only try to lock the buffer and return
> + * -EAGAIN if we fail to lock it.
> + *
> + * Return values are:
> + * -EFSCORRUPTED if have been supplied with an invalid address
> + * -EAGAIN on trylock failure
> + * -ENOENT if we fail to find a match and @new_bp was NULL
> + * 0, with @found_bp:
> + * - @new_bp if we inserted it into the cache
> + * - the buffer we found and locked.
> */
> -static struct xfs_buf *
> -_xfs_buf_find(
> +static int
> +xfs_buf_find(
> struct xfs_buftarg *btp,
> struct xfs_buf_map *map,
> int nmaps,
> xfs_buf_flags_t flags,
> - struct xfs_buf *new_bp)
> + struct xfs_buf *new_bp,
> + struct xfs_buf **found_bp)
> {
> struct xfs_perag *pag;
> xfs_buf_t *bp;
> @@ -567,6 +581,8 @@ _xfs_buf_find(
> xfs_daddr_t eofs;
> int i;
>
> + *found_bp = NULL;
> +
> for (i = 0; i < nmaps; i++)
> cmap.bm_len += map[i].bm_len;
>
> @@ -580,16 +596,11 @@ _xfs_buf_find(
> */
> eofs = XFS_FSB_TO_BB(btp->bt_mount, btp->bt_mount->m_sb.sb_dblocks);
> if (cmap.bm_bn < 0 || cmap.bm_bn >= eofs) {
> - /*
> - * XXX (dgc): we should really be returning -EFSCORRUPTED here,
> - * but none of the higher level infrastructure supports
> - * returning a specific error on buffer lookup failures.
> - */
> xfs_alert(btp->bt_mount,
> "%s: daddr 0x%llx out of range, EOFS 0x%llx",
> __func__, cmap.bm_bn, eofs);
> WARN_ON(1);
> - return NULL;
> + return -EFSCORRUPTED;
> }
>
> pag = xfs_perag_get(btp->bt_mount,
> @@ -604,19 +615,20 @@ _xfs_buf_find(
> }
>
> /* No match found */
> - if (new_bp) {
> - /* the buffer keeps the perag reference until it is freed */
> - new_bp->b_pag = pag;
> - rhashtable_insert_fast(&pag->pag_buf_hash,
> - &new_bp->b_rhash_head,
> - xfs_buf_hash_params);
> - spin_unlock(&pag->pag_buf_lock);
> - } else {
> + if (!new_bp) {
> XFS_STATS_INC(btp->bt_mount, xb_miss_locked);
> spin_unlock(&pag->pag_buf_lock);
> xfs_perag_put(pag);
> + return -ENOENT;
> }
> - return new_bp;
> +
> + /* the buffer keeps the perag reference until it is freed */
> + new_bp->b_pag = pag;
> + rhashtable_insert_fast(&pag->pag_buf_hash, &new_bp->b_rhash_head,
> + xfs_buf_hash_params);
> + spin_unlock(&pag->pag_buf_lock);
> + *found_bp = new_bp;
> + return 0;
>
> found:
> spin_unlock(&pag->pag_buf_lock);
> @@ -626,7 +638,7 @@ _xfs_buf_find(
> if (flags & XBF_TRYLOCK) {
> xfs_buf_rele(bp);
> XFS_STATS_INC(btp->bt_mount, xb_busy_locked);
> - return NULL;
> + return -EAGAIN;
> }
> xfs_buf_lock(bp);
> XFS_STATS_INC(btp->bt_mount, xb_get_locked_waited);
> @@ -646,7 +658,8 @@ _xfs_buf_find(
>
> trace_xfs_buf_find(bp, flags, _RET_IP_);
> XFS_STATS_INC(btp->bt_mount, xb_get_locked);
> - return bp;
> + *found_bp = bp;
> + return 0;
> }
>
> struct xfs_buf *
> @@ -656,8 +669,14 @@ xfs_incore(
> size_t numblks,
> xfs_buf_flags_t flags)
> {
> + struct xfs_buf *bp;
> + int error;
> DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
> - return _xfs_buf_find(target, &map, 1, flags, NULL);
> +
> + error = xfs_buf_find(target, &map, 1, flags, NULL, &bp);
> + if (error)
> + return NULL;
> + return bp;
> }
>
> /*
> @@ -676,9 +695,27 @@ xfs_buf_get_map(
> struct xfs_buf *new_bp;
> int error = 0;
>
> - bp = _xfs_buf_find(target, map, nmaps, flags, NULL);
> - if (likely(bp))
> + error = xfs_buf_find(target, map, nmaps, flags, NULL, &bp);
> +
> + switch (error) {
> + case 0:
> + /* cache hit */
> goto found;
> + case -EAGAIN:
> + /* cache hit, trylock failure, caller handles failure */
> + ASSERT(flags & XBF_TRYLOCK);
> + return NULL;
> + case -ENOENT:
> + /* cache miss, go for insert */
> + break;
> + case -EFSCORRUPTED:
> + default:
> + /*
> + * None of the higher layers understand failure types
> + * yet, so return NULL to signal a fatal lookup error.
> + */
> + return NULL;
> + }
>
> new_bp = _xfs_buf_alloc(target, map, nmaps, flags);
> if (unlikely(!new_bp))
> @@ -690,8 +727,8 @@ xfs_buf_get_map(
> return NULL;
> }
>
> - bp = _xfs_buf_find(target, map, nmaps, flags, new_bp);
> - if (!bp) {
> + error = xfs_buf_find(target, map, nmaps, flags, new_bp, &bp);
> + if (error) {
> xfs_buf_free(new_bp);
> return NULL;
> }
> --
> 2.16.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] xfs: make xfs_buf_incore out of line
2018-04-18 15:24 ` Darrick J. Wong
@ 2018-04-18 23:34 ` Dave Chinner
2018-04-19 1:10 ` Darrick J. Wong
0 siblings, 1 reply; 11+ messages in thread
From: Dave Chinner @ 2018-04-18 23:34 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On Wed, Apr 18, 2018 at 08:24:42AM -0700, Darrick J. Wong wrote:
> On Wed, Apr 18, 2018 at 01:46:58PM +0200, Carlos Maiolino wrote:
> > On Wed, Apr 18, 2018 at 10:21:10AM +1000, Dave Chinner wrote:
> > > From: Dave Chinner <dchinner@redhat.com>
> > >
> > > Move xfs_buf_incore out of line and make it the only way to look up
> > > a buffer in the buffer cache from outside the buffer cache. Convert
> > > the external users of _xfs_buf_find() to xfs_buf_incore() and make
> > > _xfs_buf_find() static.
> > >
> >
> > Looks good, but shouldn't it be xfs_incore() instead of xfs_buf_incore() in the
> > Subject/description?
>
> I wonder if this function really should be named xfs_buf_incore because
> xfs maintains a lot of incore state besides buffers, but as far as this
> patch goes I'll fix the commit message on the way in.
I think I intended to rename it xfs_buf_incore() in this patch,
but got distracted between writing the commit message (I almost
always do that first) and then making the change. ANd so I forgot
to s/xfs_incore/xfs_buf_incore.
Do you want me to resend?
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] xfs: make xfs_buf_incore out of line
2018-04-18 23:34 ` Dave Chinner
@ 2018-04-19 1:10 ` Darrick J. Wong
0 siblings, 0 replies; 11+ messages in thread
From: Darrick J. Wong @ 2018-04-19 1:10 UTC (permalink / raw)
To: Dave Chinner; +Cc: linux-xfs
On Thu, Apr 19, 2018 at 09:34:19AM +1000, Dave Chinner wrote:
> On Wed, Apr 18, 2018 at 08:24:42AM -0700, Darrick J. Wong wrote:
> > On Wed, Apr 18, 2018 at 01:46:58PM +0200, Carlos Maiolino wrote:
> > > On Wed, Apr 18, 2018 at 10:21:10AM +1000, Dave Chinner wrote:
> > > > From: Dave Chinner <dchinner@redhat.com>
> > > >
> > > > Move xfs_buf_incore out of line and make it the only way to look up
> > > > a buffer in the buffer cache from outside the buffer cache. Convert
> > > > the external users of _xfs_buf_find() to xfs_buf_incore() and make
> > > > _xfs_buf_find() static.
> > > >
> > >
> > > Looks good, but shouldn't it be xfs_incore() instead of xfs_buf_incore() in the
> > > Subject/description?
> >
> > I wonder if this function really should be named xfs_buf_incore because
> > xfs maintains a lot of incore state besides buffers, but as far as this
> > patch goes I'll fix the commit message on the way in.
>
> I think I intended to rename it xfs_buf_incore() in this patch,
> but got distracted between writing the commit message (I almost
> always do that first) and then making the change. ANd so I forgot
> to s/xfs_incore/xfs_buf_incore.
>
> Do you want me to resend?
Nah, I'll just s/xfs_incore/xfs_buf_incore/ what I already have.
--D
> Cheers,
>
> Dave.
> --
> Dave Chinner
> david@fromorbit.com
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2018-04-19 1:10 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-18 0:21 [PATCH 0/2] xfs: optimise XBF_TRYLOCK buffer lookups Dave Chinner
2018-04-18 0:21 ` [PATCH 1/2] xfs: make xfs_buf_incore out of line Dave Chinner
2018-04-18 10:29 ` Christoph Hellwig
2018-04-18 11:46 ` Carlos Maiolino
2018-04-18 15:24 ` Darrick J. Wong
2018-04-18 23:34 ` Dave Chinner
2018-04-19 1:10 ` Darrick J. Wong
2018-04-18 0:21 ` [PATCH 2/2] xfs: don't retry xfs_buf_find on XBF_TRYLOCK failure Dave Chinner
2018-04-18 10:30 ` Christoph Hellwig
2018-04-18 11:53 ` Carlos Maiolino
2018-04-18 15:24 ` Darrick J. Wong
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.