2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek/*
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek SSSD
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek KCM Server - the KCM operations wait queue
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek Copyright (C) Red Hat, 2017
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek This program is free software; you can redistribute it and/or modify
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek it under the terms of the GNU General Public License as published by
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek the Free Software Foundation; either version 3 of the License, or
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek (at your option) any later version.
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek This program is distributed in the hope that it will be useful,
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek but WITHOUT ANY WARRANTY; without even the implied warranty of
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek GNU General Public License for more details.
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek You should have received a copy of the GNU General Public License
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek along with this program. If not, see <http://www.gnu.org/licenses/>.
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek*/
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek#include "util/util.h"
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek#include "util/util_creds.h"
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek#include "responder/kcm/kcmsrv_pvt.h"
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek#define QUEUE_HASH_SIZE 32
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozekstruct kcm_ops_queue_entry {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek struct tevent_req *req;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct kcm_ops_queue *queue;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek struct kcm_ops_queue_entry *next;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek struct kcm_ops_queue_entry *prev;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek};
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozekstruct kcm_ops_queue {
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek uid_t uid;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct tevent_context *ev;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct kcm_ops_queue_ctx *qctx;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct kcm_ops_queue_entry *head;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek};
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozekstruct kcm_ops_queue_ctx {
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek /* UID:kcm_ops_queue */
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek hash_table_t *wait_queue_hash;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek};
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek/*
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek * Per-UID wait queue
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek *
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek * They key in the hash table is the UID of the peer. The value of each
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek * hash table entry is kcm_ops_queue structure which in turn contains a
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek * linked list of kcm_ops_queue_entry structures * which primarily hold the
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek * tevent request being queued.
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek */
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozekstruct kcm_ops_queue_ctx *kcm_ops_queue_create(TALLOC_CTX *mem_ctx)
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek{
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek errno_t ret;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek struct kcm_ops_queue_ctx *queue_ctx;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek queue_ctx = talloc_zero(mem_ctx, struct kcm_ops_queue_ctx);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek if (queue_ctx == NULL) {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek return NULL;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek }
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek ret = sss_hash_create_ex(mem_ctx, QUEUE_HASH_SIZE,
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek &queue_ctx->wait_queue_hash, 0, 0, 0, 0,
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek NULL, NULL);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek if (ret != EOK) {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE,
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek "sss_hash_create failed [%d]: %s\n", ret, sss_strerror(ret));
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek talloc_free(queue_ctx);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek return NULL;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek }
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek return queue_ctx;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek}
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozekvoid queue_removal_cb(struct tevent_context *ctx,
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct tevent_immediate *imm,
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek void *private_data)
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek{
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct kcm_ops_queue *kq = talloc_get_type(private_data,
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct kcm_ops_queue);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek int ret;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek hash_key_t key;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek talloc_free(imm);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek if (kq->head != NULL) {
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek DEBUG(SSSDBG_TRACE_LIBS, "The queue is no longer empty\n");
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek return;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek }
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek key.type = HASH_KEY_ULONG;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek key.ul = kq->uid;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek /* If this was the last entry, remove the key (the UID) from the
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek * hash table to signal the queue is empty
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek */
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek ret = hash_delete(kq->qctx->wait_queue_hash, &key);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek if (ret != HASH_SUCCESS) {
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE,
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek "Failed to remove wait queue for user %"SPRIuid"\n",
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek kq->uid);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek return;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek }
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek DEBUG(SSSDBG_FUNC_DATA,
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek "Removed queue for %"SPRIuid" \n", kq->uid);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek talloc_free(kq);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek}
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozekstatic int kcm_op_queue_entry_destructor(struct kcm_ops_queue_entry *entry)
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek{
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct kcm_ops_queue_entry *next_entry;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct tevent_immediate *imm;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek if (entry == NULL) {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek return 1;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek }
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek /* Take the next entry from the queue */
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek next_entry = entry->next;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek /* Remove the current entry from the queue */
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek DLIST_REMOVE(entry->queue->head, entry);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek if (next_entry == NULL) {
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek /* If there was no other entry, schedule removal of the queue. Do it
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek * in another tevent tick to avoid issues with callbacks invoking
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek * the descructor while another request is touching the queue
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek */
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek imm = tevent_create_immediate(entry->queue);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek if (imm == NULL) {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek return 1;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek }
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek tevent_schedule_immediate(imm, entry->queue->ev, queue_removal_cb, entry->queue);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek return 0;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek }
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek /* Otherwise, mark the current head as done to run the next request */
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek tevent_req_done(next_entry->req);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek return 0;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek}
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozekstatic struct kcm_ops_queue *kcm_op_queue_get(struct kcm_ops_queue_ctx *qctx,
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct tevent_context *ev,
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek uid_t uid)
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek{
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek errno_t ret;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek hash_key_t key;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek hash_value_t value;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct kcm_ops_queue *kq;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek key.type = HASH_KEY_ULONG;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek key.ul = uid;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek ret = hash_lookup(qctx->wait_queue_hash, &key, &value);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek switch (ret) {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek case HASH_SUCCESS:
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek if (value.type != HASH_VALUE_PTR) {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected hash value type.\n");
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek return NULL;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek }
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek kq = talloc_get_type(value.ptr, struct kcm_ops_queue);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek if (kq == NULL) {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "Invalid queue pointer\n");
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek return NULL;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek }
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek DEBUG(SSSDBG_TRACE_LIBS, "Found existing queue for this ID\n");
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek break;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek case HASH_ERROR_KEY_NOT_FOUND:
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek /* No request for this UID yet. Enqueue this request in case
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek * another one comes in and return EOK to run the current request
a02a5ed51178b2cbede0396d66aed716b8898096René Genz * immediately
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek */
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek DEBUG(SSSDBG_TRACE_LIBS, "No existing queue for this ID\n");
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek kq = talloc_zero(qctx->wait_queue_hash, struct kcm_ops_queue);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek if (kq == NULL) {
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek return NULL;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek }
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek kq->uid = uid;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek kq->qctx = qctx;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek kq->ev = ev;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek value.type = HASH_VALUE_PTR;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek value.ptr = kq;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek ret = hash_enter(qctx->wait_queue_hash, &key, &value);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek if (ret != HASH_SUCCESS) {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "hash_enter failed.\n");
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek return NULL;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek }
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek break;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek default:
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "hash_lookup failed.\n");
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek return NULL;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek }
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek return kq;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek}
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozekstruct kcm_op_queue_state {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek struct kcm_ops_queue_entry *entry;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek};
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozekstatic errno_t kcm_op_queue_add_req(struct kcm_ops_queue *kq,
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct tevent_req *req);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek/*
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek * Enqueue a request.
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek *
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek * If the request queue /for the given ID/ is empty, that is, if this
a02a5ed51178b2cbede0396d66aed716b8898096René Genz * request is the first one in the queue, run the request immediately.
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek *
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek * Otherwise just add it to the queue and wait until the previous request
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek * finishes and only at that point mark the current request as done, which
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek * will trigger calling the recv function and allow the request to continue.
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek */
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozekstruct tevent_req *kcm_op_queue_send(TALLOC_CTX *mem_ctx,
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek struct tevent_context *ev,
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek struct kcm_ops_queue_ctx *qctx,
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek struct cli_creds *client)
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek{
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek errno_t ret;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek struct tevent_req *req;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct kcm_ops_queue *kq;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek struct kcm_op_queue_state *state;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek uid_t uid;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek uid = cli_creds_get_uid(client);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek req = tevent_req_create(mem_ctx, &state, struct kcm_op_queue_state);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek if (req == NULL) {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek return NULL;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek }
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek DEBUG(SSSDBG_FUNC_DATA,
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek "Adding request by %"SPRIuid" to the wait queue\n", uid);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek kq = kcm_op_queue_get(qctx, ev, uid);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek if (kq == NULL) {
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek ret = EIO;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE,
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek "Cannot get queue [%d]: %s\n", ret, sss_strerror(ret));
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek goto immediate;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek }
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek ret = kcm_op_queue_add_req(kq, req);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek if (ret == EOK) {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek DEBUG(SSSDBG_TRACE_LIBS,
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek "Queue was empty, running the request immediately\n");
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek goto immediate;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek } else if (ret != EAGAIN) {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek DEBUG(SSSDBG_OP_FAILURE,
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek "Cannot enqueue request [%d]: %s\n", ret, sss_strerror(ret));
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek goto immediate;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek }
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek DEBUG(SSSDBG_TRACE_LIBS, "Waiting our turn in the queue\n");
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek return req;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozekimmediate:
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek if (ret == EOK) {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek tevent_req_done(req);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek } else {
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek tevent_req_error(req, ret);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek }
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek tevent_req_post(req, ev);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek return req;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek}
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozekstatic errno_t kcm_op_queue_add_req(struct kcm_ops_queue *kq,
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct tevent_req *req)
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek{
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek errno_t ret;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct kcm_op_queue_state *state = tevent_req_data(req,
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek struct kcm_op_queue_state);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek state->entry = talloc_zero(kq->qctx->wait_queue_hash, struct kcm_ops_queue_entry);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek if (state->entry == NULL) {
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek return ENOMEM;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek }
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek state->entry->req = req;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek state->entry->queue = kq;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek talloc_set_destructor(state->entry, kcm_op_queue_entry_destructor);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek if (kq->head == NULL) {
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek /* First entry, will run callback at once */
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek ret = EOK;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek } else {
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek /* Will wait for the previous callbacks to finish */
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek ret = EAGAIN;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek }
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek DLIST_ADD_END(kq->head, state->entry, struct kcm_ops_queue_entry *);
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek return ret;
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek}
fb51bb68e62de7bb8542f5d224994eb7143040a6Jakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek/*
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek * The queue recv function is called when this request is 'activated'. The queue
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek * entry should be allocated on the same memory context as the enqueued request
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek * to trigger freeing the kcm_ops_queue_entry structure destructor when the
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek * parent request is done and its tevent_req freed. This would in turn unblock
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek * the next request in the queue
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek */
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozekerrno_t kcm_op_queue_recv(struct tevent_req *req,
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek TALLOC_CTX *mem_ctx,
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek struct kcm_ops_queue_entry **_entry)
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek{
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek struct kcm_op_queue_state *state = tevent_req_data(req,
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek struct kcm_op_queue_state);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek TEVENT_REQ_RETURN_ON_ERROR(req);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek *_entry = talloc_steal(mem_ctx, state->entry);
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek return EOK;
2b5518eeaacc6245cfa77ee4a7086f16208060fcJakub Hrozek}