usr/src/uts/common/fs/zfs/zio.c
changeset 13150 4d89e6c6d8c8
parent 5450 b25030891c44
child 13152 b2ac0409282f
--- a/usr/src/uts/common/fs/zfs/zio.c	Mon Nov 19 02:30:45 2007 -0800
+++ b/usr/src/uts/common/fs/zfs/zio.c	Tue Nov 20 16:43:41 2007 +0000
@@ -33,8 +33,11 @@
 #include <sys/vdev_impl.h>
 #include <sys/zio_impl.h>
 #include <sys/zio_compress.h>
+#include <sys/zio_crypt.h>
 #include <sys/zio_checksum.h>
 
+#include <sys/sdt.h>
+
 /*
  * ==========================================================================
  * I/O priority table
@@ -495,8 +498,8 @@
 }
 
 zio_t *
-zio_write(zio_t *pio, spa_t *spa, int checksum, int compress, int ncopies,
-    uint64_t txg, blkptr_t *bp, void *data, uint64_t size,
+zio_write(zio_t *pio, spa_t *spa, int checksum, int compress, int crypt,
+    int ncopies, uint64_t txg, blkptr_t *bp, void *data, uint64_t size,
     zio_done_func_t *ready, zio_done_func_t *done, void *private, int priority,
     int flags, zbookmark_t *zb)
 {
@@ -508,6 +511,9 @@
 	ASSERT(compress >= ZIO_COMPRESS_OFF &&
 	    compress < ZIO_COMPRESS_FUNCTIONS);
 
+	ASSERT(crypt >= ZIO_CRYPT_OFF &&
+	    crypt < ZIO_CRYPT_FUNCTIONS);
+
 	ZIO_ENTER(spa);
 
 	zio = zio_create(pio, spa, txg, bp, data, size, done, private,
@@ -523,15 +529,21 @@
 	zio->io_checksum = checksum;
 	zio->io_compress = compress;
 	zio->io_ndvas = ncopies;
+	zio->io_crypt = crypt;
 
 	if (compress != ZIO_COMPRESS_OFF)
 		zio->io_async_stages |= 1U << ZIO_STAGE_WRITE_COMPRESS;
 
+	if (crypt != ZIO_CRYPT_OFF) {
+		zio->io_async_stages |= 1U << ZIO_STAGE_WRITE_ENCRYPT;
+	}
+
 	if (bp->blk_birth != txg) {
 		/* XXX the bp usually (always?) gets re-zeroed later */
 		BP_ZERO(bp);
 		BP_SET_LSIZE(bp, size);
 		BP_SET_PSIZE(bp, size);
+		BP_SET_CRYPT(bp, ZIO_CRYPT_OFF); /* XXX why not crypt ? */
 	} else {
 		/* Make sure someone doesn't change their mind on overwrites */
 		ASSERT(MIN(zio->io_ndvas + BP_IS_GANG(bp),
@@ -542,8 +554,8 @@
 }
 
 zio_t *
-zio_rewrite(zio_t *pio, spa_t *spa, int checksum,
-    uint64_t txg, blkptr_t *bp, void *data, uint64_t size,
+zio_rewrite(zio_t *pio, spa_t *spa, int checksum, uint64_t txg,
+    blkptr_t *bp, void *data, uint64_t size,
     zio_done_func_t *done, void *private, int priority, int flags,
     zbookmark_t *zb)
 {
@@ -556,6 +568,7 @@
 	zio->io_bookmark = *zb;
 	zio->io_checksum = checksum;
 	zio->io_compress = ZIO_COMPRESS_OFF;
+	zio->io_crypt = ZIO_CRYPT_OFF;
 
 	if (pio != NULL)
 		ASSERT3U(zio->io_ndvas, <=, BP_GET_NDVAS(bp));
@@ -574,8 +587,8 @@
 }
 
 static zio_t *
-zio_write_allocate(zio_t *pio, spa_t *spa, int checksum,
-    uint64_t txg, blkptr_t *bp, void *data, uint64_t size,
+zio_write_allocate(zio_t *pio, spa_t *spa, int checksum, uint64_t txg,
+    blkptr_t *bp, void *data, uint64_t size,
     zio_done_func_t *done, void *private, int priority, int flags)
 {
 	zio_t *zio;
@@ -584,6 +597,7 @@
 	BP_SET_LSIZE(bp, size);
 	BP_SET_PSIZE(bp, size);
 	BP_SET_COMPRESS(bp, ZIO_COMPRESS_OFF);
+	BP_SET_CRYPT(bp, ZIO_CRYPT_OFF);
 
 	zio = zio_create(pio, spa, txg, bp, data, size, done, private,
 	    ZIO_TYPE_WRITE, priority, flags,
@@ -591,6 +605,7 @@
 
 	zio->io_checksum = checksum;
 	zio->io_compress = ZIO_COMPRESS_OFF;
+	zio->io_crypt = ZIO_CRYPT_OFF;	
 	zio->io_ready = zio_write_allocate_ready;
 
 	return (zio);
@@ -698,6 +713,7 @@
 
 	BP_SET_CHECKSUM(bp, checksum);
 	BP_SET_COMPRESS(bp, ZIO_COMPRESS_OFF);
+	BP_SET_CRYPT(bp, ZIO_CRYPT_OFF);
 	BP_SET_BYTEORDER(bp, ZFS_HOST_BYTEORDER);
 
 	if (checksum != ZIO_CHECKSUM_OFF)
@@ -1084,7 +1100,6 @@
 	if (bp != NULL) {
 		ASSERT(bp->blk_pad[0] == 0);
 		ASSERT(bp->blk_pad[1] == 0);
-		ASSERT(bp->blk_pad[2] == 0);
 		ASSERT(bcmp(bp, &zio->io_bp_copy, sizeof (blkptr_t)) == 0);
 		if (zio->io_type == ZIO_TYPE_WRITE && !BP_IS_HOLE(bp) &&
 		    !(zio->io_flags & ZIO_FLAG_IO_REPAIR)) {
@@ -1316,6 +1331,15 @@
 		}
 	}
 
+	/*
+	 * XXX this really really shouldn't need to be here but it
+	 * seems like it might because of how special this function
+	 * really is
+	 */
+	if (zio->io_crypt != ZIO_CRYPT_OFF) {
+		zio->io_pipeline |= 1U << ZIO_STAGE_WRITE_ENCRYPT;
+		zio->io_async_stages |= 1U << ZIO_STAGE_WRITE_ENCRYPT;
+	}
 	zio_next_stage(zio);
 }
 
@@ -1341,6 +1365,129 @@
 	zio_next_stage(zio);
 }
 
+
+/*
+ * ==========================================================================
+ * Cryptographic support
+ * ==========================================================================
+ */
+
+static void
+zio_write_encrypt(zio_t *zio)
+{
+	int crypt = zio->io_crypt;
+	int crypt_error;
+	blkptr_t *bp = zio->io_bp;
+	void *cbuf;
+	uint64_t csize = zio->io_size;
+	uint64_t cbufsize = 0;
+
+	ASSERT3U(spa_version(zio->io_spa), >=, SPA_VERSION_CRYPTO);
+	
+	/*
+	 * ZIO_STAGE_WRITE_ENCRYPT is in several pipelines because
+	 * zio_write_compress() messes with zio->io_pipeline, so we
+	 * could be getting called even when we have nothing to do,
+	 * in that case just go to the next stage.
+	 *
+	 * XXX darrenm
+	 *
+	 * ZIO_CRYPT_INHERIT appears on disk for the root block,
+	 * we should probably check that is the only case.
+	 */
+	if (crypt == ZIO_CRYPT_OFF || crypt == ZIO_CRYPT_INHERIT) {
+#ifdef DEBUG
+		cmn_err(CE_NOTE, "zio_write_encrypt: called with crypt = %s",
+		    ZIO_CRYPT_OFF ? "ZIO_CRYPT_OFF" : "ZIO_CRYPT_INHERIT");
+#endif
+		zio_next_stage(zio);
+	}
+
+	/*
+	 * We pass in the zbookmark_t so we can lookup which key
+	 * is needed.  The io_txg is used by some mechansims as input
+	 * into the IV generation routine.
+	 */
+	crypt_error = zio_encrypt_data(crypt, zio->io_spa, zio->io_bookmark,
+	    zio->io_txg, zio->io_data, zio->io_size, &cbuf, &csize, &cbufsize);
+
+	/*
+	 * XXX may need more failure cases.
+	 * One possible failure is not having access to the
+	 * key material that the zboookmark_t says we needed,
+	 * In that case we got EACCESS so post an FMA event, we do this
+	 * here so that we don't need to pass the full zio downwards into
+	 * the crypto functions.
+	 */ 
+	switch (crypt_error) {
+	case 0:
+		zio_push_transform(zio, cbuf, csize, cbufsize);
+		ASSERT3U(csize, ==, zio->io_size);
+		BP_SET_CRYPT(zio->io_bp, crypt);
+		BP_SET_PSIZE(bp, csize);
+		break;
+	case EACCES:
+		zfs_ereport_post(FM_EREPORT_ZFS_CRYPTO_KEY_UNAVAIL,
+		    zio->io_spa, zio->io_vd, zio, 0, 0);
+	default:
+		zio->io_error = crypt_error;
+	}
+
+	zio_next_stage(zio);
+}
+
+static void
+zio_read_decrypt(zio_t *zio)
+{
+	blkptr_t *bp = zio->io_bp;
+	int crypt = BP_GET_CRYPT(bp);
+	void *data;
+	uint64_t size;
+	uint64_t bufsize;
+	int crypt_error;
+
+	ASSERT3U(spa_version(zio->io_spa), >=, SPA_VERSION_CRYPTO);
+
+	/*
+	 * XXX darrenm
+	 *
+	 * ZIO_CRYPT_INHERIT appears on disk for the root block,
+	 * we should probably check that is the only case.
+	 */
+	if (crypt == ZIO_CRYPT_OFF || crypt == ZIO_CRYPT_INHERIT) {
+#ifdef DEBUG
+		cmn_err(CE_NOTE,
+		    "zio_read_decrypt: called with crypt = %s",
+		    ZIO_CRYPT_OFF ? "ZIO_CRYPT_OFF" : "ZIO_CRYPT_INHERIT");
+#endif
+		zio_next_stage(zio);
+	}
+	
+	zio_pop_transform(zio, &data, &size, &bufsize);
+
+	crypt_error = zio_decrypt_data(crypt, zio->io_spa, zio->io_bookmark, 
+	    bp->blk_birth, data, size, zio->io_data, zio->io_size);
+
+	/*
+	 * XXX may need more failure cases.
+	 * One possible failure is not having access to the
+	 * key material that the zboookmark_t says we needed,
+	 * In that case we got EACCESS so post an FMA event, we do this
+	 * here so that we don't need to pass the full zio downwards into
+	 * the crypto functions.
+	 */ 
+	switch (crypt_error) {
+	case EACCES:
+		zfs_ereport_post(FM_EREPORT_ZFS_CRYPTO_KEY_UNAVAIL,
+		    zio->io_spa, zio->io_vd, zio, 0, 0);
+	default:
+		zio->io_error = crypt_error;
+	}
+
+	zio_buf_free(data, bufsize);
+	zio_next_stage(zio);
+}
+
 /*
  * ==========================================================================
  * Gang block support
@@ -1961,6 +2108,7 @@
 	zio_badop,
 	zio_wait_children_ready,
 	zio_write_compress,
+	zio_write_encrypt,
 	zio_checksum_generate,
 	zio_gang_pipeline,
 	zio_get_gang_header,
@@ -1979,6 +2127,7 @@
 	zio_wait_children_done,
 	zio_checksum_verify,
 	zio_read_gang_members,
+	zio_read_decrypt,
 	zio_read_decompress,
 	zio_assess,
 	zio_done,
@@ -2122,6 +2271,7 @@
 		BP_SET_PSIZE(new_bp, size);
 		BP_SET_COMPRESS(new_bp, ZIO_COMPRESS_OFF);
 		BP_SET_CHECKSUM(new_bp, ZIO_CHECKSUM_ZILOG);
+		BP_SET_CRYPT(new_bp, ZIO_CRYPT_OFF); /* XXX darrenm ZIL crypto */
 		BP_SET_TYPE(new_bp, DMU_OT_INTENT_LOG);
 		BP_SET_LEVEL(new_bp, 0);
 		BP_SET_BYTEORDER(new_bp, ZFS_HOST_BYTEORDER);