示例#1
0
/*
 * Called by KCF_PROV_REFRELE when a provider's reference count drops
 * to zero. We free the descriptor when the last reference is released.
 * However, for software providers, we do not free it when there is an
 * unregister thread waiting. We signal that thread in this case and
 * that thread is responsible for freeing the descriptor.
 */
void
kcf_provider_zero_refcnt(kcf_provider_desc_t *desc)
{
    mutex_enter(&desc->pd_lock);
    switch (desc->pd_prov_type) {
    case CRYPTO_SW_PROVIDER:
        if (desc->pd_state == KCF_PROV_REMOVED ||
                desc->pd_state == KCF_PROV_DISABLED) {
            desc->pd_state = KCF_PROV_FREED;
            cv_broadcast(&desc->pd_remove_cv);
            mutex_exit(&desc->pd_lock);
            break;
        }
    /* FALLTHRU */

    case CRYPTO_HW_PROVIDER:
    case CRYPTO_LOGICAL_PROVIDER:
        mutex_exit(&desc->pd_lock);
        kcf_free_provider_desc(desc);
    }
}
/* Caller must hold prov_tab_mutex */
static void
kcf_free_unregistered_provs()
{
	int i;
	kcf_provider_desc_t *pd;
	boolean_t walk_again = B_FALSE;

	ASSERT(MUTEX_HELD(&prov_tab_mutex));
	for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
		if ((pd = prov_tab[i]) == NULL ||
		    pd->pd_prov_type == CRYPTO_SW_PROVIDER ||
		    pd->pd_state != KCF_PROV_UNREGISTERED)
			continue;

		if (kcf_get_refcnt(pd, B_TRUE) == 0) {
			/* kcf_free_provider_desc drops prov_tab_mutex */
			kcf_free_provider_desc(pd);
			mutex_enter(&prov_tab_mutex);
		} else
			walk_again = B_TRUE;
	}

	kcf_need_provtab_walk = walk_again;
}
示例#3
0
文件: kcf_spi.c 项目: MarkGavalda/zfs
/*
 * This routine is used to notify the framework when a provider is being
 * removed.  Hardware providers call this routine in their detach routines.
 * Software providers call this routine in their _fini() routine.
 */
int
crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
{
	uint_t mech_idx;
	kcf_provider_desc_t *desc;
	kcf_prov_state_t saved_state;

	/* lookup provider descriptor */
	if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
		return (CRYPTO_UNKNOWN_PROVIDER);

	mutex_enter(&desc->pd_lock);
	/*
	 * Check if any other thread is disabling or removing
	 * this provider. We return if this is the case.
	 */
	if (desc->pd_state >= KCF_PROV_DISABLED) {
		mutex_exit(&desc->pd_lock);
		/* Release reference held by kcf_prov_tab_lookup(). */
		KCF_PROV_REFRELE(desc);
		return (CRYPTO_BUSY);
	}

	saved_state = desc->pd_state;
	desc->pd_state = KCF_PROV_REMOVED;

	if (saved_state == KCF_PROV_BUSY) {
		/*
		 * The per-provider taskq threads may be waiting. We
		 * signal them so that they can start failing requests.
		 */
		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) {
		remove_provider(desc);
	}

	if (desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
		/* remove the provider from the mechanisms tables */
		for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
		    mech_idx++) {
			kcf_remove_mech_provider(
			    desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
		}
	}

	/* remove provider from providers table */
	if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) !=
	    CRYPTO_SUCCESS) {
		/* Release reference held by kcf_prov_tab_lookup(). */
		KCF_PROV_REFRELE(desc);
		return (CRYPTO_UNKNOWN_PROVIDER);
	}

	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.
		 */
		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);
	} else {
		/*
		 * 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);
	}

	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);
		kcf_free_provider_desc(desc);
	} else {
		KCF_PROV_REFRELE(desc);
	}

	return (CRYPTO_SUCCESS);
}