storage_backend_iscsi.c 21.5 KB
Newer Older
1 2 3
/*
 * storage_backend_iscsi.c: storage backend for iSCSI handling
 *
4
 * Copyright (C) 2007-2008, 2010-2011 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 * Copyright (C) 2007-2008 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <sys/socket.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <stdio.h>
#include <regex.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
D
David Allan 已提交
36
#include <sys/stat.h>
37

38
#include "virterror_internal.h"
39
#include "storage_backend_scsi.h"
40 41
#include "storage_backend_iscsi.h"
#include "util.h"
42
#include "memory.h"
D
David Allan 已提交
43
#include "logging.h"
44
#include "files.h"
45
#include "command.h"
46

47 48
#define VIR_FROM_THIS VIR_FROM_STORAGE

49
static int
50
virStorageBackendISCSITargetIP(const char *hostname,
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
                               char *ipaddr,
                               size_t ipaddrlen)
{
    struct addrinfo hints;
    struct addrinfo *result = NULL;
    int ret;

    memset(&hints, 0, sizeof hints);
    hints.ai_flags = AI_ADDRCONFIG;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;

    ret = getaddrinfo(hostname, NULL, &hints, &result);
    if (ret != 0) {
66
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
67 68 69 70 71 72
                              _("host lookup failed %s"),
                              gai_strerror(ret));
        return -1;
    }

    if (result == NULL) {
73
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
74 75 76 77 78 79 80 81
                              _("no IP address for target %s"),
                              hostname);
        return -1;
    }

    if (getnameinfo(result->ai_addr, result->ai_addrlen,
                    ipaddr, ipaddrlen, NULL, 0,
                    NI_NUMERICHOST) < 0) {
82
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
83 84 85 86 87 88 89 90 91 92
                              _("cannot format ip addr for %s"),
                              hostname);
        freeaddrinfo(result);
        return -1;
    }

    freeaddrinfo(result);
    return 0;
}

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
static char *
virStorageBackendISCSIPortal(virStoragePoolSourcePtr source)
{
    char ipaddr[NI_MAXHOST];
    char *portal;

    if (virStorageBackendISCSITargetIP(source->host.name,
                                       ipaddr, sizeof(ipaddr)) < 0)
        return NULL;

    if (virAsprintf(&portal, "%s:%d,1", ipaddr,
                    source->host.port ?
                    source->host.port : 3260) < 0) {
        virReportOOMError();
        return NULL;
    }

    return portal;
}


114
static int
115
virStorageBackendISCSIExtractSession(virStoragePoolObjPtr pool,
116 117 118 119 120 121 122
                                     char **const groups,
                                     void *data)
{
    char **session = data;

    if (STREQ(groups[1], pool->def->source.devices[0].path)) {
        if ((*session = strdup(groups[0])) == NULL) {
123
            virReportOOMError();
124 125 126 127 128 129 130 131
            return -1;
        }
    }

    return 0;
}

static char *
132
virStorageBackendISCSISession(virStoragePoolObjPtr pool,
133
                              int probe)
134 135
{
    /*
136
     * # iscsiadm --mode session
137 138 139 140 141 142 143 144 145 146 147
     * tcp: [1] 192.168.122.170:3260,1 demo-tgt-b
     * tcp: [2] 192.168.122.170:3260,1 demo-tgt-a
     *
     * Pull out 2nd and 4th fields
     */
    const char *regexes[] = {
        "^tcp:\\s+\\[(\\S+)\\]\\s+\\S+\\s+(\\S+)\\s*$"
    };
    int vars[] = {
        2,
    };
148
    const char *const prog[] = {
149
        ISCSIADM, "--mode", "session", NULL
150 151 152
    };
    char *session = NULL;

153 154 155 156
    /* Note that we ignore the exitstatus.  Older versions of iscsiadm tools
     * returned an exit status of > 0, even if they succeeded.  We will just
     * rely on whether session got filled in properly.
     */
157
    if (virStorageBackendRunProgRegex(pool,
158 159 160 161 162
                                      prog,
                                      1,
                                      regexes,
                                      vars,
                                      virStorageBackendISCSIExtractSession,
163
                                      &session) < 0)
164 165
        return NULL;

166 167
    if (session == NULL &&
        !probe) {
168
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
169
                              "%s", _("cannot find session"));
170 171 172 173 174 175
        return NULL;
    }

    return session;
}

D
David Allan 已提交
176 177 178 179

#define LINE_SIZE 4096

static int
180
virStorageBackendIQNFound(const char *initiatoriqn,
D
David Allan 已提交
181 182 183 184 185 186 187
                          char **ifacename)
{
    int ret = IQN_MISSING, fd = -1;
    char ebuf[64];
    FILE *fp = NULL;
    char *line = NULL, *newline = NULL, *iqn = NULL, *token = NULL,
        *saveptr = NULL;
188 189
    virCommandPtr cmd = virCommandNewArgList(ISCSIADM,
                                             "--mode", "iface", NULL);
D
David Allan 已提交
190 191 192

    if (VIR_ALLOC_N(line, LINE_SIZE) != 0) {
        ret = IQN_ERROR;
193
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
D
David Allan 已提交
194
                              _("Could not allocate memory for output of '%s'"),
195
                              ISCSIADM);
D
David Allan 已提交
196 197 198 199 200
        goto out;
    }

    memset(line, 0, LINE_SIZE);

201 202
    virCommandSetOutputFD(cmd, &fd);
    if (virCommandRunAsync(cmd, NULL) < 0) {
D
David Allan 已提交
203 204 205 206
        ret = IQN_ERROR;
        goto out;
    }

207
    if ((fp = VIR_FDOPEN(fd, "r")) == NULL) {
208
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
D
David Allan 已提交
209 210
                              _("Failed to open stream for file descriptor "
                                "when reading output from '%s': '%s'"),
211
                              ISCSIADM, virStrerror(errno, ebuf, sizeof ebuf));
D
David Allan 已提交
212 213 214 215 216 217 218 219
        ret = IQN_ERROR;
        goto out;
    }

    while (fgets(line, LINE_SIZE, fp) != NULL) {
        newline = strrchr(line, '\n');
        if (newline == NULL) {
            ret = IQN_ERROR;
220
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
D
David Allan 已提交
221 222
                                  _("Unexpected line > %d characters "
                                    "when parsing output of '%s'"),
223
                                  LINE_SIZE, ISCSIADM);
D
David Allan 已提交
224 225 226 227 228 229 230 231 232 233
            goto out;
        }
        *newline = '\0';

        iqn = strrchr(line, ',');
        if (iqn == NULL) {
            continue;
        }
        iqn++;

234
        if (STREQ(iqn, initiatoriqn)) {
D
David Allan 已提交
235 236 237 238
            token = strtok_r(line, " ", &saveptr);
            *ifacename = strdup(token);
            if (*ifacename == NULL) {
                ret = IQN_ERROR;
239
                virReportOOMError();
D
David Allan 已提交
240 241 242 243 244 245 246 247
                goto out;
            }
            VIR_DEBUG("Found interface '%s' with IQN '%s'", *ifacename, iqn);
            ret = IQN_FOUND;
            break;
        }
    }

248 249 250
    if (virCommandWait(cmd, NULL) < 0)
        ret = IQN_ERROR;

D
David Allan 已提交
251 252
out:
    if (ret == IQN_MISSING) {
253
        VIR_DEBUG("Could not find interface with IQN '%s'", iqn);
D
David Allan 已提交
254 255 256
    }

    VIR_FREE(line);
257 258
    VIR_FORCE_FCLOSE(fp);
    VIR_FORCE_CLOSE(fd);
259
    virCommandFree(cmd);
D
David Allan 已提交
260 261 262 263 264 265

    return ret;
}


static int
266
virStorageBackendCreateIfaceIQN(const char *initiatoriqn,
267
                                char **ifacename)
D
David Allan 已提交
268 269 270
{
    int ret = -1, exitstatus = -1;
    char temp_ifacename[32];
271 272 273 274 275 276 277 278 279
    const char *const cmdargv1[] = {
        ISCSIADM, "--mode", "iface", "--interface",
        temp_ifacename, "--op", "new", NULL
    };
    const char *const cmdargv2[] = {
        ISCSIADM, "--mode", "iface", "--interface", temp_ifacename,
        "--op", "update", "--name", "iface.initiatorname", "--value",
        initiatoriqn, NULL
    };
D
David Allan 已提交
280 281

    if (virRandomInitialize(time(NULL) ^ getpid()) == -1) {
282
        virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
D
David Allan 已提交
283 284 285 286 287
                              _("Failed to initialize random generator "
                                "when creating iscsi interface"));
        goto out;
    }

288 289
    snprintf(temp_ifacename, sizeof(temp_ifacename), "libvirt-iface-%08x",
             virRandom(1024 * 1024 * 1024));
D
David Allan 已提交
290 291

    VIR_DEBUG("Attempting to create interface '%s' with IQN '%s'",
292
              &temp_ifacename[0], initiatoriqn);
D
David Allan 已提交
293 294 295 296 297

    /* Note that we ignore the exitstatus.  Older versions of iscsiadm
     * tools returned an exit status of > 0, even if they succeeded.
     * We will just rely on whether the interface got created
     * properly. */
298
    if (virRun(cmdargv1, &exitstatus) < 0) {
299
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
D
David Allan 已提交
300 301 302 303 304 305 306 307
                              _("Failed to run command '%s' to create new iscsi interface"),
                              cmdargv1[0]);
        goto out;
    }

    /* Note that we ignore the exitstatus.  Older versions of iscsiadm tools
     * returned an exit status of > 0, even if they succeeded.  We will just
     * rely on whether iface file got updated properly. */
308
    if (virRun(cmdargv2, &exitstatus) < 0) {
309
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
D
David Allan 已提交
310
                              _("Failed to run command '%s' to update iscsi interface with IQN '%s'"),
311
                              cmdargv2[0], initiatoriqn);
D
David Allan 已提交
312 313 314 315
        goto out;
    }

    /* Check again to make sure the interface was created. */
316
    if (virStorageBackendIQNFound(initiatoriqn, ifacename) != IQN_FOUND) {
D
David Allan 已提交
317 318
        VIR_DEBUG("Failed to find interface '%s' with IQN '%s' "
                  "after attempting to create it",
319
                  &temp_ifacename[0], initiatoriqn);
D
David Allan 已提交
320 321 322
        goto out;
    } else {
        VIR_DEBUG("Interface '%s' with IQN '%s' was created successfully",
323
                  *ifacename, initiatoriqn);
D
David Allan 已提交
324 325 326 327 328 329 330 331 332 333 334
    }

    ret = 0;

out:
    if (ret != 0)
        VIR_FREE(*ifacename);
    return ret;
}


335

D
David Allan 已提交
336
static int
337 338 339 340
virStorageBackendISCSIConnection(const char *portal,
                                 const char *initiatoriqn,
                                 const char *target,
                                 const char **extraargv)
D
David Allan 已提交
341 342
{
    int ret = -1;
343 344 345 346 347 348 349
    const char *const baseargv[] = {
        ISCSIADM,
        "--mode", "node",
        "--portal", portal,
        "--targetname", target,
        NULL
    };
350
    virCommandPtr cmd;
D
David Allan 已提交
351 352
    char *ifacename = NULL;

353 354
    cmd = virCommandNewArgs(baseargv);
    virCommandAddArgSet(cmd, extraargv);
D
David Allan 已提交
355

356 357 358 359 360 361
    if (initiatoriqn) {
        switch (virStorageBackendIQNFound(initiatoriqn, &ifacename)) {
        case IQN_FOUND:
            VIR_DEBUG("ifacename: '%s'", ifacename);
            break;
        case IQN_MISSING:
362 363
            if (virStorageBackendCreateIfaceIQN(initiatoriqn,
                                                &ifacename) != 0) {
364 365 366 367 368 369 370
                goto cleanup;
            }
            break;
        case IQN_ERROR:
        default:
            goto cleanup;
        }
371
        virCommandAddArgList(cmd, "--interface", ifacename, NULL);
D
David Allan 已提交
372
    }
373

374
    if (virCommandRun(cmd, NULL) < 0)
375
        goto cleanup;
D
David Allan 已提交
376 377 378

    ret = 0;

379
cleanup:
380
    virCommandFree(cmd);
D
David Allan 已提交
381 382 383
    VIR_FREE(ifacename);

    return ret;
384 385
}

386

387
static int
388
virStorageBackendISCSIFindLUs(virStoragePoolObjPtr pool,
389
                              const char *session)
390
{
391
    char *sysfs_path;
392 393
    int retval = 0;
    uint32_t host;
394

395 396 397 398 399
    if (virAsprintf(&sysfs_path,
                    "/sys/class/iscsi_session/session%s/device", session) < 0) {
        virReportOOMError();
        return -1;
    }
400

401
    if (virStorageBackendSCSIGetHostNumber(sysfs_path, &host) < 0) {
402
        virReportSystemError(errno,
403 404
                             _("Failed to get host number for iSCSI session "
                               "with path '%s'"),
405
                             sysfs_path);
406
        retval = -1;
407 408
    }

409
    if (virStorageBackendSCSIFindLUs(pool, host) < 0) {
410
        virReportSystemError(errno,
411 412
                             _("Failed to find LUs on host %u"), host);
        retval = -1;
413 414
    }

415 416
    VIR_FREE(sysfs_path);

417 418
    return retval;
}
419 420

static int
421
virStorageBackendISCSIRescanLUNs(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
422 423
                                 const char *session)
{
424
    const char *const cmdargv[] = {
425 426 427
        ISCSIADM, "--mode", "session", "-r", session, "-R", NULL,
    };

428
    if (virRun(cmdargv, NULL) < 0)
429 430 431 432 433
        return -1;

    return 0;
}

434 435 436 437
struct virStorageBackendISCSITargetList {
    size_t ntargets;
    char **targets;
};
438 439

static int
440 441 442
virStorageBackendISCSIGetTargets(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                 char **const groups,
                                 void *data)
443
{
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
    struct virStorageBackendISCSITargetList *list = data;
    char *target;

    if (!(target = strdup(groups[1]))) {
        virReportOOMError();
        return -1;
    }

    if (VIR_REALLOC_N(list->targets, list->ntargets + 1) < 0) {
        VIR_FREE(target);
        virReportOOMError();
        return -1;
    }

    list->targets[list->ntargets] = target;
    list->ntargets++;

    return 0;
}

static int
virStorageBackendISCSITargetAutologin(const char *portal,
                                      const char *initiatoriqn,
                                      const char *target,
                                      bool enable)
{
    const char *extraargv[] = { "--op", "update",
                                "--name", "node.startup",
                                "--value", enable ? "automatic" : "manual",
                                NULL };

    return virStorageBackendISCSIConnection(portal, initiatoriqn, target, extraargv);
}


static int
virStorageBackendISCSIScanTargets(const char *portal,
                                  const char *initiatoriqn,
                                  size_t *ntargetsret,
                                  char ***targetsret)
{
    /**
     *
     * The output of sendtargets is very simple, just two columns,
     * portal then target name
     *
     * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo0.bf6d84
     * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo1.bf6d84
     * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo2.bf6d84
     * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo3.bf6d84
     */
    const char *regexes[] = {
        "^\\s*(\\S+)\\s+(\\S+)\\s*$"
497
    };
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
    int vars[] = { 2 };
    const char *const cmdsendtarget[] = {
        ISCSIADM, "--mode", "discovery", "--type", "sendtargets",
        "--portal", portal, NULL
    };
    struct virStorageBackendISCSITargetList list;
    int i;

    memset(&list, 0, sizeof(list));

    if (virStorageBackendRunProgRegex(NULL, /* No pool for callback */
                                      cmdsendtarget,
                                      1,
                                      regexes,
                                      vars,
                                      virStorageBackendISCSIGetTargets,
514
                                      &list) < 0) {
515
        return -1;
516
    }
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539

    for (i = 0 ; i < list.ntargets ; i++) {
        /* We have to ignore failure, because we can't undo
         * the results of 'sendtargets', unless we go scrubbing
         * around in the dirt in /var/lib/iscsi.
         */
        if (virStorageBackendISCSITargetAutologin(portal,
                                                  initiatoriqn,
                                                  list.targets[i], false) < 0)
            VIR_WARN("Unable to disable auto-login on iSCSI target %s: %s",
                     portal, list.targets[i]);
    }

    if (ntargetsret && targetsret) {
        *ntargetsret = list.ntargets;
        *targetsret = list.targets;
    } else {
        for (i = 0 ; i < list.ntargets ; i++) {
            VIR_FREE(list.targets[i]);
        }
        VIR_FREE(list.targets);
    }

540
    return 0;
541 542 543
}


544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
static char *
virStorageBackendISCSIFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
                                      const char *srcSpec,
                                      unsigned int flags ATTRIBUTE_UNUSED)
{
    virStoragePoolSourcePtr source = NULL;
    size_t ntargets = 0;
    char **targets = NULL;
    char *ret = NULL;
    int i;
    virStoragePoolSourceList list = {
        .type = VIR_STORAGE_POOL_ISCSI,
        .nsources = 0,
        .sources = NULL
    };
    char *portal = NULL;

    if (!(source = virStoragePoolDefParseSourceString(srcSpec,
                                                      list.type)))
        return NULL;

    if (!(portal = virStorageBackendISCSIPortal(source)))
        goto cleanup;

    if (virStorageBackendISCSIScanTargets(portal,
                                          source->initiator.iqn,
                                          &ntargets, &targets) < 0)
        goto cleanup;

    if (VIR_ALLOC_N(list.sources, ntargets) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    for (i = 0 ; i < ntargets ; i++) {
        if (VIR_ALLOC_N(list.sources[i].devices, 1) < 0) {
            virReportOOMError();
            goto cleanup;
        }
        list.sources[i].host = source->host;
        list.sources[i].initiator = source->initiator;
        list.sources[i].ndevice = 1;
        list.sources[i].devices[0].path = targets[i];
        list.nsources++;
    }

    if (!(ret = virStoragePoolSourceListFormat(&list))) {
        virReportOOMError();
        goto cleanup;
    }

cleanup:
    if (list.sources) {
        for (i = 0 ; i < ntargets ; i++)
            VIR_FREE(list.sources[i].devices);
        VIR_FREE(list.sources);
    }
    for (i = 0 ; i < ntargets ; i++)
        VIR_FREE(targets[i]);
    VIR_FREE(targets);
    VIR_FREE(portal);
    virStoragePoolSourceFree(source);
    return ret;
}

609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
static int
virStorageBackendISCSICheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                virStoragePoolObjPtr pool,
                                bool *isActive)
{
    char *session = NULL;
    int ret = -1;

    *isActive = false;

    if (pool->def->source.host.name == NULL) {
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                              "%s", _("missing source host"));
        return -1;
    }

    if (pool->def->source.ndevice != 1 ||
        pool->def->source.devices[0].path == NULL) {
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                              "%s", _("missing source device"));
        return -1;
    }

    if ((session = virStorageBackendISCSISession(pool, 1)) != NULL) {
        *isActive = true;
        VIR_FREE(session);
    }
    ret = 0;

    return ret;
}


642
static int
643
virStorageBackendISCSIStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
644 645 646
                                virStoragePoolObjPtr pool)
{
    char *portal = NULL;
647 648 649
    char *session = NULL;
    int ret = -1;
    const char *loginargv[] = { "--login", NULL };
650 651

    if (pool->def->source.host.name == NULL) {
652
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
653
                              "%s", _("missing source host"));
654 655 656 657 658
        return -1;
    }

    if (pool->def->source.ndevice != 1 ||
        pool->def->source.devices[0].path == NULL) {
659
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
660
                              "%s", _("missing source device"));
661 662 663
        return -1;
    }

664
    if ((session = virStorageBackendISCSISession(pool, 1)) == NULL) {
665 666 667 668 669 670
        if ((portal = virStorageBackendISCSIPortal(&pool->def->source)) == NULL)
            goto cleanup;
        /*
         * iscsiadm doesn't let you login to a target, unless you've
         * first issued a 'sendtargets' command to the portal :-(
         */
671 672 673
        if (virStorageBackendISCSIScanTargets(portal,
                                              pool->def->source.initiator.iqn,
                                              NULL, NULL) < 0)
674 675 676 677 678 679 680
            goto cleanup;

        if (virStorageBackendISCSIConnection(portal,
                                             pool->def->source.initiator.iqn,
                                             pool->def->source.devices[0].path,
                                             loginargv) < 0)
            goto cleanup;
681
    }
682 683 684 685 686
    ret = 0;

cleanup:
    VIR_FREE(session);
    return ret;
687 688 689
}

static int
690
virStorageBackendISCSIRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
691 692 693 694 695 696
                                  virStoragePoolObjPtr pool)
{
    char *session = NULL;

    pool->def->allocation = pool->def->capacity = pool->def->available = 0;

697
    if ((session = virStorageBackendISCSISession(pool, 0)) == NULL)
698
        goto cleanup;
699
    if (virStorageBackendISCSIRescanLUNs(pool, session) < 0)
700
        goto cleanup;
701
    if (virStorageBackendISCSIFindLUs(pool, session) < 0)
702
        goto cleanup;
703
    VIR_FREE(session);
704 705 706 707

    return 0;

 cleanup:
708
    VIR_FREE(session);
709 710 711 712 713
    return -1;
}


static int
714
virStorageBackendISCSIStopPool(virConnectPtr conn ATTRIBUTE_UNUSED,
715 716
                               virStoragePoolObjPtr pool)
{
717
    const char *logoutargv[] = { "--logout", NULL };
718
    char *portal;
719
    int ret = -1;
720

721
    if ((portal = virStorageBackendISCSIPortal(&pool->def->source)) == NULL)
722 723
        return -1;

724 725 726 727 728 729
    if (virStorageBackendISCSIConnection(portal,
                                         pool->def->source.initiator.iqn,
                                         pool->def->source.devices[0].path,
                                         logoutargv) < 0)
        goto cleanup;
    ret = 0;
730

731 732 733
cleanup:
    VIR_FREE(portal);
    return ret;
734 735 736
}

virStorageBackend virStorageBackendISCSI = {
737
    .type = VIR_STORAGE_POOL_ISCSI,
738

739
    .checkPool = virStorageBackendISCSICheckPool,
740 741 742
    .startPool = virStorageBackendISCSIStartPool,
    .refreshPool = virStorageBackendISCSIRefreshPool,
    .stopPool = virStorageBackendISCSIStopPool,
743
    .findPoolSources = virStorageBackendISCSIFindPoolSources,
744
};