summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/crypto/spi/kcf_spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/crypto/spi/kcf_spi.c')
-rw-r--r--usr/src/uts/common/crypto/spi/kcf_spi.c150
1 files changed, 82 insertions, 68 deletions
diff --git a/usr/src/uts/common/crypto/spi/kcf_spi.c b/usr/src/uts/common/crypto/spi/kcf_spi.c
index 6aead8fb0f..90e4dd6a0c 100644
--- a/usr/src/uts/common/crypto/spi/kcf_spi.c
+++ b/usr/src/uts/common/crypto/spi/kcf_spi.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -250,12 +250,12 @@ crypto_register_provider(crypto_provider_info_t *info,
* to keep some entries cached to improve performance.
*/
if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
- prov_desc->pd_sched_info.ks_taskq = taskq_create("kcf_taskq",
+ prov_desc->pd_taskq = taskq_create("kcf_taskq",
crypto_taskq_threads, minclsyspri,
crypto_taskq_minalloc, crypto_taskq_maxalloc,
TASKQ_PREPOPULATE);
else
- prov_desc->pd_sched_info.ks_taskq = NULL;
+ prov_desc->pd_taskq = NULL;
/* no kernel session to logical providers */
if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
@@ -308,7 +308,6 @@ crypto_register_provider(crypto_provider_info_t *info,
sizeof (kcf_stats_ks_data_template));
prov_desc->pd_kstat->ks_data = &prov_desc->pd_ks_data;
KCF_PROV_REFHOLD(prov_desc);
- KCF_PROV_IREFHOLD(prov_desc);
prov_desc->pd_kstat->ks_private = prov_desc;
prov_desc->pd_kstat->ks_update = kcf_prov_kstat_update;
kstat_install(prov_desc->pd_kstat);
@@ -319,9 +318,8 @@ crypto_register_provider(crypto_provider_info_t *info,
process_logical_providers(info, prov_desc);
if (need_verify == 1) {
- /* kcf_verify_signature routine will release these holds */
+ /* kcf_verify_signature routine will release this hold */
KCF_PROV_REFHOLD(prov_desc);
- KCF_PROV_IREFHOLD(prov_desc);
if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER) {
/*
@@ -356,6 +354,27 @@ bail:
return (ret);
}
+/* Return the number of holds on a provider. */
+int
+kcf_get_refcnt(kcf_provider_desc_t *pd, boolean_t do_lock)
+{
+ int i;
+ int refcnt = 0;
+
+ if (do_lock)
+ for (i = 0; i < pd->pd_nbins; i++)
+ mutex_enter(&(pd->pd_percpu_bins[i].kp_lock));
+
+ for (i = 0; i < pd->pd_nbins; i++)
+ refcnt += pd->pd_percpu_bins[i].kp_holdcnt;
+
+ if (do_lock)
+ for (i = 0; i < pd->pd_nbins; i++)
+ mutex_exit(&(pd->pd_percpu_bins[i].kp_lock));
+
+ return (refcnt);
+}
+
/*
* This routine is used to notify the framework when a provider is being
* removed. Hardware providers call this routine in their detach routines.
@@ -385,7 +404,7 @@ crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
}
saved_state = desc->pd_state;
- desc->pd_state = KCF_PROV_REMOVED;
+ desc->pd_state = KCF_PROV_UNREGISTERING;
if (saved_state == KCF_PROV_BUSY) {
/*
@@ -395,25 +414,6 @@ crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
cv_broadcast(&desc->pd_resume_cv);
}
- if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
- /*
- * Check if this provider is currently being used.
- * pd_irefcnt is the number of holds from the internal
- * structures. We add one to account for the above lookup.
- */
- if (desc->pd_refcnt > desc->pd_irefcnt + 1) {
- desc->pd_state = saved_state;
- mutex_exit(&desc->pd_lock);
- /* Release reference held by kcf_prov_tab_lookup(). */
- KCF_PROV_REFRELE(desc);
- /*
- * The administrator presumably will stop the clients
- * thus removing the holds, when they get the busy
- * return value. Any retry will succeed then.
- */
- return (CRYPTO_BUSY);
- }
- }
mutex_exit(&desc->pd_lock);
if (desc->pd_prov_type != CRYPTO_SW_PROVIDER) {
@@ -440,40 +440,58 @@ crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
delete_kstat(desc);
if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
- /* Release reference held by kcf_prov_tab_lookup(). */
- KCF_PROV_REFRELE(desc);
-
/*
- * Wait till the existing requests complete.
+ * Wait till the existing requests with the provider complete
+ * and all the holds are released. All the holds on a software
+ * provider are from kernel clients and the hold time
+ * is expected to be short. So, we won't be stuck here forever.
*/
- mutex_enter(&desc->pd_lock);
- while (desc->pd_state != KCF_PROV_FREED)
- cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
- mutex_exit(&desc->pd_lock);
+ while (kcf_get_refcnt(desc, B_TRUE) > 1) {
+ /* wait 1 second and try again. */
+ delay(1 * drv_usectohz(1000000));
+ }
} else {
+ int i;
+ kcf_prov_cpu_t *mp;
+
/*
* Wait until requests that have been sent to the provider
* complete.
*/
- mutex_enter(&desc->pd_lock);
- while (desc->pd_irefcnt > 0)
- cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
- mutex_exit(&desc->pd_lock);
+ for (i = 0; i < desc->pd_nbins; i++) {
+ mp = &(desc->pd_percpu_bins[i]);
+
+ mutex_enter(&mp->kp_lock);
+ while (mp->kp_jobcnt > 0) {
+ cv_wait(&mp->kp_cv, &mp->kp_lock);
+ }
+ mutex_exit(&mp->kp_lock);
+ }
}
+ mutex_enter(&desc->pd_lock);
+ desc->pd_state = KCF_PROV_UNREGISTERED;
+ mutex_exit(&desc->pd_lock);
+
kcf_do_notify(desc, B_FALSE);
- if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
- /*
- * This is the only place where kcf_free_provider_desc()
- * is called directly. KCF_PROV_REFRELE() should free the
- * structure in all other places.
- */
- ASSERT(desc->pd_state == KCF_PROV_FREED &&
- desc->pd_refcnt == 0);
+ /* Release reference held by kcf_prov_tab_lookup(). */
+ KCF_PROV_REFRELE(desc);
+
+ if (kcf_get_refcnt(desc, B_TRUE) == 0) {
kcf_free_provider_desc(desc);
} else {
- KCF_PROV_REFRELE(desc);
+ ASSERT(desc->pd_prov_type != CRYPTO_SW_PROVIDER);
+ /*
+ * We could avoid this if /dev/crypto can proactively
+ * remove any holds on us from a dormant PKCS #11 app.
+ * For now, a kcfd thread does a periodic check of the
+ * provider table for KCF_PROV_UNREGISTERED entries
+ * and frees them when refcnt reaches zero.
+ */
+ mutex_enter(&prov_tab_mutex);
+ kcf_need_provtab_walk = B_TRUE;
+ mutex_exit(&prov_tab_mutex);
}
return (CRYPTO_SUCCESS);
@@ -592,17 +610,13 @@ crypto_op_notification(crypto_req_handle_t handle, int error)
if ((ctype = GET_REQ_TYPE(handle)) == CRYPTO_SYNCH) {
kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)handle;
- if (error != CRYPTO_SUCCESS)
- sreq->sn_provider->pd_sched_info.ks_nfails++;
- KCF_PROV_IREFRELE(sreq->sn_provider);
+ KCF_PROV_JOB_RELE_STAT(sreq->sn_mp, (error != CRYPTO_SUCCESS));
kcf_sop_done(sreq, error);
} else {
kcf_areq_node_t *areq = (kcf_areq_node_t *)handle;
ASSERT(ctype == CRYPTO_ASYNCH);
- if (error != CRYPTO_SUCCESS)
- areq->an_provider->pd_sched_info.ks_nfails++;
- KCF_PROV_IREFRELE(areq->an_provider);
+ KCF_PROV_JOB_RELE_STAT(areq->an_mp, (error != CRYPTO_SUCCESS));
kcf_aop_done(areq, error);
}
}
@@ -764,6 +778,7 @@ kcf_prov_kstat_update(kstat_t *ksp, int rw)
{
kcf_prov_stats_t *ks_data;
kcf_provider_desc_t *pd = (kcf_provider_desc_t *)ksp->ks_private;
+ int i;
if (rw == KSTAT_WRITE)
return (EACCES);
@@ -776,16 +791,20 @@ kcf_prov_kstat_update(kstat_t *ksp, int rw)
ks_data->ps_ops_failed.value.ui64 = 0;
ks_data->ps_ops_busy_rval.value.ui64 = 0;
} else {
- ks_data->ps_ops_total.value.ui64 =
- pd->pd_sched_info.ks_ndispatches;
- ks_data->ps_ops_failed.value.ui64 =
- pd->pd_sched_info.ks_nfails;
- ks_data->ps_ops_busy_rval.value.ui64 =
- pd->pd_sched_info.ks_nbusy_rval;
- ks_data->ps_ops_passed.value.ui64 =
- pd->pd_sched_info.ks_ndispatches -
- pd->pd_sched_info.ks_nfails -
- pd->pd_sched_info.ks_nbusy_rval;
+ uint64_t dtotal, ftotal, btotal;
+
+ dtotal = ftotal = btotal = 0;
+ /* No locking done since an exact count is not required. */
+ for (i = 0; i < pd->pd_nbins; i++) {
+ dtotal += pd->pd_percpu_bins[i].kp_ndispatches;
+ ftotal += pd->pd_percpu_bins[i].kp_nfails;
+ btotal += pd->pd_percpu_bins[i].kp_nbusy_rval;
+ }
+
+ ks_data->ps_ops_total.value.ui64 = dtotal;
+ ks_data->ps_ops_failed.value.ui64 = ftotal;
+ ks_data->ps_ops_busy_rval.value.ui64 = btotal;
+ ks_data->ps_ops_passed.value.ui64 = dtotal - ftotal - btotal;
}
return (0);
@@ -837,7 +856,6 @@ redo_register_provider(kcf_provider_desc_t *pd)
* table.
*/
KCF_PROV_REFHOLD(pd);
- KCF_PROV_IREFHOLD(pd);
}
/*
@@ -854,7 +872,6 @@ add_provider_to_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
mutex_enter(&p2->pd_lock);
new->pl_next = p2->pd_provider_list;
p2->pd_provider_list = new;
- KCF_PROV_IREFHOLD(p1);
new->pl_provider = p1;
mutex_exit(&p2->pd_lock);
}
@@ -884,7 +901,6 @@ remove_provider_from_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
}
/* detach and free kcf_provider_list structure */
- KCF_PROV_IREFRELE(p1);
*prev = pl->pl_next;
kmem_free(pl, sizeof (*pl));
mutex_exit(&p2->pd_lock);
@@ -942,7 +958,6 @@ remove_provider(kcf_provider_desc_t *pp)
if (p->pd_prov_type == CRYPTO_HW_PROVIDER &&
p->pd_provider_list == NULL)
p->pd_flags &= ~KCF_LPROV_MEMBER;
- KCF_PROV_IREFRELE(p);
next = e->pl_next;
kmem_free(e, sizeof (*e));
}
@@ -1010,6 +1025,5 @@ delete_kstat(kcf_provider_desc_t *desc)
kstat_delete(kspd->pd_kstat);
desc->pd_kstat = NULL;
KCF_PROV_REFRELE(kspd);
- KCF_PROV_IREFRELE(kspd);
}
}