📄 crypto.c
字号:
if ((crp->crp_flags & CRYPTO_F_DONE) != 0) printk("crypto: crypto_done op already done, flags 0x%x", crp->crp_flags); crp->crp_flags |= CRYPTO_F_DONE; if (crp->crp_etype != 0) cryptostats.cs_errs++; /* * CBIMM means unconditionally do the callback immediately; * CBIFSYNC means do the callback immediately only if the * operation was done synchronously. Both are used to avoid * doing extraneous context switches; the latter is mostly * used with the software crypto driver. */ if ((crp->crp_flags & CRYPTO_F_CBIMM) || ((crp->crp_flags & CRYPTO_F_CBIFSYNC) && (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC))) { /* * Do the callback directly. This is ok when the * callback routine does very little (e.g. the * /dev/crypto callback method just does a wakeup). */ crp->crp_callback(crp); } else { int wasempty, r_flags; /* * Normal case; queue the callback for the thread. */ CRYPTO_RETQ_LOCK(); wasempty = list_empty(&crp_ret_q); list_add_tail(&crp->crp_list, &crp_ret_q); if (wasempty) wake_up_interruptible(&cryptoretproc_wait); /*shared wait channel */ CRYPTO_RETQ_UNLOCK(); }}/* * Invoke the callback on behalf of the driver. */voidcrypto_kdone(struct cryptkop *krp){ int wasempty, r_flags; if (krp->krp_status != 0) cryptostats.cs_kerrs++; CRYPTO_RETQ_LOCK(); wasempty = list_empty(&crp_ret_kq); list_add_tail(&krp->krp_list, &crp_ret_kq); if (wasempty) wake_up_interruptible(&cryptoretproc_wait); /* shared wait channel */ CRYPTO_RETQ_UNLOCK();}intcrypto_getfeat(int *featp){ int hid, kalg, feat = 0, d_flags; if (!crypto_userasymcrypto) goto out; CRYPTO_DRIVER_LOCK(); for (hid = 0; hid < crypto_drivers_num; hid++) { if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE) && !crypto_devallowsoft) { continue; } if (crypto_drivers[hid].cc_kprocess == NULL) continue; for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++) if ((crypto_drivers[hid].cc_kalg[kalg] & CRYPTO_ALG_FLAG_SUPPORTED) != 0) feat |= 1 << kalg; } CRYPTO_DRIVER_UNLOCK();out: *featp = feat; return (0);}/* * Crypto thread, dispatches crypto requests. */static intcrypto_proc(void *arg){ struct cryptop *crp, *submit; struct cryptkop *krp, *krpp; struct cryptocap *cap; int result, hint, q_flags; daemonize(); spin_lock_irq(¤t->sigmask_lock); sigemptyset(¤t->blocked); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); sprintf(current->comm, "crypto"); CRYPTO_Q_LOCK(); for (;;) { /* * Find the first element in the queue that can be * processed and look-ahead to see if multiple ops * are ready for the same driver. */ submit = NULL; hint = 0; list_for_each_entry(crp, &crp_q, crp_list) { u_int32_t hid = CRYPTO_SESID2HID(crp->crp_sid); cap = crypto_checkdriver(hid); if (cap == NULL || cap->cc_process == NULL) { /* Op needs to be migrated, process it. */ if (submit == NULL) submit = crp; break; } if (!cap->cc_qblocked) { if (submit != NULL) { /* * We stop on finding another op, * regardless whether its for the same * driver or not. We could keep * searching the queue but it might be * better to just use a per-driver * queue instead. */ if (CRYPTO_SESID2HID(submit->crp_sid) == hid) hint = CRYPTO_HINT_MORE; break; } else { submit = crp; if ((submit->crp_flags & CRYPTO_F_BATCH) == 0) break; /* keep scanning for more are q'd */ } } } if (submit != NULL) { list_del(&submit->crp_list); result = crypto_invoke(submit, hint); if (result == ERESTART) { /* * The driver ran out of resources, mark the * driver ``blocked'' for cryptop's and put * the request back in the queue. It would * best to put the request back where we got * it but that's hard so for now we put it * at the front. This should be ok; putting * it at the end does not work. */ /* XXX validate sid again? */ crypto_drivers[CRYPTO_SESID2HID(submit->crp_sid)].cc_qblocked = 1; list_add(&submit->crp_list, &crp_q); cryptostats.cs_blocks++; } } /* As above, but for key ops */ krp = NULL; list_for_each_entry(krpp, &crp_kq, krp_list) { cap = crypto_checkdriver(krpp->krp_hid); if (cap == NULL || cap->cc_kprocess == NULL) { /* Op needs to be migrated, process it. */ krp = krpp; break; } if (!cap->cc_kqblocked) { krp = krpp; break; } } if (krp != NULL) { list_del(&krp->krp_list); result = crypto_kinvoke(krp, 0); if (result == ERESTART) { /* * The driver ran out of resources, mark the * driver ``blocked'' for cryptkop's and put * the request back in the queue. It would * best to put the request back where we got * it but that's hard so for now we put it * at the front. This should be ok; putting * it at the end does not work. */ /* XXX validate sid again? */ crypto_drivers[krp->krp_hid].cc_kqblocked = 1; list_add(&krp->krp_list, &crp_kq); cryptostats.cs_kblocks++; } } if (submit == NULL && krp == NULL) { /* * Nothing more to be processed. Sleep until we're * woken because there are more ops to process. * This happens either by submission or by a driver * becoming unblocked and notifying us through * crypto_unblock. Note that when we wakeup we * start processing each queue again from the * front. It's not clear that it's important to * preserve this ordering since ops may finish * out of order if dispatched to different devices * and some become blocked while others do not. */ dprintk("%s - sleeping\n", __FUNCTION__); CRYPTO_Q_UNLOCK(); wait_event_interruptible(cryptoproc_wait, cryptoproc == (pid_t) -1 || !list_empty(&crp_q) || !list_empty(&crp_kq)); if (signal_pending (current)) { spin_lock_irq(¤t->sigmask_lock); flush_signals(current); spin_unlock_irq(¤t->sigmask_lock); } CRYPTO_Q_LOCK(); dprintk("%s - awake\n", __FUNCTION__); if (cryptoproc == (pid_t) -1) break; cryptostats.cs_intrs++; } } CRYPTO_Q_UNLOCK(); complete_and_exit(&cryptoproc_exited, 0);}/* * Crypto returns thread, does callbacks for processed crypto requests. * Callbacks are done here, rather than in the crypto drivers, because * callbacks typically are expensive and would slow interrupt handling. */static intcrypto_ret_proc(void *arg){ struct cryptop *crpt; struct cryptkop *krpt; int r_flags; daemonize(); spin_lock_irq(¤t->sigmask_lock); sigemptyset(¤t->blocked); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); sprintf(current->comm, "crypto_ret"); CRYPTO_RETQ_LOCK(); for (;;) { /* Harvest return q's for completed ops */ crpt = NULL; if (!list_empty(&crp_ret_q)) crpt = list_entry(crp_ret_q.next, typeof(*crpt), crp_list); if (crpt != NULL) list_del(&crpt->crp_list); krpt = NULL; if (!list_empty(&crp_ret_kq)) krpt = list_entry(crp_ret_kq.next, typeof(*krpt), krp_list); if (krpt != NULL) list_del(&krpt->krp_list); if (crpt != NULL || krpt != NULL) { CRYPTO_RETQ_UNLOCK(); /* * Run callbacks unlocked. */ if (crpt != NULL) crpt->crp_callback(crpt); if (krpt != NULL) krpt->krp_callback(krpt); CRYPTO_RETQ_LOCK(); } else { /* * Nothing more to be processed. Sleep until we're * woken because there are more returns to process. */ dprintk("%s - sleeping\n", __FUNCTION__); CRYPTO_RETQ_UNLOCK(); wait_event_interruptible(cryptoretproc_wait, cryptoretproc == (pid_t) -1 || !list_empty(&crp_ret_q) || !list_empty(&crp_ret_kq)); if (signal_pending (current)) { spin_lock_irq(¤t->sigmask_lock); flush_signals(current); spin_unlock_irq(¤t->sigmask_lock); } CRYPTO_RETQ_LOCK(); dprintk("%s - awake\n", __FUNCTION__); if (cryptoretproc == (pid_t) -1) break; cryptostats.cs_rets++; } } CRYPTO_RETQ_UNLOCK(); complete_and_exit(&cryptoretproc_exited, 0);}static intcrypto_init(void){ int error; dprintk("%s(0x%x)\n", __FUNCTION__, (int) crypto_init); if (crypto_initted) return 0; crypto_initted = 1; spin_lock_init(&crypto_drivers_lock); spin_lock_init(&crypto_q_lock); spin_lock_init(&crypto_ret_q_lock); cryptop_zone = kmem_cache_create("cryptop", sizeof(struct cryptop), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); cryptodesc_zone = kmem_cache_create("cryptodesc", sizeof(struct cryptodesc), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (cryptodesc_zone == NULL || cryptop_zone == NULL) { printk("crypto: crypto_init cannot setup crypto zones\n"); error = ENOMEM; goto bad; } crypto_drivers_num = CRYPTO_DRIVERS_INITIAL; crypto_drivers = kmalloc(crypto_drivers_num * sizeof(struct cryptocap), GFP_KERNEL); if (crypto_drivers == NULL) { printk("crypto: crypto_init cannot setup crypto drivers\n"); error = ENOMEM; goto bad; } memset(crypto_drivers, 0, crypto_drivers_num * sizeof(struct cryptocap)); init_completion(&cryptoproc_exited); init_completion(&cryptoretproc_exited); cryptoproc = kernel_thread(crypto_proc, NULL, CLONE_FS|CLONE_FILES); if (cryptoproc < 0) { error = cryptoproc; printk("crypto: crypto_init cannot start crypto thread; error %d", error); goto bad; } cryptoretproc = kernel_thread(crypto_ret_proc, NULL, CLONE_FS|CLONE_FILES); if (cryptoretproc < 0) { error = cryptoretproc; printk("crypto: crypto_init cannot start cryptoret thread; error %d", error); goto bad; } return 0;bad: crypto_exit(); return error;}static voidcrypto_exit(void){ pid_t p; int d_flags; dprintk("%s()\n", __FUNCTION__); /* * Terminate any crypto threads. */ CRYPTO_DRIVER_LOCK(); p = cryptoproc; cryptoproc = (pid_t) -1; kill_proc(p, SIGTERM, 1); wake_up_interruptible(&cryptoproc_wait); wait_for_completion(&cryptoproc_exited); p = cryptoretproc; cryptoretproc = (pid_t) -1; kill_proc(p, SIGTERM, 1); wake_up_interruptible(&cryptoretproc_wait); wait_for_completion(&cryptoretproc_exited); CRYPTO_DRIVER_UNLOCK(); /* XXX flush queues??? */ /* * Reclaim dynamically allocated resources. */ if (crypto_drivers != NULL) kfree(crypto_drivers); if (cryptodesc_zone != NULL) kmem_cache_destroy(cryptodesc_zone); if (cryptop_zone != NULL) kmem_cache_destroy(cryptop_zone);}EXPORT_SYMBOL(crypto_newsession);EXPORT_SYMBOL(crypto_freesession);EXPORT_SYMBOL(crypto_get_driverid);EXPORT_SYMBOL(crypto_kregister);EXPORT_SYMBOL(crypto_register);EXPORT_SYMBOL(crypto_unregister);EXPORT_SYMBOL(crypto_unregister_all);EXPORT_SYMBOL(crypto_unblock);EXPORT_SYMBOL(crypto_dispatch);EXPORT_SYMBOL(crypto_kdispatch);EXPORT_SYMBOL(crypto_freereq);EXPORT_SYMBOL(crypto_getreq);EXPORT_SYMBOL(crypto_done);EXPORT_SYMBOL(crypto_kdone);EXPORT_SYMBOL(crypto_getfeat);module_init(crypto_init);module_exit(crypto_exit);MODULE_LICENSE("BSD");MODULE_AUTHOR("davidm@snapgear.com");MODULE_DESCRIPTION("OCF (OpenBSD Cryptographic Framework)");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -