Commit 321a9583 authored by Dave Chinner's avatar Dave Chinner Committed by Ben Myers

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: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarBen Myers <bpm@sgi.com>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent 34510185
...@@ -56,16 +56,9 @@ xfs_symlink_blocks( ...@@ -56,16 +56,9 @@ xfs_symlink_blocks(
struct xfs_mount *mp, struct xfs_mount *mp,
int pathlen) int pathlen)
{ {
int fsblocks = 0; int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
int len = pathlen;
do { return (pathlen + buflen - 1) / buflen;
fsblocks++;
len -= XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
} while (len > 0);
ASSERT(fsblocks <= XFS_SYMLINK_MAPS);
return fsblocks;
} }
static int static int
...@@ -405,7 +398,7 @@ xfs_symlink( ...@@ -405,7 +398,7 @@ xfs_symlink(
if (pathlen <= XFS_LITINO(mp, dp->i_d.di_version)) if (pathlen <= XFS_LITINO(mp, dp->i_d.di_version))
fs_blocks = 0; fs_blocks = 0;
else else
fs_blocks = XFS_B_TO_FSB(mp, pathlen); fs_blocks = xfs_symlink_blocks(mp, pathlen);
resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks); resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
error = xfs_trans_reserve(tp, resblks, XFS_SYMLINK_LOG_RES(mp), 0, error = xfs_trans_reserve(tp, resblks, XFS_SYMLINK_LOG_RES(mp), 0,
XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT); XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT);
...@@ -512,7 +505,7 @@ xfs_symlink( ...@@ -512,7 +505,7 @@ xfs_symlink(
cur_chunk = target_path; cur_chunk = target_path;
offset = 0; offset = 0;
for (n = 0; n < nmaps; n++) { for (n = 0; n < nmaps; n++) {
char *buf; char *buf;
d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
...@@ -525,9 +518,7 @@ xfs_symlink( ...@@ -525,9 +518,7 @@ xfs_symlink(
bp->b_ops = &xfs_symlink_buf_ops; bp->b_ops = &xfs_symlink_buf_ops;
byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt); byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
if (pathlen < byte_cnt) { byte_cnt = min(byte_cnt, pathlen);
byte_cnt = pathlen;
}
buf = bp->b_addr; buf = bp->b_addr;
buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset, buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset,
...@@ -542,6 +533,7 @@ xfs_symlink( ...@@ -542,6 +533,7 @@ xfs_symlink(
xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) - xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) -
(char *)bp->b_addr); (char *)bp->b_addr);
} }
ASSERT(pathlen == 0);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment