--- 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);