linux/drivers/hv/hv_kvp.c
<<
>>
Prefs
   1/*
   2 * An implementation of key value pair (KVP) functionality for Linux.
   3 *
   4 *
   5 * Copyright (C) 2010, Novell, Inc.
   6 * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify it
   9 * under the terms of the GNU General Public License version 2 as published
  10 * by the Free Software Foundation.
  11 *
  12 * This program is distributed in the hope that it will be useful, but
  13 * WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  15 * NON INFRINGEMENT.  See the GNU General Public License for more
  16 * details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  21 *
  22 */
  23#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  24
  25#include <linux/net.h>
  26#include <linux/nls.h>
  27#include <linux/connector.h>
  28#include <linux/workqueue.h>
  29#include <linux/hyperv.h>
  30
  31
  32
  33/*
  34 * Global state maintained for transaction that is being processed.
  35 * Note that only one transaction can be active at any point in time.
  36 *
  37 * This state is set when we receive a request from the host; we
  38 * cleanup this state when the transaction is completed - when we respond
  39 * to the host with the key value.
  40 */
  41
  42static struct {
  43        bool active; /* transaction status - active or not */
  44        int recv_len; /* number of bytes received. */
  45        struct hv_kvp_msg  *kvp_msg; /* current message */
  46        struct vmbus_channel *recv_channel; /* chn we got the request */
  47        u64 recv_req_id; /* request ID. */
  48        void *kvp_context; /* for the channel callback */
  49} kvp_transaction;
  50
  51/*
  52 * Before we can accept KVP messages from the host, we need
  53 * to handshake with the user level daemon. This state tracks
  54 * if we are in the handshake phase.
  55 */
  56static bool in_hand_shake = true;
  57
  58/*
  59 * This state maintains the version number registered by the daemon.
  60 */
  61static int dm_reg_value;
  62
  63static void kvp_send_key(struct work_struct *dummy);
  64
  65
  66static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error);
  67static void kvp_work_func(struct work_struct *dummy);
  68static void kvp_register(int);
  69
  70static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func);
  71static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
  72
  73static struct cb_id kvp_id = { CN_KVP_IDX, CN_KVP_VAL };
  74static const char kvp_name[] = "kvp_kernel_module";
  75static u8 *recv_buffer;
  76/*
  77 * Register the kernel component with the user-level daemon.
  78 * As part of this registration, pass the LIC version number.
  79 */
  80
  81static void
  82kvp_register(int reg_value)
  83{
  84
  85        struct cn_msg *msg;
  86        struct hv_kvp_msg *kvp_msg;
  87        char *version;
  88
  89        msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg), GFP_ATOMIC);
  90
  91        if (msg) {
  92                kvp_msg = (struct hv_kvp_msg *)msg->data;
  93                version = kvp_msg->body.kvp_register.version;
  94                msg->id.idx =  CN_KVP_IDX;
  95                msg->id.val = CN_KVP_VAL;
  96
  97                kvp_msg->kvp_hdr.operation = reg_value;
  98                strcpy(version, HV_DRV_VERSION);
  99                msg->len = sizeof(struct hv_kvp_msg);
 100                cn_netlink_send(msg, 0, GFP_ATOMIC);
 101                kfree(msg);
 102        }
 103}
 104static void
 105kvp_work_func(struct work_struct *dummy)
 106{
 107        /*
 108         * If the timer fires, the user-mode component has not responded;
 109         * process the pending transaction.
 110         */
 111        kvp_respond_to_host(NULL, HV_E_FAIL);
 112}
 113
 114static int kvp_handle_handshake(struct hv_kvp_msg *msg)
 115{
 116        int ret = 1;
 117
 118        switch (msg->kvp_hdr.operation) {
 119        case KVP_OP_REGISTER:
 120                dm_reg_value = KVP_OP_REGISTER;
 121                pr_info("KVP: IP injection functionality not available\n");
 122                pr_info("KVP: Upgrade the KVP daemon\n");
 123                break;
 124        case KVP_OP_REGISTER1:
 125                dm_reg_value = KVP_OP_REGISTER1;
 126                break;
 127        default:
 128                pr_info("KVP: incompatible daemon\n");
 129                pr_info("KVP: KVP version: %d, Daemon version: %d\n",
 130                        KVP_OP_REGISTER1, msg->kvp_hdr.operation);
 131                ret = 0;
 132        }
 133
 134        if (ret) {
 135                /*
 136                 * We have a compatible daemon; complete the handshake.
 137                 */
 138                pr_info("KVP: user-mode registering done.\n");
 139                kvp_register(dm_reg_value);
 140                kvp_transaction.active = false;
 141                if (kvp_transaction.kvp_context)
 142                        hv_kvp_onchannelcallback(kvp_transaction.kvp_context);
 143        }
 144        return ret;
 145}
 146
 147
 148/*
 149 * Callback when data is received from user mode.
 150 */
 151
 152static void
 153kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
 154{
 155        struct hv_kvp_msg *message;
 156        struct hv_kvp_msg_enumerate *data;
 157        int     error = 0;
 158
 159        message = (struct hv_kvp_msg *)msg->data;
 160
 161        /*
 162         * If we are negotiating the version information
 163         * with the daemon; handle that first.
 164         */
 165
 166        if (in_hand_shake) {
 167                if (kvp_handle_handshake(message))
 168                        in_hand_shake = false;
 169                return;
 170        }
 171
 172        /*
 173         * Based on the version of the daemon, we propagate errors from the
 174         * daemon differently.
 175         */
 176
 177        data = &message->body.kvp_enum_data;
 178
 179        switch (dm_reg_value) {
 180        case KVP_OP_REGISTER:
 181                /*
 182                 * Null string is used to pass back error condition.
 183                 */
 184                if (data->data.key[0] == 0)
 185                        error = HV_S_CONT;
 186                break;
 187
 188        case KVP_OP_REGISTER1:
 189                /*
 190                 * We use the message header information from
 191                 * the user level daemon to transmit errors.
 192                 */
 193                error = message->error;
 194                break;
 195        }
 196
 197        /*
 198         * Complete the transaction by forwarding the key value
 199         * to the host. But first, cancel the timeout.
 200         */
 201        if (cancel_delayed_work_sync(&kvp_work))
 202                kvp_respond_to_host(message, error);
 203}
 204
 205
 206static int process_ob_ipinfo(void *in_msg, void *out_msg, int op)
 207{
 208        struct hv_kvp_msg *in = in_msg;
 209        struct hv_kvp_ip_msg *out = out_msg;
 210        int len;
 211
 212        switch (op) {
 213        case KVP_OP_GET_IP_INFO:
 214                /*
 215                 * Transform all parameters into utf16 encoding.
 216                 */
 217                len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.ip_addr,
 218                                strlen((char *)in->body.kvp_ip_val.ip_addr),
 219                                UTF16_HOST_ENDIAN,
 220                                (wchar_t *)out->kvp_ip_val.ip_addr,
 221                                MAX_IP_ADDR_SIZE);
 222                if (len < 0)
 223                        return len;
 224
 225                len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.sub_net,
 226                                strlen((char *)in->body.kvp_ip_val.sub_net),
 227                                UTF16_HOST_ENDIAN,
 228                                (wchar_t *)out->kvp_ip_val.sub_net,
 229                                MAX_IP_ADDR_SIZE);
 230                if (len < 0)
 231                        return len;
 232
 233                len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.gate_way,
 234                                strlen((char *)in->body.kvp_ip_val.gate_way),
 235                                UTF16_HOST_ENDIAN,
 236                                (wchar_t *)out->kvp_ip_val.gate_way,
 237                                MAX_GATEWAY_SIZE);
 238                if (len < 0)
 239                        return len;
 240
 241                len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.dns_addr,
 242                                strlen((char *)in->body.kvp_ip_val.dns_addr),
 243                                UTF16_HOST_ENDIAN,
 244                                (wchar_t *)out->kvp_ip_val.dns_addr,
 245                                MAX_IP_ADDR_SIZE);
 246                if (len < 0)
 247                        return len;
 248
 249                len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.adapter_id,
 250                                strlen((char *)in->body.kvp_ip_val.adapter_id),
 251                                UTF16_HOST_ENDIAN,
 252                                (wchar_t *)out->kvp_ip_val.adapter_id,
 253                                MAX_IP_ADDR_SIZE);
 254                if (len < 0)
 255                        return len;
 256
 257                out->kvp_ip_val.dhcp_enabled =
 258                        in->body.kvp_ip_val.dhcp_enabled;
 259                out->kvp_ip_val.addr_family =
 260                        in->body.kvp_ip_val.addr_family;
 261        }
 262
 263        return 0;
 264}
 265
 266static void process_ib_ipinfo(void *in_msg, void *out_msg, int op)
 267{
 268        struct hv_kvp_ip_msg *in = in_msg;
 269        struct hv_kvp_msg *out = out_msg;
 270
 271        switch (op) {
 272        case KVP_OP_SET_IP_INFO:
 273                /*
 274                 * Transform all parameters into utf8 encoding.
 275                 */
 276                utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.ip_addr,
 277                                MAX_IP_ADDR_SIZE,
 278                                UTF16_LITTLE_ENDIAN,
 279                                (__u8 *)out->body.kvp_ip_val.ip_addr,
 280                                MAX_IP_ADDR_SIZE);
 281
 282                utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.sub_net,
 283                                MAX_IP_ADDR_SIZE,
 284                                UTF16_LITTLE_ENDIAN,
 285                                (__u8 *)out->body.kvp_ip_val.sub_net,
 286                                MAX_IP_ADDR_SIZE);
 287
 288                utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.gate_way,
 289                                MAX_GATEWAY_SIZE,
 290                                UTF16_LITTLE_ENDIAN,
 291                                (__u8 *)out->body.kvp_ip_val.gate_way,
 292                                MAX_GATEWAY_SIZE);
 293
 294                utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.dns_addr,
 295                                MAX_IP_ADDR_SIZE,
 296                                UTF16_LITTLE_ENDIAN,
 297                                (__u8 *)out->body.kvp_ip_val.dns_addr,
 298                                MAX_IP_ADDR_SIZE);
 299
 300                out->body.kvp_ip_val.dhcp_enabled = in->kvp_ip_val.dhcp_enabled;
 301
 302        default:
 303                utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id,
 304                                MAX_ADAPTER_ID_SIZE,
 305                                UTF16_LITTLE_ENDIAN,
 306                                (__u8 *)out->body.kvp_ip_val.adapter_id,
 307                                MAX_ADAPTER_ID_SIZE);
 308
 309                out->body.kvp_ip_val.addr_family = in->kvp_ip_val.addr_family;
 310        }
 311}
 312
 313
 314
 315
 316static void
 317kvp_send_key(struct work_struct *dummy)
 318{
 319        struct cn_msg *msg;
 320        struct hv_kvp_msg *message;
 321        struct hv_kvp_msg *in_msg;
 322        __u8 operation = kvp_transaction.kvp_msg->kvp_hdr.operation;
 323        __u8 pool = kvp_transaction.kvp_msg->kvp_hdr.pool;
 324        __u32 val32;
 325        __u64 val64;
 326
 327        msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC);
 328        if (!msg)
 329                return;
 330
 331        msg->id.idx =  CN_KVP_IDX;
 332        msg->id.val = CN_KVP_VAL;
 333
 334        message = (struct hv_kvp_msg *)msg->data;
 335        message->kvp_hdr.operation = operation;
 336        message->kvp_hdr.pool = pool;
 337        in_msg = kvp_transaction.kvp_msg;
 338
 339        /*
 340         * The key/value strings sent from the host are encoded in
 341         * in utf16; convert it to utf8 strings.
 342         * The host assures us that the utf16 strings will not exceed
 343         * the max lengths specified. We will however, reserve room
 344         * for the string terminating character - in the utf16s_utf8s()
 345         * function we limit the size of the buffer where the converted
 346         * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to gaurantee
 347         * that the strings can be properly terminated!
 348         */
 349
 350        switch (message->kvp_hdr.operation) {
 351        case KVP_OP_SET_IP_INFO:
 352                process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO);
 353                break;
 354        case KVP_OP_GET_IP_INFO:
 355                process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO);
 356                break;
 357        case KVP_OP_SET:
 358                switch (in_msg->body.kvp_set.data.value_type) {
 359                case REG_SZ:
 360                        /*
 361                         * The value is a string - utf16 encoding.
 362                         */
 363                        message->body.kvp_set.data.value_size =
 364                                utf16s_to_utf8s(
 365                                (wchar_t *)in_msg->body.kvp_set.data.value,
 366                                in_msg->body.kvp_set.data.value_size,
 367                                UTF16_LITTLE_ENDIAN,
 368                                message->body.kvp_set.data.value,
 369                                HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1) + 1;
 370                                break;
 371
 372                case REG_U32:
 373                        /*
 374                         * The value is a 32 bit scalar.
 375                         * We save this as a utf8 string.
 376                         */
 377                        val32 = in_msg->body.kvp_set.data.value_u32;
 378                        message->body.kvp_set.data.value_size =
 379                                sprintf(message->body.kvp_set.data.value,
 380                                        "%d", val32) + 1;
 381                        break;
 382
 383                case REG_U64:
 384                        /*
 385                         * The value is a 64 bit scalar.
 386                         * We save this as a utf8 string.
 387                         */
 388                        val64 = in_msg->body.kvp_set.data.value_u64;
 389                        message->body.kvp_set.data.value_size =
 390                                sprintf(message->body.kvp_set.data.value,
 391                                        "%llu", val64) + 1;
 392                        break;
 393
 394                }
 395        case KVP_OP_GET:
 396                message->body.kvp_set.data.key_size =
 397                        utf16s_to_utf8s(
 398                        (wchar_t *)in_msg->body.kvp_set.data.key,
 399                        in_msg->body.kvp_set.data.key_size,
 400                        UTF16_LITTLE_ENDIAN,
 401                        message->body.kvp_set.data.key,
 402                        HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
 403                        break;
 404
 405        case KVP_OP_DELETE:
 406                message->body.kvp_delete.key_size =
 407                        utf16s_to_utf8s(
 408                        (wchar_t *)in_msg->body.kvp_delete.key,
 409                        in_msg->body.kvp_delete.key_size,
 410                        UTF16_LITTLE_ENDIAN,
 411                        message->body.kvp_delete.key,
 412                        HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
 413                        break;
 414
 415        case KVP_OP_ENUMERATE:
 416                message->body.kvp_enum_data.index =
 417                        in_msg->body.kvp_enum_data.index;
 418                        break;
 419        }
 420
 421        msg->len = sizeof(struct hv_kvp_msg);
 422        cn_netlink_send(msg, 0, GFP_ATOMIC);
 423        kfree(msg);
 424
 425        return;
 426}
 427
 428/*
 429 * Send a response back to the host.
 430 */
 431
 432static void
 433kvp_respond_to_host(struct hv_kvp_msg *msg_to_host, int error)
 434{
 435        struct hv_kvp_msg  *kvp_msg;
 436        struct hv_kvp_exchg_msg_value  *kvp_data;
 437        char    *key_name;
 438        char    *value;
 439        struct icmsg_hdr *icmsghdrp;
 440        int     keylen = 0;
 441        int     valuelen = 0;
 442        u32     buf_len;
 443        struct vmbus_channel *channel;
 444        u64     req_id;
 445        int ret;
 446
 447        /*
 448         * If a transaction is not active; log and return.
 449         */
 450
 451        if (!kvp_transaction.active) {
 452                /*
 453                 * This is a spurious call!
 454                 */
 455                pr_warn("KVP: Transaction not active\n");
 456                return;
 457        }
 458        /*
 459         * Copy the global state for completing the transaction. Note that
 460         * only one transaction can be active at a time.
 461         */
 462
 463        buf_len = kvp_transaction.recv_len;
 464        channel = kvp_transaction.recv_channel;
 465        req_id = kvp_transaction.recv_req_id;
 466
 467        kvp_transaction.active = false;
 468
 469        icmsghdrp = (struct icmsg_hdr *)
 470                        &recv_buffer[sizeof(struct vmbuspipe_hdr)];
 471
 472        if (channel->onchannel_callback == NULL)
 473                /*
 474                 * We have raced with util driver being unloaded;
 475                 * silently return.
 476                 */
 477                return;
 478
 479        icmsghdrp->status = error;
 480
 481        /*
 482         * If the error parameter is set, terminate the host's enumeration
 483         * on this pool.
 484         */
 485        if (error) {
 486                /*
 487                 * Something failed or we have timedout;
 488                 * terminate the current host-side iteration.
 489                 */
 490                goto response_done;
 491        }
 492
 493        kvp_msg = (struct hv_kvp_msg *)
 494                        &recv_buffer[sizeof(struct vmbuspipe_hdr) +
 495                        sizeof(struct icmsg_hdr)];
 496
 497        switch (kvp_transaction.kvp_msg->kvp_hdr.operation) {
 498        case KVP_OP_GET_IP_INFO:
 499                ret = process_ob_ipinfo(msg_to_host,
 500                                 (struct hv_kvp_ip_msg *)kvp_msg,
 501                                 KVP_OP_GET_IP_INFO);
 502                if (ret < 0)
 503                        icmsghdrp->status = HV_E_FAIL;
 504
 505                goto response_done;
 506        case KVP_OP_SET_IP_INFO:
 507                goto response_done;
 508        case KVP_OP_GET:
 509                kvp_data = &kvp_msg->body.kvp_get.data;
 510                goto copy_value;
 511
 512        case KVP_OP_SET:
 513        case KVP_OP_DELETE:
 514                goto response_done;
 515
 516        default:
 517                break;
 518        }
 519
 520        kvp_data = &kvp_msg->body.kvp_enum_data.data;
 521        key_name = msg_to_host->body.kvp_enum_data.data.key;
 522
 523        /*
 524         * The windows host expects the key/value pair to be encoded
 525         * in utf16. Ensure that the key/value size reported to the host
 526         * will be less than or equal to the MAX size (including the
 527         * terminating character).
 528         */
 529        keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN,
 530                                (wchar_t *) kvp_data->key,
 531                                (HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2) - 2);
 532        kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */
 533
 534copy_value:
 535        value = msg_to_host->body.kvp_enum_data.data.value;
 536        valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
 537                                (wchar_t *) kvp_data->value,
 538                                (HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2);
 539        kvp_data->value_size = 2*(valuelen + 1); /* utf16 encoding */
 540
 541        /*
 542         * If the utf8s to utf16s conversion failed; notify host
 543         * of the error.
 544         */
 545        if ((keylen < 0) || (valuelen < 0))
 546                icmsghdrp->status = HV_E_FAIL;
 547
 548        kvp_data->value_type = REG_SZ; /* all our values are strings */
 549
 550response_done:
 551        icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
 552
 553        vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
 554                                VM_PKT_DATA_INBAND, 0);
 555
 556}
 557
 558/*
 559 * This callback is invoked when we get a KVP message from the host.
 560 * The host ensures that only one KVP transaction can be active at a time.
 561 * KVP implementation in Linux needs to forward the key to a user-mde
 562 * component to retrive the corresponding value. Consequently, we cannot
 563 * respond to the host in the conext of this callback. Since the host
 564 * guarantees that at most only one transaction can be active at a time,
 565 * we stash away the transaction state in a set of global variables.
 566 */
 567
 568void hv_kvp_onchannelcallback(void *context)
 569{
 570        struct vmbus_channel *channel = context;
 571        u32 recvlen;
 572        u64 requestid;
 573
 574        struct hv_kvp_msg *kvp_msg;
 575
 576        struct icmsg_hdr *icmsghdrp;
 577        struct icmsg_negotiate *negop = NULL;
 578
 579        if (kvp_transaction.active) {
 580                /*
 581                 * We will defer processing this callback once
 582                 * the current transaction is complete.
 583                 */
 584                kvp_transaction.kvp_context = context;
 585                return;
 586        }
 587
 588        vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
 589                         &requestid);
 590
 591        if (recvlen > 0) {
 592                icmsghdrp = (struct icmsg_hdr *)&recv_buffer[
 593                        sizeof(struct vmbuspipe_hdr)];
 594
 595                if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
 596                        vmbus_prep_negotiate_resp(icmsghdrp, negop,
 597                                 recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
 598                } else {
 599                        kvp_msg = (struct hv_kvp_msg *)&recv_buffer[
 600                                sizeof(struct vmbuspipe_hdr) +
 601                                sizeof(struct icmsg_hdr)];
 602
 603                        /*
 604                         * Stash away this global state for completing the
 605                         * transaction; note transactions are serialized.
 606                         */
 607
 608                        kvp_transaction.recv_len = recvlen;
 609                        kvp_transaction.recv_channel = channel;
 610                        kvp_transaction.recv_req_id = requestid;
 611                        kvp_transaction.active = true;
 612                        kvp_transaction.kvp_msg = kvp_msg;
 613
 614                        /*
 615                         * Get the information from the
 616                         * user-mode component.
 617                         * component. This transaction will be
 618                         * completed when we get the value from
 619                         * the user-mode component.
 620                         * Set a timeout to deal with
 621                         * user-mode not responding.
 622                         */
 623                        schedule_work(&kvp_sendkey_work);
 624                        schedule_delayed_work(&kvp_work, 5*HZ);
 625
 626                        return;
 627
 628                }
 629
 630                icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
 631                        | ICMSGHDRFLAG_RESPONSE;
 632
 633                vmbus_sendpacket(channel, recv_buffer,
 634                                       recvlen, requestid,
 635                                       VM_PKT_DATA_INBAND, 0);
 636        }
 637
 638}
 639
 640int
 641hv_kvp_init(struct hv_util_service *srv)
 642{
 643        int err;
 644
 645        err = cn_add_callback(&kvp_id, kvp_name, kvp_cn_callback);
 646        if (err)
 647                return err;
 648        recv_buffer = srv->recv_buffer;
 649
 650        /*
 651         * When this driver loads, the user level daemon that
 652         * processes the host requests may not yet be running.
 653         * Defer processing channel callbacks until the daemon
 654         * has registered.
 655         */
 656        kvp_transaction.active = true;
 657
 658        return 0;
 659}
 660
 661void hv_kvp_deinit(void)
 662{
 663        cn_del_callback(&kvp_id);
 664        cancel_delayed_work_sync(&kvp_work);
 665        cancel_work_sync(&kvp_sendkey_work);
 666}
 667
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.