aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)
468 mp = args->dp->i_mount; 468 mp = args->dp->i_mount;
469 469
470 /* 470 /*
471 * Roll through the "value", invalidating the attribute value's 471 * Roll through the "value", invalidating the attribute value's blocks.
472 * blocks. 472 * Note that args->rmtblkcnt is the minimum number of data blocks we'll
473 * see for a CRC enabled remote attribute. Each extent will have a
474 * header, and so we may have more blocks than we realise here. If we
475 * fail to map the blocks correctly, we'll have problems with the buffer
476 * lookups.
473 */ 477 */
474 lblkno = args->rmtblkno; 478 lblkno = args->rmtblkno;
475 valuelen = args->rmtblkcnt; 479 valuelen = args->valuelen;
480 blkcnt = xfs_attr3_rmt_blocks(mp, valuelen);
476 while (valuelen > 0) { 481 while (valuelen > 0) {
482 int dblkcnt;
483
477 /* 484 /*
478 * Try to remember where we decided to put the value. 485 * Try to remember where we decided to put the value.
479 */ 486 */
480 nmap = 1; 487 nmap = 1;
481 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, 488 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
482 args->rmtblkcnt, &map, &nmap, 489 blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
483 XFS_BMAPI_ATTRFORK);
484 if (error) 490 if (error)
485 return(error); 491 return(error);
486 ASSERT(nmap == 1); 492 ASSERT(nmap == 1);
@@ -488,28 +494,31 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
488 (map.br_startblock != HOLESTARTBLOCK)); 494 (map.br_startblock != HOLESTARTBLOCK));
489 495
490 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), 496 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
491 blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); 497 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
492 498
493 /* 499 /*
494 * If the "remote" value is in the cache, remove it. 500 * If the "remote" value is in the cache, remove it.
495 */ 501 */
496 bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, XBF_TRYLOCK); 502 bp = xfs_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK);
497 if (bp) { 503 if (bp) {
498 xfs_buf_stale(bp); 504 xfs_buf_stale(bp);
499 xfs_buf_relse(bp); 505 xfs_buf_relse(bp);
500 bp = NULL; 506 bp = NULL;
501 } 507 }
502 508
503 valuelen -= map.br_blockcount; 509 valuelen -= XFS_ATTR3_RMT_BUF_SPACE(mp,
510 XFS_FSB_TO_B(mp, map.br_blockcount));
504 511
505 lblkno += map.br_blockcount; 512 lblkno += map.br_blockcount;
513 blkcnt -= map.br_blockcount;
514 blkcnt = max(blkcnt, xfs_attr3_rmt_blocks(mp, valuelen));
506 } 515 }
507 516
508 /* 517 /*
509 * Keep de-allocating extents until the remote-value region is gone. 518 * Keep de-allocating extents until the remote-value region is gone.
510 */ 519 */
520 blkcnt = lblkno - args->rmtblkno;
511 lblkno = args->rmtblkno; 521 lblkno = args->rmtblkno;
512 blkcnt = args->rmtblkcnt;
513 done = 0; 522 done = 0;
514 while (!done) { 523 while (!done) {
515 xfs_bmap_init(args->flist, args->firstblock); 524 xfs_bmap_init(args->flist, args->firstblock);