From: Lachlan McIlroy <lachlan@sgi.com>
To: Christoph Hellwig <hch@infradead.org>
Cc: xfs-dev <xfs-dev@sgi.com>, xfs-oss <xfs@oss.sgi.com>
Subject: Re: [PATCH] fix extent corruption in xfs_iext_irec_compact_full()
Date: Mon, 16 Jun 2008 13:18:46 +1000 [thread overview]
Message-ID: <4855DB96.9030208@sgi.com> (raw)
In-Reply-To: <20080613132304.GA28190@infradead.org>
Christoph Hellwig wrote:
> On Fri, Jun 13, 2008 at 05:22:25PM +1000, Lachlan McIlroy wrote:
>> This function is used to compact the indirect extent list by moving
>> extents from one page to the previous to fill them up. After we
>> move some extents to an earlier page we need to shuffle the remaining
>> extents to the start of the page. The actual bug here is the second
>> argument to memmove() needs to index past the extents, that were copied
>> to the previous page, and move the remaining extents. For pages that
>> are already full (ie ext_avail == 0) the compaction code has no net
>> effect so don't do it.
>>
>> Thanks to Dave Chinner for pointing out the bug.
>
>
> Looks good but this function needs a lot more comments. Below is a
> version of the patch with some more comments describing what's going
> on that I came up with when trying to understand what this patch does
> in detail:
Thanks Christoph.
>
>
> Index: linux-2.6-xfs/fs/xfs/xfs_inode.c
> ===================================================================
> --- linux-2.6-xfs.orig/fs/xfs/xfs_inode.c 2008-06-13 14:58:33.000000000 +0200
> +++ linux-2.6-xfs/fs/xfs/xfs_inode.c 2008-06-13 15:15:25.000000000 +0200
> @@ -4532,39 +4532,63 @@ xfs_iext_irec_compact_full(
> int nlists; /* number of irec's (ex lists) */
>
> ASSERT(ifp->if_flags & XFS_IFEXTIREC);
> +
> nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
> erp = ifp->if_u1.if_ext_irec;
> ep = &erp->er_extbuf[erp->er_extcount];
> erp_next = erp + 1;
> ep_next = erp_next->er_extbuf;
> +
> while (erp_idx < nlists - 1) {
> + /*
> + * Check how many extent records are available in this irec.
> + * If there is none skip the whole exercise.
> + */
> ext_avail = XFS_LINEAR_EXTS - erp->er_extcount;
> - ext_diff = MIN(ext_avail, erp_next->er_extcount);
> - memcpy(ep, ep_next, ext_diff * sizeof(xfs_bmbt_rec_t));
> - erp->er_extcount += ext_diff;
> - erp_next->er_extcount -= ext_diff;
> - /* Remove next page */
> - if (erp_next->er_extcount == 0) {
> + if (ext_avail) {
> +
> + /*
> + * Copy over as many as possible extent records into
> + * the previous page.
> + */
> + ext_diff = MIN(ext_avail, erp_next->er_extcount);
> + memcpy(ep, ep_next, ext_diff * sizeof(xfs_bmbt_rec_t));
> + erp->er_extcount += ext_diff;
> + erp_next->er_extcount -= ext_diff;
> +
> /*
> - * Free page before removing extent record
> - * so er_extoffs don't get modified in
> - * xfs_iext_irec_remove.
> + * If the next irec is empty now we can simply
> + * remove it.
> */
> - kmem_free(erp_next->er_extbuf);
> - erp_next->er_extbuf = NULL;
> - xfs_iext_irec_remove(ifp, erp_idx + 1);
> - erp = &ifp->if_u1.if_ext_irec[erp_idx];
> - nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
> - /* Update next page */
> - } else {
> - /* Move rest of page up to become next new page */
> - memmove(erp_next->er_extbuf, ep_next,
> - erp_next->er_extcount * sizeof(xfs_bmbt_rec_t));
> - ep_next = erp_next->er_extbuf;
> - memset(&ep_next[erp_next->er_extcount], 0,
> - (XFS_LINEAR_EXTS - erp_next->er_extcount) *
> - sizeof(xfs_bmbt_rec_t));
> + if (erp_next->er_extcount == 0) {
> + /*
> + * Free page before removing extent record
> + * so er_extoffs don't get modified in
> + * xfs_iext_irec_remove.
> + */
> + kmem_free(erp_next->er_extbuf);
> + erp_next->er_extbuf = NULL;
> + xfs_iext_irec_remove(ifp, erp_idx + 1);
> + erp = &ifp->if_u1.if_ext_irec[erp_idx];
> + nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
> +
> + /*
> + * If the next irec is not empty move up the content
> + * that has not been copied to the previous page to
> + * the beggining of this one.
> + */
> + } else {
> + memmove(erp_next->er_extbuf, &ep_next[ext_diff],
> + erp_next->er_extcount *
> + sizeof(xfs_bmbt_rec_t));
> + ep_next = erp_next->er_extbuf;
> + memset(&ep_next[erp_next->er_extcount], 0,
> + (XFS_LINEAR_EXTS -
> + erp_next->er_extcount) *
> + sizeof(xfs_bmbt_rec_t));
> + }
> }
> +
> if (erp->er_extcount == XFS_LINEAR_EXTS) {
> erp_idx++;
> if (erp_idx < nlists)
>
prev parent reply other threads:[~2008-06-16 3:14 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-06-13 7:22 [PATCH] fix extent corruption in xfs_iext_irec_compact_full() Lachlan McIlroy
2008-06-13 13:23 ` Christoph Hellwig
2008-06-16 3:18 ` Lachlan McIlroy [this message]
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=4855DB96.9030208@sgi.com \
--to=lachlan@sgi.com \
--cc=hch@infradead.org \
--cc=xfs-dev@sgi.com \
--cc=xfs@oss.sgi.com \
/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.