static void virtblk_done(struct virtqueue *vq) { struct virtio_blk *vblk = vq->vdev->priv; bool req_done = false; int qid = vq->index; struct virtblk_req *vbr; unsigned long flags; unsigned int len; spin_lock_irqsave(&vblk->vqs[qid].lock, flags); do { virtqueue_disable_cb(vq); while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) { blk_mq_complete_request(vbr->req, vbr->req->errors); req_done = true; } if (unlikely(virtqueue_is_broken(vq))) break; } while (!virtqueue_enable_cb(vq)); /* In case queue is stopped waiting for more buffers. */ if (req_done) blk_mq_start_stopped_hw_queues(vblk->disk->queue, true); spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags); }
static int virtio_crypto_alg_ablkcipher_close_session( struct virtio_crypto_ablkcipher_ctx *ctx, int encrypt) { struct scatterlist outhdr, status_sg, *sgs[2]; unsigned int tmp; struct virtio_crypto_destroy_session_req *destroy_session; struct virtio_crypto *vcrypto = ctx->vcrypto; int err; unsigned int num_out = 0, num_in = 0; spin_lock(&vcrypto->ctrl_lock); vcrypto->ctrl_status.status = VIRTIO_CRYPTO_ERR; /* Pad ctrl header */ vcrypto->ctrl.header.opcode = cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION); /* Set the default virtqueue id to 0 */ vcrypto->ctrl.header.queue_id = 0; destroy_session = &vcrypto->ctrl.u.destroy_session; if (encrypt) destroy_session->session_id = cpu_to_le64(ctx->enc_sess_info.session_id); else destroy_session->session_id = cpu_to_le64(ctx->dec_sess_info.session_id); sg_init_one(&outhdr, &vcrypto->ctrl, sizeof(vcrypto->ctrl)); sgs[num_out++] = &outhdr; /* Return status and session id back */ sg_init_one(&status_sg, &vcrypto->ctrl_status.status, sizeof(vcrypto->ctrl_status.status)); sgs[num_out + num_in++] = &status_sg; err = virtqueue_add_sgs(vcrypto->ctrl_vq, sgs, num_out, num_in, vcrypto, GFP_ATOMIC); if (err < 0) { spin_unlock(&vcrypto->ctrl_lock); return err; } virtqueue_kick(vcrypto->ctrl_vq); while (!virtqueue_get_buf(vcrypto->ctrl_vq, &tmp) && !virtqueue_is_broken(vcrypto->ctrl_vq)) cpu_relax(); if (vcrypto->ctrl_status.status != VIRTIO_CRYPTO_OK) { spin_unlock(&vcrypto->ctrl_lock); pr_err("virtio_crypto: Close session failed status: %u, session_id: 0x%llx\n", vcrypto->ctrl_status.status, destroy_session->session_id); return -EINVAL; } spin_unlock(&vcrypto->ctrl_lock); return 0; }
static int virtio_crypto_alg_ablkcipher_init_session( struct virtio_crypto_ablkcipher_ctx *ctx, uint32_t alg, const uint8_t *key, unsigned int keylen, int encrypt) { struct scatterlist outhdr, key_sg, inhdr, *sgs[3]; unsigned int tmp; struct virtio_crypto *vcrypto = ctx->vcrypto; int op = encrypt ? VIRTIO_CRYPTO_OP_ENCRYPT : VIRTIO_CRYPTO_OP_DECRYPT; int err; unsigned int num_out = 0, num_in = 0; /* * Avoid to do DMA from the stack, switch to using * dynamically-allocated for the key */ uint8_t *cipher_key = kmalloc(keylen, GFP_ATOMIC); if (!cipher_key) return -ENOMEM; memcpy(cipher_key, key, keylen); spin_lock(&vcrypto->ctrl_lock); /* Pad ctrl header */ vcrypto->ctrl.header.opcode = cpu_to_le32(VIRTIO_CRYPTO_CIPHER_CREATE_SESSION); vcrypto->ctrl.header.algo = cpu_to_le32(alg); /* Set the default dataqueue id to 0 */ vcrypto->ctrl.header.queue_id = 0; vcrypto->input.status = cpu_to_le32(VIRTIO_CRYPTO_ERR); /* Pad cipher's parameters */ vcrypto->ctrl.u.sym_create_session.op_type = cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER); vcrypto->ctrl.u.sym_create_session.u.cipher.para.algo = vcrypto->ctrl.header.algo; vcrypto->ctrl.u.sym_create_session.u.cipher.para.keylen = cpu_to_le32(keylen); vcrypto->ctrl.u.sym_create_session.u.cipher.para.op = cpu_to_le32(op); sg_init_one(&outhdr, &vcrypto->ctrl, sizeof(vcrypto->ctrl)); sgs[num_out++] = &outhdr; /* Set key */ sg_init_one(&key_sg, cipher_key, keylen); sgs[num_out++] = &key_sg; /* Return status and session id back */ sg_init_one(&inhdr, &vcrypto->input, sizeof(vcrypto->input)); sgs[num_out + num_in++] = &inhdr; err = virtqueue_add_sgs(vcrypto->ctrl_vq, sgs, num_out, num_in, vcrypto, GFP_ATOMIC); if (err < 0) { spin_unlock(&vcrypto->ctrl_lock); kzfree(cipher_key); return err; } virtqueue_kick(vcrypto->ctrl_vq); /* * Trapping into the hypervisor, so the request should be * handled immediately. */ while (!virtqueue_get_buf(vcrypto->ctrl_vq, &tmp) && !virtqueue_is_broken(vcrypto->ctrl_vq)) cpu_relax(); if (le32_to_cpu(vcrypto->input.status) != VIRTIO_CRYPTO_OK) { spin_unlock(&vcrypto->ctrl_lock); pr_err("virtio_crypto: Create session failed status: %u\n", le32_to_cpu(vcrypto->input.status)); kzfree(cipher_key); return -EINVAL; } if (encrypt) ctx->enc_sess_info.session_id = le64_to_cpu(vcrypto->input.session_id); else ctx->dec_sess_info.session_id = le64_to_cpu(vcrypto->input.session_id); spin_unlock(&vcrypto->ctrl_lock); kzfree(cipher_key); return 0; }