提交 58a72281 编写于 作者: D Dave Chinner 提交者: Ben Myers

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: NDave Chinner <dchinner@redhat.com>
Reviewed-by: NBen Myers <bpm@sgi.com>
Signed-off-by: NBen Myers <bpm@sgi.com>

(cherry picked from commit 6863ef84)
上级 26f71445
...@@ -468,19 +468,25 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) ...@@ -468,19 +468,25 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
mp = args->dp->i_mount; mp = args->dp->i_mount;
/* /*
* Roll through the "value", invalidating the attribute value's * Roll through the "value", invalidating the attribute value's blocks.
* 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; lblkno = args->rmtblkno;
valuelen = args->rmtblkcnt; valuelen = args->valuelen;
blkcnt = xfs_attr3_rmt_blocks(mp, valuelen);
while (valuelen > 0) { while (valuelen > 0) {
int dblkcnt;
/* /*
* Try to remember where we decided to put the value. * Try to remember where we decided to put the value.
*/ */
nmap = 1; nmap = 1;
error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
args->rmtblkcnt, &map, &nmap, blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
XFS_BMAPI_ATTRFORK);
if (error) if (error)
return(error); return(error);
ASSERT(nmap == 1); ASSERT(nmap == 1);
...@@ -488,28 +494,31 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) ...@@ -488,28 +494,31 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
(map.br_startblock != HOLESTARTBLOCK)); (map.br_startblock != HOLESTARTBLOCK));
dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), 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. * 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) { if (bp) {
xfs_buf_stale(bp); xfs_buf_stale(bp);
xfs_buf_relse(bp); xfs_buf_relse(bp);
bp = NULL; 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; 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. * Keep de-allocating extents until the remote-value region is gone.
*/ */
blkcnt = lblkno - args->rmtblkno;
lblkno = args->rmtblkno; lblkno = args->rmtblkno;
blkcnt = args->rmtblkcnt;
done = 0; done = 0;
while (!done) { while (!done) {
xfs_bmap_init(args->flist, args->firstblock); xfs_bmap_init(args->flist, args->firstblock);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册