libceph: Create a new key type "ceph".

This allows us to use existence of the key type as a feature test,
from userspace.

Signed-off-by: Tommi Virtanen <tommi.virtanen@dreamhost.com>
Signed-off-by: Sage Weil <sage@newdream.net>
diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c
index 75f0893..5a8009c 100644
--- a/net/ceph/crypto.c
+++ b/net/ceph/crypto.c
@@ -5,7 +5,9 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <crypto/hash.h>
+#include <linux/key-type.h>
 
+#include <keys/ceph-type.h>
 #include <linux/ceph/decode.h>
 #include "crypto.h"
 
@@ -421,3 +423,63 @@
 		return -EINVAL;
 	}
 }
+
+int ceph_key_instantiate(struct key *key, const void *data, size_t datalen)
+{
+	struct ceph_crypto_key *ckey;
+	int ret;
+	void *p;
+
+	ret = -EINVAL;
+	if (datalen <= 0 || datalen > 32767 || !data)
+		goto err;
+
+	ret = key_payload_reserve(key, datalen);
+	if (ret < 0)
+		goto err;
+
+	ret = -ENOMEM;
+	ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
+	if (!ckey)
+		goto err;
+
+	/* TODO ceph_crypto_key_decode should really take const input */
+	p = (void*)data;
+	ret = ceph_crypto_key_decode(ckey, &p, (char*)data+datalen);
+	if (ret < 0)
+		goto err_ckey;
+
+	key->payload.data = ckey;
+	return 0;
+
+err_ckey:
+	kfree(ckey);
+err:
+	return ret;
+}
+
+int ceph_key_match(const struct key *key, const void *description)
+{
+	return strcmp(key->description, description) == 0;
+}
+
+void ceph_key_destroy(struct key *key) {
+	struct ceph_crypto_key *ckey = key->payload.data;
+
+	ceph_crypto_key_destroy(ckey);
+}
+
+struct key_type key_type_ceph = {
+	.name		= "ceph",
+	.instantiate	= ceph_key_instantiate,
+	.match		= ceph_key_match,
+	.destroy	= ceph_key_destroy,
+};
+
+int ceph_crypto_init(void) {
+	return register_key_type(&key_type_ceph);
+}
+
+void ceph_crypto_shutdown(void) {
+	unregister_key_type(&key_type_ceph);
+}