xfs
[Top] [All Lists]

[PATCH 10/14] xfs: remote attribute read too short

To: xfs@xxxxxxxxxxx
Subject: [PATCH 10/14] xfs: remote attribute read too short
From: Dave Chinner <david@xxxxxxxxxxxxx>
Date: Mon, 20 May 2013 09:51:17 +1000
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <1369007481-15185-1-git-send-email-david@xxxxxxxxxxxxx>
References: <1369007481-15185-1-git-send-email-david@xxxxxxxxxxxxx>
From: Dave Chinner <dchinner@xxxxxxxxxx>

Reading a maximally size remote attribute fails when CRCs are
enabled with this verification error:

XFS (vdb): remote attribute header does not match required off/len/owner)

There are two reasons for this, the first being that the
length of the buffer being read is determined from the
args->rmtblkcnt which doesn't take into account CRC headers. Hence
the mapped length ends up being too short and so we need to
calculate it directly from the value length.

The second is that the byte count of valid data within a buffer is
capped by the length of the data and so doesn't take into account
that the buffer might be longer due to headers. Hence we need to
calculate the data space in the buffer first before calculating the
actual byte count of data.

Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx>
---
 fs/xfs/xfs_attr_remote.c |   15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/fs/xfs/xfs_attr_remote.c b/fs/xfs/xfs_attr_remote.c
index aad95b0..bcdc07c 100644
--- a/fs/xfs/xfs_attr_remote.c
+++ b/fs/xfs/xfs_attr_remote.c
@@ -52,9 +52,11 @@ xfs_attr3_rmt_blocks(
        struct xfs_mount *mp,
        int             attrlen)
 {
-       int             buflen = XFS_ATTR3_RMT_BUF_SPACE(mp,
-                                                        mp->m_sb.sb_blocksize);
-       return (attrlen + buflen - 1) / buflen;
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
+               return (attrlen + buflen - 1) / buflen;
+       }
+       return XFS_B_TO_FSB(mp, attrlen);
 }
 
 static bool
@@ -206,8 +208,9 @@ xfs_attr_rmtval_get(
 
        while (valuelen > 0) {
                nmap = ATTR_RMTVALUE_MAPSIZE;
+               blkcnt = xfs_attr3_rmt_blocks(mp, valuelen);
                error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
-                                      args->rmtblkcnt, map, &nmap,
+                                      blkcnt, map, &nmap,
                                       XFS_BMAPI_ATTRFORK);
                if (error)
                        return error;
@@ -227,8 +230,8 @@ xfs_attr_rmtval_get(
                        if (error)
                                return error;
 
-                       byte_cnt = min_t(int, valuelen, BBTOB(bp->b_length));
-                       byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, byte_cnt);
+                       byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, 
BBTOB(bp->b_length));
+                       byte_cnt = min_t(int, valuelen, byte_cnt);
 
                        src = bp->b_addr;
                        if (xfs_sb_version_hascrc(&mp->m_sb)) {
-- 
1.7.10.4

<Prev in Thread] Current Thread [Next in Thread>