summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-05-21 18:02:04 +1000
committerBen Myers <bpm@sgi.com>2013-05-30 17:26:08 -0500
commit58a72281555bf301f6dff24db2db205c87ef8db1 (patch)
tree08167ec47b27c14dcf71744557a0edaac73d2bdd
parent26f714450c3907ce07c41a0bd1bea40368e0b4da (diff)
downloadlinux-58a72281555bf301f6dff24db2db205c87ef8db1.tar.gz
linux-58a72281555bf301f6dff24db2db205c87ef8db1.tar.bz2
linux-58a72281555bf301f6dff24db2db205c87ef8db1.zip
xfs: correctly map remote attr buffers during removal
If we don't map the buffers correctly (same as for get/set operations) then the incore buffer lookup will fail. If a block number matches but a length is wrong, then debug kernels will ASSERT fail in _xfs_buf_find() due to the length mismatch. Ensure that we map the buffers correctly by basing the length of the buffer on the attribute data length rather than the remote block count. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Ben Myers <bpm@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com> (cherry picked from commit 6863ef8449f1908c19f43db572e4474f24a1e9da)
-rw-r--r--fs/xfs/xfs_attr_remote.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/fs/xfs/xfs_attr_remote.c b/fs/xfs/xfs_attr_remote.c
index e207bf0004b6..d8bcb2d742d1 100644
--- a/fs/xfs/xfs_attr_remote.c
+++ b/fs/xfs/xfs_attr_remote.c
@@ -468,19 +468,25 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
mp = args->dp->i_mount;
/*
- * Roll through the "value", invalidating the attribute value's
- * blocks.
+ * Roll through the "value", invalidating the attribute value's blocks.
+ * Note that args->rmtblkcnt is the minimum number of data blocks we'll
+ * see for a CRC enabled remote attribute. Each extent will have a
+ * header, and so we may have more blocks than we realise here. If we
+ * fail to map the blocks correctly, we'll have problems with the buffer
+ * lookups.
*/
lblkno = args->rmtblkno;
- valuelen = args->rmtblkcnt;
+ valuelen = args->valuelen;
+ blkcnt = xfs_attr3_rmt_blocks(mp, valuelen);
while (valuelen > 0) {
+ int dblkcnt;
+
/*
* Try to remember where we decided to put the value.
*/
nmap = 1;
error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
- args->rmtblkcnt, &map, &nmap,
- XFS_BMAPI_ATTRFORK);
+ blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
if (error)
return(error);
ASSERT(nmap == 1);
@@ -488,28 +494,31 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
(map.br_startblock != HOLESTARTBLOCK));
dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
- blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
+ dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
/*
* If the "remote" value is in the cache, remove it.
*/
- bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, XBF_TRYLOCK);
+ bp = xfs_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK);
if (bp) {
xfs_buf_stale(bp);
xfs_buf_relse(bp);
bp = NULL;
}
- valuelen -= map.br_blockcount;
+ valuelen -= XFS_ATTR3_RMT_BUF_SPACE(mp,
+ XFS_FSB_TO_B(mp, map.br_blockcount));
lblkno += map.br_blockcount;
+ blkcnt -= map.br_blockcount;
+ blkcnt = max(blkcnt, xfs_attr3_rmt_blocks(mp, valuelen));
}
/*
* Keep de-allocating extents until the remote-value region is gone.
*/
+ blkcnt = lblkno - args->rmtblkno;
lblkno = args->rmtblkno;
- blkcnt = args->rmtblkcnt;
done = 0;
while (!done) {
xfs_bmap_init(args->flist, args->firstblock);