1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * This file contains the core framework routines for the
28  * kernel cryptographic framework. These routines are at the
29  * layer, between the kernel API/ioctls and the SPI.
30  */
31 
32 #include <sys/zfs_context.h>
33 #include <sys/crypto/common.h>
34 #include <sys/crypto/impl.h>
35 #include <sys/crypto/sched_impl.h>
36 #include <sys/crypto/api.h>
37 
38 /* kmem caches used by the scheduler */
39 static kmem_cache_t *kcf_context_cache;
40 
41 /*
42  * Create a new context.
43  */
44 crypto_ctx_t *
45 kcf_new_ctx(kcf_provider_desc_t *pd)
46 {
47 	crypto_ctx_t *ctx;
48 	kcf_context_t *kcf_ctx;
49 
50 	kcf_ctx = kmem_cache_alloc(kcf_context_cache, KM_SLEEP);
51 	if (kcf_ctx == NULL)
52 		return (NULL);
53 
54 	/* initialize the context for the consumer */
55 	kcf_ctx->kc_refcnt = 1;
56 	KCF_PROV_REFHOLD(pd);
57 	kcf_ctx->kc_prov_desc = pd;
58 	kcf_ctx->kc_sw_prov_desc = NULL;
59 
60 	ctx = &kcf_ctx->kc_glbl_ctx;
61 	ctx->cc_provider_private = NULL;
62 	ctx->cc_framework_private = (void *)kcf_ctx;
63 
64 	return (ctx);
65 }
66 
67 /*
68  * We're done with this framework context, so free it. Note that freeing
69  * framework context (kcf_context) frees the global context (crypto_ctx).
70  *
71  * The provider is responsible for freeing provider private context after a
72  * final or single operation and resetting the cc_provider_private field
73  * to NULL. It should do this before it notifies the framework of the
74  * completion. We still need to call KCF_PROV_FREE_CONTEXT to handle cases
75  * like crypto_cancel_ctx(9f).
76  */
77 void
78 kcf_free_context(kcf_context_t *kcf_ctx)
79 {
80 	kcf_provider_desc_t *pd = kcf_ctx->kc_prov_desc;
81 	crypto_ctx_t *gctx = &kcf_ctx->kc_glbl_ctx;
82 
83 	if (gctx->cc_provider_private != NULL) {
84 		mutex_enter(&pd->pd_lock);
85 		if (!KCF_IS_PROV_REMOVED(pd)) {
86 			/*
87 			 * Increment the provider's internal refcnt so it
88 			 * doesn't unregister from the framework while
89 			 * we're calling the entry point.
90 			 */
91 			KCF_PROV_IREFHOLD(pd);
92 			mutex_exit(&pd->pd_lock);
93 			(void) KCF_PROV_FREE_CONTEXT(pd, gctx);
94 			KCF_PROV_IREFRELE(pd);
95 		} else {
96 			mutex_exit(&pd->pd_lock);
97 		}
98 	}
99 
100 	/* kcf_ctx->kc_prov_desc has a hold on pd */
101 	KCF_PROV_REFRELE(kcf_ctx->kc_prov_desc);
102 
103 	kmem_cache_free(kcf_context_cache, kcf_ctx);
104 }
105 
106 /*
107  * kmem_cache_alloc constructor for kcf_context structure.
108  */
109 static int
110 kcf_context_cache_constructor(void *buf, void *cdrarg, int kmflags)
111 {
112 	(void) cdrarg, (void) kmflags;
113 	kcf_context_t *kctx = (kcf_context_t *)buf;
114 
115 	kctx->kc_refcnt = 0;
116 
117 	return (0);
118 }
119 
120 static void
121 kcf_context_cache_destructor(void *buf, void *cdrarg)
122 {
123 	(void) cdrarg;
124 	kcf_context_t *kctx = (kcf_context_t *)buf;
125 
126 	ASSERT(kctx->kc_refcnt == 0);
127 }
128 
129 void
130 kcf_sched_destroy(void)
131 {
132 	if (kcf_context_cache)
133 		kmem_cache_destroy(kcf_context_cache);
134 }
135 
136 /*
137  * Creates and initializes all the structures needed by the framework.
138  */
139 void
140 kcf_sched_init(void)
141 {
142 	/*
143 	 * Create all the kmem caches needed by the framework. We set the
144 	 * align argument to 64, to get a slab aligned to 64-byte as well as
145 	 * have the objects (cache_chunksize) to be a 64-byte multiple.
146 	 * This helps to avoid false sharing as this is the size of the
147 	 * CPU cache line.
148 	 */
149 	kcf_context_cache = kmem_cache_create("kcf_context_cache",
150 	    sizeof (struct kcf_context), 64, kcf_context_cache_constructor,
151 	    kcf_context_cache_destructor, NULL, NULL, NULL, 0);
152 }
153