LCOV - code coverage report
Current view: top level - tapback - frontend.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 185 0.0 %
Date: 2025-04-18 11:59:49 Functions: 0 8 0.0 %
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2016, Citrix Systems, Inc.
       3                 :            :  *
       4                 :            :  * All rights reserved.
       5                 :            :  *
       6                 :            :  * Redistribution and use in source and binary forms, with or without
       7                 :            :  * modification, are permitted provided that the following conditions are met:
       8                 :            :  * 
       9                 :            :  *  1. Redistributions of source code must retain the above copyright
      10                 :            :  *     notice, this list of conditions and the following disclaimer.
      11                 :            :  *  2. Redistributions in binary form must reproduce the above copyright
      12                 :            :  *     notice, this list of conditions and the following disclaimer in the
      13                 :            :  *     documentation and/or other materials provided with the distribution.
      14                 :            :  *  3. Neither the name of the copyright holder nor the names of its 
      15                 :            :  *     contributors may be used to endorse or promote products derived from 
      16                 :            :  *     this software without specific prior written permission.
      17                 :            :  *
      18                 :            :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      19                 :            :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      20                 :            :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      21                 :            :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
      22                 :            :  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
      23                 :            :  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      24                 :            :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
      25                 :            :  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
      26                 :            :  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
      27                 :            :  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      28                 :            :  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      29                 :            :  *
      30                 :            :  * This file contains the handler executed when the front-end XenStore path of
      31                 :            :  * a VBD gets modified.
      32                 :            :  */
      33                 :            : 
      34                 :            : #include "tapback.h"
      35                 :            : 
      36                 :            : #include <xen/io/protocols.h>
      37                 :            : #include "xen_blkif.h"
      38                 :            : 
      39                 :            : /**
      40                 :            :  * Switches the back-end state of the device by writing to XenStore.
      41                 :            :  *
      42                 :            :  * @param device the VBD
      43                 :            :  * @param state the state to switch to
      44                 :            :  * @returns 0 on success, an error code otherwise
      45                 :            :  */
      46                 :            : int
      47                 :          0 : xenbus_switch_state(vbd_t * const device,
      48                 :            :         const XenbusState state)
      49                 :            : {
      50                 :            :     int err;
      51                 :            : 
      52                 :          0 :     ASSERT(device);
      53                 :            : 
      54                 :            :     /*
      55                 :            :      * TODO Ensure @state contains a legitimate XenbusState value.
      56                 :            :      * TODO Check for valid state transitions?
      57                 :            :      */
      58                 :            : 
      59                 :          0 :     err = -tapback_device_printf(device, XBT_NULL, "state", false, "%u",
      60                 :            :             state);
      61                 :          0 :     if (err)
      62                 :          0 :         WARN(device, "failed to switch back-end state to %s: %s\n",
      63                 :            :                 xenbus_strstate(state), strerror(err));
      64                 :            :     else {
      65                 :          0 :         DBG(device, "switched back-end state to %s\n", xenbus_strstate(state));
      66                 :          0 :         device->state = state;
      67                 :            :     }
      68                 :          0 :     return err;
      69                 :            : }
      70                 :            : 
      71                 :            : /**
      72                 :            :  * Core functions that instructs the tapdisk to connect to the shared ring (if
      73                 :            :  * not already connected).
      74                 :            :  *
      75                 :            :  * If the tapdisk is not already connected, all the necessary information is
      76                 :            :  * read from XenStore and the tapdisk gets connected using this information.
      77                 :            :  * This function is idempotent: if the tapback daemon gets restarted this
      78                 :            :  * function will be called again but it won't really do anything.
      79                 :            :  *
      80                 :            :  * @param device the VBD the tapdisk should connect to
      81                 :            :  * @returns (a) 0 on success, (b) ESRCH if the tapdisk is not available, and
      82                 :            :  * (c) an error code otherwise
      83                 :            :  */
      84                 :            : static inline int
      85                 :          0 : connect_tap(vbd_t * const device)
      86                 :            : {
      87                 :          0 :     evtchn_port_t port = 0;
      88                 :          0 :     grant_ref_t *gref = NULL;
      89                 :          0 :     int err = 0;
      90                 :          0 :     char *proto_str = NULL;
      91                 :          0 :     char *persistent_grants_str = NULL;
      92                 :          0 :     int nr_pages = 0, proto = 0, order = 0;
      93                 :          0 :     bool persistent_grants = false;
      94                 :            : 
      95                 :          0 :     ASSERT(device);
      96                 :            : 
      97                 :            :     /*
      98                 :            :      * FIXME disconnect if already connected and then reconnect, this is how
      99                 :            :      * blkback does.
     100                 :            :      * FIXME If we're already connected, why did we end up here in the first
     101                 :            :      * place?
     102                 :            :      */
     103                 :          0 :     ASSERT(!device->connected);
     104                 :            : 
     105                 :            :     /*
     106                 :            :      * The physical-device XenStore key has not been written yet.
     107                 :            :      */
     108                 :          0 :     if (!device->tap) {
     109                 :          0 :         DBG(device, "no tapdisk yet\n");
     110                 :            :         err = ESRCH;
     111                 :            :         goto out;
     112                 :            :     }
     113                 :            :     /*
     114                 :            :      * TODO How can we make sure we're not missing a node written by the
     115                 :            :      * front-end? Use xs_directory?
     116                 :            :      */
     117                 :            : 
     118                 :          0 :     if (1 != tapback_device_scanf_otherend(device, XBT_NULL, RING_PAGE_ORDER,
     119                 :            :                 "%d", &order))
     120                 :          0 :         order = 0;
     121                 :            : 
     122                 :          0 :      nr_pages = 1 << order;
     123                 :            : 
     124                 :          0 :     if (!(gref = calloc(nr_pages, sizeof(grant_ref_t)))) {
     125                 :          0 :         WARN(device, "failed to allocate memory for grant refs.\n");
     126                 :            :         err = ENOMEM;
     127                 :            :         goto out;
     128                 :            :     }
     129                 :            : 
     130                 :            :     /*
     131                 :            :      * Read the grant references.
     132                 :            :      */
     133                 :          0 :     if (order) {
     134                 :          0 :         int i = 0;
     135                 :            :         /*
     136                 :            :          * +10 is for INT_MAX, +1 for NULL termination
     137                 :            :          */
     138                 :            : 
     139                 :            :         static const size_t len = sizeof(RING_REF) + 10 + 1;
     140                 :          0 :         char ring_ref[len];
     141                 :          0 :         for (i = 0; i < nr_pages; i++) {
     142                 :          0 :             if (snprintf(ring_ref, len, "%s%d", RING_REF, i) >= (int)len) {
     143                 :          0 :                 DBG(device, "error printing to buffer\n");
     144                 :            :                 err = EINVAL;
     145                 :          0 :                 goto out;
     146                 :            :             }
     147                 :          0 :             if (1 != tapback_device_scanf_otherend(device, XBT_NULL, ring_ref,
     148                 :          0 :                         "%u", &gref[i])) {
     149                 :          0 :                 WARN(device, "failed to read grant ref 0x%x\n", i);
     150                 :            :                 err = ENOENT;
     151                 :            :                 goto out;
     152                 :            :             }
     153                 :            :         }
     154                 :            :     } else {
     155                 :          0 :         if (1 != tapback_device_scanf_otherend(device, XBT_NULL, RING_REF,
     156                 :            :                     "%u", &gref[0])) {
     157                 :          0 :             WARN(device, "failed to read grant ref\n");
     158                 :            :             err = ENOENT;
     159                 :            :             goto out;
     160                 :            :         }
     161                 :            :     }
     162                 :            : 
     163                 :            :     /*
     164                 :            :      * Read the event channel.
     165                 :            :      */
     166                 :          0 :     if (1 != tapback_device_scanf_otherend(device, XBT_NULL, EVENT_CHANNEL,
     167                 :            :                 "%u", &port)) {
     168                 :          0 :         WARN(device, "failed to read event channel\n");
     169                 :            :         err = ENOENT;
     170                 :            :         goto out;
     171                 :            :     }
     172                 :            : 
     173                 :            :     /*
     174                 :            :      * Read the guest VM's ABI.
     175                 :            :      */
     176                 :          0 :     if (!(proto_str = tapback_device_read_otherend(device, XBT_NULL, PROTO)))
     177                 :            :         proto = BLKIF_PROTOCOL_X86_32;
     178                 :          0 :     else if (!strcmp(proto_str, XEN_IO_PROTO_ABI_NATIVE))
     179                 :            :         proto = BLKIF_PROTOCOL_NATIVE;
     180                 :          0 :     else if (!strcmp(proto_str, XEN_IO_PROTO_ABI_X86_32))
     181                 :            :         proto = BLKIF_PROTOCOL_X86_32;
     182                 :          0 :     else if (!strcmp(proto_str, XEN_IO_PROTO_ABI_X86_64))
     183                 :            :         proto = BLKIF_PROTOCOL_X86_64;
     184                 :            :     else {
     185                 :          0 :         WARN(device, "unsupported protocol %s\n", proto_str);
     186                 :            :         err = EINVAL;
     187                 :            :         goto out;
     188                 :            :     }
     189                 :            : 
     190                 :          0 :     DBG(device, "protocol=%d\n", proto);
     191                 :            : 
     192                 :            :     /*
     193                 :            :      * Does the front-end support persistent grants?
     194                 :            :      */
     195                 :          0 :     persistent_grants_str = tapback_device_read_otherend(device, XBT_NULL,
     196                 :            :             FEAT_PERSIST);
     197                 :          0 :     if (persistent_grants_str) {
     198                 :          0 :         if (!strcmp(persistent_grants_str, "0"))
     199                 :            :             persistent_grants = false;
     200                 :          0 :         else if (!strcmp(persistent_grants_str, "1"))
     201                 :            :             persistent_grants = true;
     202                 :            :         else {
     203                 :          0 :             WARN(device, "invalid %s value: %s\n", FEAT_PERSIST,
     204                 :            :                     persistent_grants_str);
     205                 :            :             err = EINVAL;
     206                 :            :             goto out;
     207                 :            :         }
     208                 :            :     }
     209                 :            :     else
     210                 :          0 :         DBG(device, "front-end doesn't support persistent grants\n");
     211                 :            : 
     212                 :            :     /*
     213                 :            :      * persistent grants are not yet supported
     214                 :            :      */
     215                 :          0 :     if (persistent_grants)
     216                 :          0 :         WARN(device, "front-end supports persistent grants but we don't\n");
     217                 :            : 
     218                 :            :     /*
     219                 :            :      * Create the shared ring and ask the tapdisk to connect to it.
     220                 :            :      */
     221                 :          0 :     if ((err = -tap_ctl_connect_xenblkif(device->tap->pid, device->domid,
     222                 :            :                     device->devid, device->polling_duration, device->polling_idle_threshold,
     223                 :            :                     gref, order, port, proto, NULL,
     224                 :            :                     device->minor))) {
     225                 :            :         /*
     226                 :            :          * This happens if the tapback dameon gets restarted while there are
     227                 :            :          * active VBDs.
     228                 :            :          */
     229                 :          0 :         if (err == EALREADY) {
     230                 :          0 :             INFO(device, "tapdisk[%d] minor=%d already connected to the "
     231                 :            :                                         "shared ring\n", device->tap->pid, device->tap->minor);
     232                 :            :             err = 0;
     233                 :            :         } else {
     234                 :          0 :             WARN(device, "tapdisk[%d] failed to connect to the shared "
     235                 :            :                     "ring: %s\n", device->tap->pid, strerror(err));
     236                 :            :             goto out;
     237                 :            :         }
     238                 :            :     }
     239                 :            : 
     240                 :          0 :     device->connected = true;
     241                 :            : 
     242                 :          0 :     DBG(device, "tapdisk[%d] connected to shared ring\n", device->tap->pid);
     243                 :            : 
     244                 :            : out:
     245                 :          0 :     if (err && device->connected) {
     246                 :          0 :         const int err2 = -tap_ctl_disconnect_xenblkif(device->tap->pid,
     247                 :          0 :                 device->domid, device->devid, NULL);
     248                 :          0 :         if (err2) {
     249                 :          0 :             WARN(device, "error disconnecting tapdisk[%d] from the shared "
     250                 :            :                     "ring (error ignored): %s\n", device->tap->pid,
     251                 :            :                     strerror(err2));
     252                 :            :         }
     253                 :            : 
     254                 :          0 :         device->connected = false;
     255                 :            :     }
     256                 :            : 
     257                 :          0 :     free(gref);
     258                 :          0 :     free(proto_str);
     259                 :          0 :     free(persistent_grants_str);
     260                 :            : 
     261                 :          0 :     return err;
     262                 :            : }
     263                 :            : 
     264                 :            : 
     265                 :            : /**
     266                 :            :  * Returns 0 on success, a negative error code otherwise.
     267                 :            :  */
     268                 :            : static inline int
     269                 :          0 : connect_frontend(vbd_t *device) {
     270                 :            : 
     271                 :          0 :     int err = 0;
     272                 :          0 :     xs_transaction_t xst = XBT_NULL;
     273                 :          0 :     bool abort_transaction = false;
     274                 :            : 
     275                 :          0 :     ASSERT(device);
     276                 :            : 
     277                 :            :     do {
     278                 :          0 :         if (!(xst = xs_transaction_start(device->backend->xs))) {
     279                 :          0 :             err = -errno;
     280                 :          0 :             WARN(device, "failed to start transaction: %s\n", strerror(err));
     281                 :            :             goto out;
     282                 :            :         }
     283                 :            : 
     284                 :          0 :         abort_transaction = true;
     285                 :            : 
     286                 :            :         /*
     287                 :            :          * FIXME blkback writes discard-granularity, discard-alignment,
     288                 :            :          * discard-secure, feature-discard but we don't.
     289                 :            :          */
     290                 :            : 
     291                 :            :         /*
     292                 :            :                  * Write the number of sectors, sector size, info, and barrier support
     293                 :            :                  * to the back-end path in XenStore so that the front-end creates a VBD
     294                 :            :                  * with the appropriate characteristics.
     295                 :            :          */
     296                 :          0 :         if ((err = tapback_device_printf(device, xst, "feature-barrier", true,
     297                 :          0 :                         "%d", device->backend->barrier ? 1 : 0))) {
     298                 :          0 :             WARN(device, "failed to write feature-barrier: %s\n",
     299                 :            :                                         strerror(-err));
     300                 :            :             break;
     301                 :            :         }
     302                 :            : 
     303                 :          0 :         if ((err = tapback_device_printf(device, xst, "sector-size", true,
     304                 :            :                         "%u", device->sector_size))) {
     305                 :          0 :             WARN(device, "failed to write sector-size: %s\n", strerror(-err));
     306                 :            :             break;
     307                 :            :         }
     308                 :            : 
     309                 :          0 :         if ((err = tapback_device_printf(device, xst, "sectors", true, "%llu",
     310                 :            :                         device->sectors))) {
     311                 :          0 :             WARN(device, "failed to write sectors: %s\n", strerror(-err));
     312                 :            :             break;
     313                 :            :         }
     314                 :            : 
     315                 :          0 :         if ((err = tapback_device_printf(device, xst, "info", true, "%u",
     316                 :            :                         device->info))) {
     317                 :          0 :             WARN(device, "failed to write info: %s\n", strerror(-err));
     318                 :            :             break;
     319                 :            :         }
     320                 :            : 
     321                 :          0 :                 abort_transaction = false;
     322                 :          0 :         if (!xs_transaction_end(device->backend->xs, xst, 0)) {
     323                 :          0 :             err = -errno;
     324                 :          0 :             ASSERT(err);
     325                 :            :         }
     326                 :          0 :     } while (err == -EAGAIN);
     327                 :            : 
     328                 :          0 :     if (abort_transaction) {
     329                 :          0 :         if (!xs_transaction_end(device->backend->xs, xst, 1)) {
     330                 :          0 :             int err2 = errno;
     331                 :          0 :             WARN(device, "failed to abort transaction: %s\n", strerror(err2));
     332                 :            :         }
     333                 :            :         goto out;
     334                 :            :     }
     335                 :            : 
     336                 :          0 :     if (err) {
     337                 :          0 :         WARN(device, "failed to end transaction: %s\n", strerror(-err));
     338                 :            :         goto out;
     339                 :            :     }
     340                 :            : 
     341                 :          0 :     err = -xenbus_switch_state(device, XenbusStateConnected);
     342                 :          0 :     if (err)
     343                 :          0 :         WARN(device, "failed to switch back-end state to connected: %s\n",
     344                 :            :                 strerror(-err));
     345                 :            : out:
     346                 :          0 :     return err;
     347                 :            : }
     348                 :            : 
     349                 :            : /*
     350                 :            :  * Returns 0 on success, a positive error code otherwise.
     351                 :            :  *
     352                 :            :  * If tapdisk is not yet available (the physical-device key has not yet been
     353                 :            :  * written), ESRCH is returned.
     354                 :            :  */
     355                 :            : static inline int
     356                 :          0 : xenbus_connect(vbd_t *device) {
     357                 :            :     int err;
     358                 :            : 
     359                 :          0 :     ASSERT(device);
     360                 :            : 
     361                 :          0 :     err = connect_tap(device);
     362                 :            :     /*
     363                 :            :      * No tapdisk yet (the physical-device XenStore key has not been written).
     364                 :            :      */
     365                 :          0 :     if (err == ESRCH)
     366                 :            :         goto out;
     367                 :            :     /*
     368                 :            :      * Even if tapdisk is already connected to the shared ring, we continue
     369                 :            :      * connecting since we don't know how far the connection process had gone
     370                 :            :      * before the tapback daemon was restarted.
     371                 :            :      */
     372                 :          0 :     if (err && err != -EALREADY)
     373                 :            :         goto out;
     374                 :          0 :     err = -connect_frontend(device);
     375                 :            : out:
     376                 :          0 :     return err;
     377                 :            : }
     378                 :            : 
     379                 :            : /**
     380                 :            :  * Callback that is executed when the front-end goes to StateClosed.
     381                 :            :  *
     382                 :            :  * Instructs the tapdisk to disconnect itself from the shared ring and switches
     383                 :            :  * the back-end state to StateClosed.
     384                 :            :  *
     385                 :            :  * @param xdevice the VBD whose tapdisk should be disconnected
     386                 :            :  * @param state unused
     387                 :            :  * @returns 0 on success, a +errno otherwise
     388                 :            :  *
     389                 :            :  * XXX Only called by frontend_changed.
     390                 :            :  */
     391                 :            : static inline int
     392                 :          0 : backend_close(vbd_t * const device)
     393                 :            : {
     394                 :          0 :     int err = 0;
     395                 :            : 
     396                 :          0 :     ASSERT(device);
     397                 :            : 
     398                 :          0 :     if (!device->connected) {
     399                 :            :         /*
     400                 :            :          * This VBD might be a CD-ROM device, or a disk device that never went
     401                 :            :          * to state Connected.
     402                 :            :          */
     403                 :          0 :                 if (device->tap)
     404                 :          0 :                 DBG(device, "tapdisk[%d] not connected\n", device->tap->pid);
     405                 :            :                 else
     406                 :          0 :                 DBG(device, "no tapdisk connected\n");
     407                 :            :     } else {
     408                 :          0 :         ASSERT(device->tap);
     409                 :            : 
     410                 :          0 :         DBG(device, "disconnecting tapdisk[%d] minor=%d from the ring\n",
     411                 :            :             device->tap->pid, device->minor);
     412                 :            : 
     413                 :          0 :                 err = -tap_ctl_disconnect_xenblkif(device->tap->pid, device->domid,
     414                 :            :                                 device->devid, NULL);
     415                 :          0 :                 if (err) {
     416                 :          0 :                         if (err == ESRCH) {/* tapdisk might have died :-( */
     417                 :          0 :                                 WARN(device, "tapdisk[%d] not running\n", device->tap->pid);
     418                 :            :                         } else {
     419                 :          0 :                                 WARN(device, "error disconnecting tapdisk[%d] minor=%d from "
     420                 :            :                                                 "the ring: %s\n", device->tap->pid, device->minor,
     421                 :            :                                                 strerror(err));
     422                 :          0 :                                 return err;
     423                 :            :                         }
     424                 :            :                 }
     425                 :            : 
     426                 :          0 :         device->connected = false;
     427                 :            :     }
     428                 :            : 
     429                 :          0 :     return xenbus_switch_state(device, XenbusStateClosed);
     430                 :            : }
     431                 :            : 
     432                 :            : int
     433                 :          0 : frontend_changed(vbd_t * const device, const XenbusState state)
     434                 :            : {
     435                 :          0 :     int err = 0;
     436                 :            : 
     437                 :          0 :     DBG(device, "front-end switched to state %s\n", xenbus_strstate(state));
     438                 :          0 :         device->frontend_state = state;
     439                 :            : 
     440                 :          0 :     switch (state) {
     441                 :            :         case XenbusStateInitialising:
     442                 :          0 :                         if (device->hotplug_status_connected)
     443                 :          0 :                                 err = xenbus_switch_state(device, XenbusStateInitWait);
     444                 :            :             break;
     445                 :            :         case XenbusStateInitialised:
     446                 :            :         case XenbusStateConnected:
     447                 :          0 :             if (!device->hotplug_status_connected)
     448                 :          0 :                 DBG(device, "udev scripts haven't yet run\n");
     449                 :            :             else {
     450                 :          0 :                 if (device->state != XenbusStateConnected) {
     451                 :          0 :                     DBG(device, "connecting to front-end\n");
     452                 :          0 :                     err = xenbus_connect(device);
     453                 :            :                 } else
     454                 :          0 :                     DBG(device, "already connected\n");
     455                 :            :             }
     456                 :            :             break;
     457                 :            :         case XenbusStateClosing:
     458                 :          0 :             err = xenbus_switch_state(device, XenbusStateClosing);
     459                 :          0 :             break;
     460                 :            :         case XenbusStateClosed:
     461                 :          0 :             err = backend_close(device);
     462                 :          0 :             break;
     463                 :            :         case XenbusStateUnknown:
     464                 :            :             err = 0;
     465                 :            :             break;
     466                 :            :         default:
     467                 :          0 :             err = EINVAL;
     468                 :          0 :             WARN(device, "invalid front-end state %d\n", state);
     469                 :            :             break;
     470                 :            :     }
     471                 :          0 :     return err;
     472                 :            : }
     473                 :            : 
     474                 :            : int
     475                 :          0 : tapback_backend_handle_otherend_watch(backend_t *backend,
     476                 :            :                 const char * const path)
     477                 :            : {
     478                 :          0 :     vbd_t *device = NULL;
     479                 :          0 :     int err = 0, state = 0;
     480                 :          0 :     char *s = NULL, *end = NULL, *_path = NULL;
     481                 :            : 
     482                 :          0 :         ASSERT(backend);
     483                 :          0 :     ASSERT(path);
     484                 :            : 
     485                 :            :     /*
     486                 :            :      * Find the device that has the same front-end state path.
     487                 :            :      *
     488                 :            :      * There should definitely be such a device in our list, otherwise this
     489                 :            :      * function would not have executed at all, since we would not be waiting
     490                 :            :      * on that XenStore path.  The XenStore path we wait for is:
     491                 :            :      * /local/domain/<domid>/device/vbd/<devname>/state. In order to watch this
     492                 :            :      * path, it means that we have received a device create request, so the
     493                 :            :      * device will be there.
     494                 :            :      *
     495                 :            :      * TODO Instead of this linear search we could do better (hash table etc).
     496                 :            :      */
     497                 :          0 :     tapback_backend_find_device(backend, device,
     498                 :            :             device->frontend_state_path &&
     499                 :            :                         !strcmp(device->frontend_state_path, path));
     500                 :          0 :     if (!device) {
     501                 :          0 :         WARN(NULL, "path \'%s\' does not correspond to a known device\n",
     502                 :            :                 path);
     503                 :          0 :         return ENODEV;
     504                 :            :     }
     505                 :            : 
     506                 :            :     /*
     507                 :            :      * Read the new front-end's state.
     508                 :            :      */
     509                 :          0 :         s = tapback_xs_read(device->backend->xs, XBT_NULL, "%s",
     510                 :            :                         device->frontend_state_path);
     511                 :          0 :     if (!s) {
     512                 :          0 :         err = errno;
     513                 :            :                 /*
     514                 :            :          * If the front-end XenBus node is missing, the XenBus device has been
     515                 :            :          * removed: remove the XenBus back-end node.
     516                 :            :                  */
     517                 :          0 :                 if (err == ENOENT) {
     518                 :          0 :             err = asprintf(&_path, "%s/%s/%d/%d", XENSTORE_BACKEND,
     519                 :          0 :                     device->backend->name, device->domid, device->devid);
     520                 :          0 :             if (err == -1) {
     521                 :          0 :                 err = errno;
     522                 :          0 :                 WARN(device, "failed to asprintf: %s\n", strerror(err));
     523                 :            :                 goto out;
     524                 :            :             }
     525                 :          0 :             err = 0;
     526                 :          0 :             if (!xs_rm(device->backend->xs, XBT_NULL, _path)) {
     527                 :          0 :                 if (errno != ENOENT) {
     528                 :          0 :                     err = errno;
     529                 :          0 :                     WARN(device, "failed to remove %s: %s\n", path,
     530                 :            :                             strerror(err));
     531                 :            :                 }
     532                 :            :             }
     533                 :            :                 }
     534                 :            :     } else {
     535                 :          0 :         state = strtol(s, &end, 0);
     536                 :          0 :         if (*end != 0 || end == s) {
     537                 :          0 :             WARN(device, "invalid XenBus state '%s'\n", s);
     538                 :            :             err = EINVAL;
     539                 :            :         } else
     540                 :          0 :             err = frontend_changed(device, state);
     541                 :            :     }
     542                 :            : 
     543                 :            : out:
     544                 :          0 :     free(s);
     545                 :          0 :     free(_path);
     546                 :          0 :     return err;
     547                 :            : }
     548                 :            : 
     549                 :            : struct backend_slave*
     550                 :          0 : tapback_find_slave(const backend_t *master, const domid_t domid) {
     551                 :            : 
     552                 :          0 :     struct backend_slave _slave, **__slave = NULL;
     553                 :            : 
     554                 :          0 :     ASSERT(master);
     555                 :            : 
     556                 :          0 :     _slave.master.domid = domid;
     557                 :            : 
     558                 :          0 :     __slave = tfind(&_slave, &master->master.slaves, compare);
     559                 :          0 :     if (!__slave)
     560                 :          0 :         return NULL;
     561                 :          0 :     return *__slave;
     562                 :            : }

Generated by: LCOV version 1.13