[PATCH 7/7] xfs: implement block-metadata based data checksums

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a quick hack to demonstrate how data checksumming can be
implemented when it can be stored in the out of line metadata for each
logical block.  It builds on top of the previous PI infrastructure
and instead of generating/verifying protection information it simply
generates and verifies a crc32c checksum and stores it in the non-PI
metadata.  It misses a feature bit in the superblock, checking that
enough size is available in the metadata and many other things.

Signed-off-by: Christoph Hellwig <hch@xxxxxx>
---
 fs/xfs/xfs_data_csum.c | 79 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 76 insertions(+), 3 deletions(-)

diff --git a/fs/xfs/xfs_data_csum.c b/fs/xfs/xfs_data_csum.c
index d9d3620654b1..862388803398 100644
--- a/fs/xfs/xfs_data_csum.c
+++ b/fs/xfs/xfs_data_csum.c
@@ -14,6 +14,73 @@
 #include <linux/blk-integrity.h>
 #include <linux/bio-integrity.h>
 
+static inline void *xfs_csum_buf(struct bio *bio)
+{
+	return bvec_virt(bio_integrity(bio)->bip_vec);
+}
+
+static inline __le32
+xfs_data_csum(
+	void			*data,
+	unsigned int		len)
+{
+	return xfs_end_cksum(crc32c(XFS_CRC_SEED, data, len));
+}
+
+static void
+__xfs_data_csum_generate(
+	struct bio		*bio)
+{
+	unsigned int		ssize = bdev_logical_block_size(bio->bi_bdev);
+	__le32			*csum_buf = xfs_csum_buf(bio);
+	struct bvec_iter_all	iter;
+	struct bio_vec		*bv;
+	int			c = 0;
+
+	bio_for_each_segment_all(bv, bio, iter) {
+		void		*p;
+		unsigned int	off;
+
+		p = bvec_kmap_local(bv);
+		for (off = 0; off < bv->bv_len; off += ssize)
+			csum_buf[c++] = xfs_data_csum(p + off, ssize);
+		kunmap_local(p);
+	}
+}
+
+static int
+__xfs_data_csum_verify(
+	struct bio		*bio,
+	struct xfs_inode	*ip,
+	xfs_off_t		file_offset)
+{
+	unsigned int		ssize = bdev_logical_block_size(bio->bi_bdev);
+	__le32			*csum_buf = xfs_csum_buf(bio);
+	int			c = 0;
+	struct bvec_iter_all	iter;
+	struct bio_vec		*bv;
+
+	bio_for_each_segment_all(bv, bio, iter) {
+		void		*p;
+		unsigned int	off;
+
+		p = bvec_kmap_local(bv);
+		for (off = 0; off < bv->bv_len; off += ssize) {
+			if (xfs_data_csum(p + off, ssize) != csum_buf[c++]) {
+				kunmap_local(p);
+				xfs_warn(ip->i_mount,
+"checksum mismatch at inode 0x%llx offset %lld",
+					ip->i_ino, file_offset);
+				return -EFSBADCRC;
+			}
+			file_offset += ssize;
+		}
+		kunmap_local(p);
+	}
+
+	return 0;
+}
+
 void *
 xfs_data_csum_alloc(
 	struct bio		*bio)
@@ -53,11 +120,14 @@ xfs_data_csum_generate(
 {
 	struct blk_integrity	*bi = blk_get_integrity(bio->bi_bdev->bd_disk);
 
-	if (!bi || !bi->csum_type)
+	if (!bi)
 		return;
 
 	xfs_data_csum_alloc(bio);
-	blk_integrity_generate(bio);
+	if (!bi->csum_type)
+		__xfs_data_csum_generate(bio);
+	else
+		blk_integrity_generate(bio);
 }
 
 int
@@ -67,7 +137,10 @@ xfs_data_csum_verify(
 	struct bio		*bio = &ioend->io_bio;
 	struct blk_integrity	*bi = blk_get_integrity(bio->bi_bdev->bd_disk);
 
-	if (!bi || !bi->csum_type)
+	if (!bi)
 		return 0;
+	if (!bi->csum_type)
+		return __xfs_data_csum_verify(&ioend->io_bio,
+				XFS_I(ioend->io_inode), ioend->io_offset);
 	return blk_integrity_verify_all(bio, ioend->io_sector);
 }
-- 
2.45.2





[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux