[PATCH 47/48] xfs_repair: support CRC enabled remote symlinks
Dave Chinner
david at fromorbit.com
Thu Jun 6 19:26:10 CDT 2013
From: Dave Chinner <dchinner at redhat.com>
Add support for verifying the contents of remote symlinks with CRCs.
Factor the remote symlink checking code out of the symlink function
so that it is clear what it is checking. This also reduces the
indentation and makes the code clearer.
Then add support for the CRC format by modelling the checking
function directly on the code that is used in the kernel for reading
and checking both remote symlink formats.
Signed-off-by: Dave Chinner <dchinner at redhat.com>
---
libxfs/xfs_symlink.c | 11 +----
repair/dinode.c | 132 ++++++++++++++++++++++++++++++++------------------
2 files changed, 88 insertions(+), 55 deletions(-)
diff --git a/libxfs/xfs_symlink.c b/libxfs/xfs_symlink.c
index a3da965..860b123 100644
--- a/libxfs/xfs_symlink.c
+++ b/libxfs/xfs_symlink.c
@@ -14,16 +14,9 @@ xfs_symlink_blocks(
struct xfs_mount *mp,
int pathlen)
{
- int fsblocks = 0;
- int len = pathlen;
+ int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
- do {
- fsblocks++;
- len -= XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
- } while (len > 0);
-
- ASSERT(fsblocks <= XFS_SYMLINK_MAPS);
- return fsblocks;
+ return (pathlen + buflen - 1) / buflen;
}
/*
diff --git a/repair/dinode.c b/repair/dinode.c
index 31a26d7..b0f1396 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -1449,6 +1449,86 @@ null_check(char *name, int length)
return(0);
}
+static int
+process_symlink_remote(
+ struct xfs_mount *mp,
+ xfs_ino_t lino,
+ struct xfs_dinode *dino,
+ struct blkmap *blkmap,
+ char *dst)
+{
+ xfs_dfsbno_t fsbno;
+ struct xfs_buf *bp;
+ char *src;
+ int pathlen;
+ int offset;
+ int i;
+
+ offset = 0;
+ pathlen = be64_to_cpu(dino->di_size);
+ i = 0;
+
+ while (pathlen > 0) {
+ int blk_cnt = 1;
+ int byte_cnt;
+
+ fsbno = blkmap_get(blkmap, i);
+ if (fsbno == NULLDFSBNO) {
+ do_warn(
+_("cannot read inode %" PRIu64 ", file block %d, NULL disk block\n"),
+ lino, i);
+ return 1;
+ }
+
+ /*
+ * There's a symlink header for each contiguous extent. If
+ * there are contiguous blocks, read them in one go.
+ */
+ while (blk_cnt <= max_symlink_blocks) {
+ if (blkmap_get(blkmap, i + 1) != fsbno + 1)
+ break;
+ blk_cnt++;
+ i++;
+ }
+
+ byte_cnt = XFS_FSB_TO_B(mp, blk_cnt);
+
+ bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
+ BTOBB(byte_cnt), 0, &xfs_symlink_buf_ops);
+ if (!bp) {
+ do_warn(
+_("cannot read inode %" PRIu64 ", file block %d, disk block %" PRIu64 "\n"),
+ lino, i, fsbno);
+ return 1;
+ }
+
+ byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
+ byte_cnt = MIN(pathlen, byte_cnt);
+
+ src = bp->b_addr;
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
+ if (!libxfs_symlink_hdr_ok(mp, lino, offset,
+ byte_cnt, bp)) {
+ do_warn(
+_("bad symlink header ino %" PRIu64 ", file block %d, disk block %" PRIu64 "\n"),
+ lino, i, fsbno);
+ libxfs_putbuf(bp);
+ return 1;
+ }
+ src += sizeof(struct xfs_dsymlink_hdr);
+ }
+
+ memmove(dst + offset, src, byte_cnt);
+
+ pathlen -= byte_cnt;
+ offset += byte_cnt;
+ i++;
+
+ libxfs_putbuf(bp);
+ }
+ return 0;
+}
+
/*
* like usual, returns 0 if everything's ok and 1 if something's
* bogus
@@ -1460,10 +1540,7 @@ process_symlink(
xfs_dinode_t *dino,
blkmap_t *blkmap)
{
- xfs_dfsbno_t fsbno;
- xfs_buf_t *bp = NULL;
- char *symlink, *cptr, *buf_data;
- int i, size, amountdone;
+ char *symlink, *cptr;
char data[MAXPATHLEN];
/*
@@ -1491,50 +1568,13 @@ process_symlink(
memmove(symlink, XFS_DFORK_DPTR(dino),
be64_to_cpu(dino->di_size));
} else {
- /*
- * stored in a meta-data file, have to bmap one block
- * at a time and copy the symlink into the data area
- */
- i = size = amountdone = 0;
- cptr = symlink;
-
- while (amountdone < be64_to_cpu(dino->di_size)) {
- fsbno = blkmap_get(blkmap, i);
- if (fsbno != NULLDFSBNO)
- bp = libxfs_readbuf(mp->m_dev,
- XFS_FSB_TO_DADDR(mp, fsbno),
- XFS_FSB_TO_BB(mp, 1), 0,
- &xfs_symlink_buf_ops);
- if (!bp || fsbno == NULLDFSBNO) {
- do_warn(
-_("cannot read inode %" PRIu64 ", file block %d, disk block %" PRIu64 "\n"),
- lino, i, fsbno);
- return(1);
- }
-
+ int error;
- buf_data = (char *)XFS_BUF_PTR(bp);
- size = MIN(be64_to_cpu(dino->di_size) - amountdone,
- XFS_SYMLINK_BUF_SPACE(mp,
- mp->m_sb.sb_blocksize));
- if (xfs_sb_version_hascrc(&mp->m_sb)) {
- if (!libxfs_symlink_hdr_ok(mp, lino, amountdone,
- size, bp)) {
- do_warn(
-_("bad symlink header ino %" PRIu64 ", file block %d, disk block %" PRIu64 "\n"),
- lino, i, fsbno);
- libxfs_putbuf(bp);
- return(1);
- }
- buf_data += sizeof(struct xfs_dsymlink_hdr);
- }
- memmove(cptr, buf_data, size);
- cptr += size;
- amountdone += size;
- i++;
- libxfs_putbuf(bp);
- }
+ error = process_symlink_remote(mp, lino, dino, blkmap, symlink);
+ if (error)
+ return error;
}
+
data[be64_to_cpu(dino->di_size)] = '\0';
/*
--
1.7.10.4
More information about the xfs
mailing list