Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 687

kernel-2.6.18-238.el5.src.rpm

Date: Thu, 21 Sep 2006 16:50:01 +0100
From: Alasdair G Kergon <agk@redhat.com>
Subject: [RHEL5 PATCH 22/30] dm table: add target preresume

This patch adds a target preresume hook.

It is called before the targets are resumed and if it returns
an error the resume gets cancelled.

The crypt target will use this to indicate that it is
unable to process I/O because no encryption key has been supplied.

Index: linux-2.6.18.noarch/include/linux/device-mapper.h
===================================================================
--- linux-2.6.18.noarch.orig/include/linux/device-mapper.h
+++ linux-2.6.18.noarch/include/linux/device-mapper.h
@@ -57,6 +57,7 @@ typedef int (*dm_endio_fn) (struct dm_ta
 
 typedef void (*dm_presuspend_fn) (struct dm_target *ti);
 typedef void (*dm_postsuspend_fn) (struct dm_target *ti);
+typedef int (*dm_preresume_fn) (struct dm_target *ti);
 typedef void (*dm_resume_fn) (struct dm_target *ti);
 
 typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type,
@@ -92,6 +93,7 @@ struct target_type {
 	dm_endio_fn end_io;
 	dm_presuspend_fn presuspend;
 	dm_postsuspend_fn postsuspend;
+	dm_preresume_fn preresume;
 	dm_resume_fn resume;
 	dm_status_fn status;
 	dm_message_fn message;
Index: linux-2.6.18.noarch/drivers/md/dm-table.c
===================================================================
--- linux-2.6.18.noarch.orig/drivers/md/dm-table.c
+++ linux-2.6.18.noarch/drivers/md/dm-table.c
@@ -939,9 +939,20 @@ void dm_table_postsuspend_targets(struct
 	return suspend_targets(t, 1);
 }
 
-void dm_table_resume_targets(struct dm_table *t)
+int dm_table_resume_targets(struct dm_table *t)
 {
-	int i;
+	int i, r = 0;
+
+	for (i = 0; i < t->num_targets; i++) {
+		struct dm_target *ti = t->targets + i;
+
+		if (!ti->type->preresume)
+			continue;
+
+		r = ti->type->preresume(ti);
+		if (r)
+			return r;
+	}
 
 	for (i = 0; i < t->num_targets; i++) {
 		struct dm_target *ti = t->targets + i;
@@ -949,6 +960,8 @@ void dm_table_resume_targets(struct dm_t
 		if (ti->type->resume)
 			ti->type->resume(ti);
 	}
+
+	return 0;
 }
 
 int dm_table_any_congested(struct dm_table *t, int bdi_bits)
Index: linux-2.6.18.noarch/drivers/md/dm.c
===================================================================
--- linux-2.6.18.noarch.orig/drivers/md/dm.c
+++ linux-2.6.18.noarch/drivers/md/dm.c
@@ -1360,7 +1360,9 @@ int dm_resume(struct mapped_device *md)
 	if (!map || !dm_table_get_size(map))
 		goto out;
 
-	dm_table_resume_targets(map);
+	r = dm_table_resume_targets(map);
+	if (r)
+		goto out;
 
 	down_write(&md->io_lock);
 	clear_bit(DMF_BLOCK_IO, &md->flags);
Index: linux-2.6.18.noarch/drivers/md/dm.h
===================================================================
--- linux-2.6.18.noarch.orig/drivers/md/dm.h
+++ linux-2.6.18.noarch/drivers/md/dm.h
@@ -57,7 +57,7 @@ void dm_table_set_restrictions(struct dm
 struct list_head *dm_table_get_devices(struct dm_table *t);
 void dm_table_presuspend_targets(struct dm_table *t);
 void dm_table_postsuspend_targets(struct dm_table *t);
-void dm_table_resume_targets(struct dm_table *t);
+int dm_table_resume_targets(struct dm_table *t);
 int dm_table_any_congested(struct dm_table *t, int bdi_bits);
 void dm_table_unplug_all(struct dm_table *t);
 int dm_table_flush_all(struct dm_table *t);
Index: linux-2.6.18.noarch/include/linux/dm-ioctl.h
===================================================================
--- linux-2.6.18.noarch.orig/include/linux/dm-ioctl.h
+++ linux-2.6.18.noarch/include/linux/dm-ioctl.h
@@ -285,9 +285,9 @@ typedef char ioctl_struct[308];
 #define DM_DEV_SET_GEOMETRY	_IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR	4
-#define DM_VERSION_MINOR	8
+#define DM_VERSION_MINOR	9
 #define DM_VERSION_PATCHLEVEL	0
-#define DM_VERSION_EXTRA	"-ioctl (2006-06-24)"
+#define DM_VERSION_EXTRA	"-ioctl (2006-09-14)"
 
 /* Status bits */
 #define DM_READONLY_FLAG	(1 << 0) /* In/Out */

Date: Thu, 21 Sep 2006 16:50:13 +0100
From: Alasdair G Kergon <agk@redhat.com>
Subject: [RHEL5 PATCH 23/30] dm crypt: add key msg

Add the facility to wipe the encryption key from memory
(for example while a laptop is suspended) and reinstate
it later (when the laptop gets resumed).

Index: linux-2.6.18.noarch/drivers/md/dm-crypt.c
===================================================================
--- linux-2.6.18.noarch.orig/drivers/md/dm-crypt.c
+++ linux-2.6.18.noarch/drivers/md/dm-crypt.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2003 Christophe Saout <christophe@saout.de>
  * Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
  *
  * This file is released under the GPL.
  */
@@ -21,6 +22,7 @@
 #include "dm.h"
 
 #define DM_MSG_PREFIX "crypt"
+#define MESG_STR(x) x, sizeof(x)
 
 /*
  * per bio private data
@@ -62,6 +64,7 @@ struct crypt_iv_operations {
  * Crypt: maps a linear range of a block device
  * and encrypts / decrypts at the same time.
  */
+enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID };
 struct crypt_config {
 	struct dm_dev *dev;
 	sector_t start;
@@ -83,6 +86,7 @@ struct crypt_config {
 	unsigned int iv_size;
 
 	struct crypto_tfm *tfm;
+	unsigned long flags;
 	unsigned int key_size;
 	u8 key[0];
 };
@@ -503,6 +507,31 @@ static void crypt_encode_key(char *hex, 
 	}
 }
 
+static int crypt_set_key(struct crypt_config *cc, char *key)
+{
+	unsigned key_size = strlen(key) >> 1;
+
+	if (cc->key_size && cc->key_size != key_size)
+		return -EINVAL;
+
+	cc->key_size = key_size; /* initial settings */
+
+	if ((!key_size && strcmp(key, "-")) ||
+	    (key_size && crypt_decode_key(cc->key, key, key_size) < 0))
+		return -EINVAL;
+
+	set_bit(DM_CRYPT_KEY_VALID, &cc->flags);
+
+	return 0;
+}
+
+static int crypt_wipe_key(struct crypt_config *cc)
+{
+	clear_bit(DM_CRYPT_KEY_VALID, &cc->flags);
+	memset(&cc->key, 0, cc->key_size * sizeof(u8));
+	return 0;
+}
+
 /*
  * Construct an encryption mapping:
  * <cipher> <key> <iv_offset> <dev_path> <start>
@@ -536,16 +565,14 @@ static int crypt_ctr(struct dm_target *t
 
 	key_size = strlen(argv[1]) >> 1;
 
-	cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
+ 	cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
 	if (cc == NULL) {
 		ti->error =
 			"Cannot allocate transparent encryption context";
 		return -ENOMEM;
 	}
 
-	cc->key_size = key_size;
-	if ((!key_size && strcmp(argv[1], "-") != 0) ||
-	    (key_size && crypt_decode_key(cc->key, argv[1], key_size) < 0)) {
+ 	if (crypt_set_key(cc, argv[1])) {
 		ti->error = "Error decoding key";
 		goto bad1;
 	}
@@ -783,13 +810,14 @@ static int crypt_map(struct dm_target *t
 		     union map_info *map_context)
 {
 	struct crypt_config *cc = (struct crypt_config *) ti->private;
-	struct crypt_io *io = mempool_alloc(cc->io_pool, GFP_NOIO);
+	struct crypt_io *io;
 	struct convert_context ctx;
 	struct bio *clone;
 	unsigned int remaining = bio->bi_size;
 	sector_t sector = bio->bi_sector - ti->begin;
 	unsigned int bvec_idx = 0;
 
+	io = mempool_alloc(cc->io_pool, GFP_NOIO);
 	io->target = ti;
 	io->bio = bio;
 	io->first_clone = NULL;
@@ -895,14 +923,71 @@ static int crypt_status(struct dm_target
 	return 0;
 }
 
+static void crypt_postsuspend(struct dm_target *ti)
+{
+	struct crypt_config *cc = ti->private;
+
+	set_bit(DM_CRYPT_SUSPENDED, &cc->flags);
+}
+
+static int crypt_preresume(struct dm_target *ti)
+{
+	struct crypt_config *cc = ti->private;
+
+	if (!test_bit(DM_CRYPT_KEY_VALID, &cc->flags)) {
+		DMERR("aborting resume - crypt key is not set.");
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static void crypt_resume(struct dm_target *ti)
+{
+	struct crypt_config *cc = ti->private;
+
+	clear_bit(DM_CRYPT_SUSPENDED, &cc->flags);
+}
+
+/* Message interface
+ *	key set <key>
+ *	key wipe
+ */
+static int crypt_message(struct dm_target *ti, unsigned argc, char **argv)
+{
+	struct crypt_config *cc = ti->private;
+
+	if (argc < 2)
+		goto error;
+
+	if (!strnicmp(argv[0], MESG_STR("key"))) {
+		if (!test_bit(DM_CRYPT_SUSPENDED, &cc->flags)) {
+			DMWARN("not suspended during key manipulation.");
+			return -EINVAL;
+		}
+		if (argc == 3 && !strnicmp(argv[1], MESG_STR("set")))
+			return crypt_set_key(cc, argv[2]);
+		if (argc == 2 && !strnicmp(argv[1], MESG_STR("wipe")))
+			return crypt_wipe_key(cc);
+	}
+
+error:
+	DMWARN("unrecognised message received.");
+	return -EINVAL;
+}
+
 static struct target_type crypt_target = {
 	.name   = "crypt",
-	.version= {1, 1, 0},
+	.version= {1, 2, 0},
 	.module = THIS_MODULE,
 	.ctr    = crypt_ctr,
 	.dtr    = crypt_dtr,
 	.map    = crypt_map,
 	.status = crypt_status,
+	.postsuspend = crypt_postsuspend,
+	.preresume = crypt_preresume,
+	.resume = crypt_resume,
+	.message = crypt_message,
 };
 
 static int __init dm_crypt_init(void)