Commit 1de09d1ae48152e56399aba0bfd984fb0ddae6b0

Authored by Dave Chinner
Committed by Ben Myers
1 parent 7d2ffe80aa

xfs: fix incorrect remote symlink block count

When CRCs are enabled, the number of blocks needed to hold a remote
symlink on a 1k block size filesystem may be 2 instead of 1. The
transaction reservation for the allocated blocks was not taking this
into account and only allocating one block. Hence when trying to
read or invalidate such symlinks, we are mapping a hole where there
should be a block and things go bad at that point.

Fix the reservation to use the correct block count, clean up the
block count calculation similar to the remote attribute calculation,
and add a debug guard to detect when we don't write the entire
symlink to disk.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Ben Myers <bpm@sgi.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Ben Myers <bpm@sgi.com>

(cherry picked from commit 321a95839e65db3759a07a3655184b0283af90fe)

Showing 1 changed file with 6 additions and 14 deletions Side-by-side Diff

fs/xfs/xfs_symlink.c
... ... @@ -56,16 +56,9 @@
56 56 struct xfs_mount *mp,
57 57 int pathlen)
58 58 {
59   - int fsblocks = 0;
60   - int len = pathlen;
  59 + int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
61 60  
62   - do {
63   - fsblocks++;
64   - len -= XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
65   - } while (len > 0);
66   -
67   - ASSERT(fsblocks <= XFS_SYMLINK_MAPS);
68   - return fsblocks;
  61 + return (pathlen + buflen - 1) / buflen;
69 62 }
70 63  
71 64 static int
... ... @@ -405,7 +398,7 @@
405 398 if (pathlen <= XFS_LITINO(mp, dp->i_d.di_version))
406 399 fs_blocks = 0;
407 400 else
408   - fs_blocks = XFS_B_TO_FSB(mp, pathlen);
  401 + fs_blocks = xfs_symlink_blocks(mp, pathlen);
409 402 resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
410 403 error = xfs_trans_reserve(tp, resblks, XFS_SYMLINK_LOG_RES(mp), 0,
411 404 XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT);
... ... @@ -512,7 +505,7 @@
512 505 cur_chunk = target_path;
513 506 offset = 0;
514 507 for (n = 0; n < nmaps; n++) {
515   - char *buf;
  508 + char *buf;
516 509  
517 510 d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
518 511 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
... ... @@ -525,9 +518,7 @@
525 518 bp->b_ops = &xfs_symlink_buf_ops;
526 519  
527 520 byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
528   - if (pathlen < byte_cnt) {
529   - byte_cnt = pathlen;
530   - }
  521 + byte_cnt = min(byte_cnt, pathlen);
531 522  
532 523 buf = bp->b_addr;
533 524 buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset,
... ... @@ -542,6 +533,7 @@
542 533 xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) -
543 534 (char *)bp->b_addr);
544 535 }
  536 + ASSERT(pathlen == 0);
545 537 }
546 538  
547 539 /*