aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-05-21 04:02:03 -0400
committerBen Myers <bpm@sgi.com>2013-05-30 18:25:58 -0400
commit26f714450c3907ce07c41a0bd1bea40368e0b4da (patch)
tree75fc5d6b3c66dcf43851b3160034b5bbf20147ab /fs
parent551b382f5368900d6d82983505cb52553c946a2b (diff)
xfs: remote attribute tail zeroing does too much
When an attribute data does not fill then entire remote block, we zero the remaining part of the buffer. This, however, needs to take into account that the buffer has a header, and so the offset where zeroing starts and the length of zeroing need to take this into account. Otherwise we end up with zeros over the end of the attribute value when CRCs are enabled. While there, make sure we only ask to map an extent that covers the remaining range of the attribute, rather than asking every time for the full length of remote data. If the remote attribute blocks are contiguous with other parts of the attribute tree, it will map those blocks as well and we can potentially zero them incorrectly. We can also get buffer size mistmatches when trying to read or remove the remote attribute, and this can lead to not finding the correct buffer when looking it up in cache. 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 4af3644c9a53eb2f1ecf69cc53576561b64be4c6)
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/xfs_attr_remote.c37
1 files changed, 18 insertions, 19 deletions
diff --git a/fs/xfs/xfs_attr_remote.c b/fs/xfs/xfs_attr_remote.c
index bcdc07c4e8f4..e207bf0004b6 100644
--- a/fs/xfs/xfs_attr_remote.c
+++ b/fs/xfs/xfs_attr_remote.c
@@ -296,10 +296,7 @@ xfs_attr_rmtval_set(
296 * and we may not need that many, so we have to handle this when 296 * and we may not need that many, so we have to handle this when
297 * allocating the blocks below. 297 * allocating the blocks below.
298 */ 298 */
299 if (!crcs) 299 blkcnt = xfs_attr3_rmt_blocks(mp, args->valuelen);
300 blkcnt = XFS_B_TO_FSB(mp, args->valuelen);
301 else
302 blkcnt = xfs_attr3_rmt_blocks(mp, args->valuelen);
303 300
304 error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, 301 error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
305 XFS_ATTR_FORK); 302 XFS_ATTR_FORK);
@@ -394,8 +391,11 @@ xfs_attr_rmtval_set(
394 */ 391 */
395 lblkno = args->rmtblkno; 392 lblkno = args->rmtblkno;
396 valuelen = args->valuelen; 393 valuelen = args->valuelen;
394 blkcnt = args->rmtblkcnt;
397 while (valuelen > 0) { 395 while (valuelen > 0) {
398 int byte_cnt; 396 int byte_cnt;
397 int hdr_size;
398 int dblkcnt;
399 char *buf; 399 char *buf;
400 400
401 /* 401 /*
@@ -404,7 +404,7 @@ xfs_attr_rmtval_set(
404 xfs_bmap_init(args->flist, args->firstblock); 404 xfs_bmap_init(args->flist, args->firstblock);
405 nmap = 1; 405 nmap = 1;
406 error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno, 406 error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
407 args->rmtblkcnt, &map, &nmap, 407 blkcnt, &map, &nmap,
408 XFS_BMAPI_ATTRFORK); 408 XFS_BMAPI_ATTRFORK);
409 if (error) 409 if (error)
410 return(error); 410 return(error);
@@ -413,26 +413,25 @@ xfs_attr_rmtval_set(
413 (map.br_startblock != HOLESTARTBLOCK)); 413 (map.br_startblock != HOLESTARTBLOCK));
414 414
415 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), 415 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
416 blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); 416 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
417 417
418 bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt, 0); 418 bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0);
419 if (!bp) 419 if (!bp)
420 return ENOMEM; 420 return ENOMEM;
421 bp->b_ops = &xfs_attr3_rmt_buf_ops; 421 bp->b_ops = &xfs_attr3_rmt_buf_ops;
422
423 byte_cnt = BBTOB(bp->b_length);
424 byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, byte_cnt);
425 if (valuelen < byte_cnt)
426 byte_cnt = valuelen;
427
428 buf = bp->b_addr; 422 buf = bp->b_addr;
429 buf += xfs_attr3_rmt_hdr_set(mp, dp->i_ino, offset, 423
424 byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, BBTOB(bp->b_length));
425 byte_cnt = min_t(int, valuelen, byte_cnt);
426 hdr_size = xfs_attr3_rmt_hdr_set(mp, dp->i_ino, offset,
430 byte_cnt, bp); 427 byte_cnt, bp);
431 memcpy(buf, src, byte_cnt); 428 ASSERT(hdr_size + byte_cnt <= BBTOB(bp->b_length));
432 429
433 if (byte_cnt < BBTOB(bp->b_length)) 430 memcpy(buf + hdr_size, src, byte_cnt);
434 xfs_buf_zero(bp, byte_cnt, 431
435 BBTOB(bp->b_length) - byte_cnt); 432 if (byte_cnt + hdr_size < BBTOB(bp->b_length))
433 xfs_buf_zero(bp, byte_cnt + hdr_size,
434 BBTOB(bp->b_length) - byte_cnt - hdr_size);
436 435
437 error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */ 436 error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
438 xfs_buf_relse(bp); 437 xfs_buf_relse(bp);
@@ -442,9 +441,9 @@ xfs_attr_rmtval_set(
442 src += byte_cnt; 441 src += byte_cnt;
443 valuelen -= byte_cnt; 442 valuelen -= byte_cnt;
444 offset += byte_cnt; 443 offset += byte_cnt;
445 hdrcnt--;
446 444
447 lblkno += map.br_blockcount; 445 lblkno += map.br_blockcount;
446 blkcnt -= map.br_blockcount;
448 } 447 }
449 ASSERT(valuelen == 0); 448 ASSERT(valuelen == 0);
450 return 0; 449 return 0;