[CRYPTO] api: Add crypto_alg reference counting

Up until now we've relied on module reference counting to ensure that the
crypto_alg structures don't disappear from under us.  This was good enough
as long as each crypto_alg came from exactly one module.

However, with parameterised crypto algorithms a crypto_alg object may need
two or more modules to operate.  This means that we need to count the
references to the crypto_alg object directly.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/crypto/api.c b/crypto/api.c
index 8c2743a..5994a58 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -29,13 +29,26 @@
 LIST_HEAD(crypto_alg_list);
 DECLARE_RWSEM(crypto_alg_sem);
 
-static inline int crypto_mod_get(struct crypto_alg *alg)
+static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg)
 {
-	return try_module_get(alg->cra_module);
+	atomic_inc(&alg->cra_refcnt);
+	return alg;
 }
 
-static inline void crypto_mod_put(struct crypto_alg *alg)
+static inline void crypto_alg_put(struct crypto_alg *alg)
 {
+	if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy)
+		alg->cra_destroy(alg);
+}
+
+static struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
+{
+	return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL;
+}
+
+static void crypto_mod_put(struct crypto_alg *alg)
+{
+	crypto_alg_put(alg);
 	module_put(alg->cra_module);
 }
 
@@ -274,6 +287,7 @@
 	}
 	
 	list_add(&alg->cra_list, &crypto_alg_list);
+	atomic_set(&alg->cra_refcnt, 1);
 out:	
 	up_write(&crypto_alg_sem);
 	return ret;
@@ -284,8 +298,6 @@
 	int ret = -ENOENT;
 	struct crypto_alg *q;
 	
-	BUG_ON(!alg->cra_module);
-	
 	down_write(&crypto_alg_sem);
 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
 		if (alg == q) {
@@ -296,7 +308,15 @@
 	}
 out:	
 	up_write(&crypto_alg_sem);
-	return ret;
+
+	if (ret)
+		return ret;
+
+	BUG_ON(atomic_read(&alg->cra_refcnt) != 1);
+	if (alg->cra_destroy)
+		alg->cra_destroy(alg);
+
+	return 0;
 }
 
 int crypto_alg_available(const char *name, u32 flags)