Annotation of qemu/block/iscsi.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * QEMU Block driver for iSCSI images
                      3:  *
                      4:  * Copyright (c) 2010-2011 Ronnie Sahlberg <[email protected]>
                      5:  *
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: 
                     25: #include "config-host.h"
                     26: 
                     27: #include <poll.h>
                     28: #include "qemu-common.h"
                     29: #include "qemu-error.h"
                     30: #include "block_int.h"
                     31: #include "trace.h"
                     32: 
                     33: #include <iscsi/iscsi.h>
                     34: #include <iscsi/scsi-lowlevel.h>
                     35: 
                     36: 
                     37: typedef struct IscsiLun {
                     38:     struct iscsi_context *iscsi;
                     39:     int lun;
                     40:     int block_size;
                     41:     unsigned long num_blocks;
                     42: } IscsiLun;
                     43: 
                     44: typedef struct IscsiAIOCB {
                     45:     BlockDriverAIOCB common;
                     46:     QEMUIOVector *qiov;
                     47:     QEMUBH *bh;
                     48:     IscsiLun *iscsilun;
                     49:     struct scsi_task *task;
                     50:     uint8_t *buf;
                     51:     int status;
                     52:     int canceled;
                     53:     size_t read_size;
                     54:     size_t read_offset;
                     55: } IscsiAIOCB;
                     56: 
                     57: struct IscsiTask {
                     58:     IscsiLun *iscsilun;
                     59:     BlockDriverState *bs;
                     60:     int status;
                     61:     int complete;
                     62: };
                     63: 
                     64: static void
                     65: iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
                     66:                     void *private_data)
                     67: {
                     68: }
                     69: 
                     70: static void
                     71: iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
                     72: {
                     73:     IscsiAIOCB *acb = (IscsiAIOCB *)blockacb;
                     74:     IscsiLun *iscsilun = acb->iscsilun;
                     75: 
                     76:     acb->common.cb(acb->common.opaque, -ECANCELED);
                     77:     acb->canceled = 1;
                     78: 
                     79:     /* send a task mgmt call to the target to cancel the task on the target */
                     80:     iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
                     81:                                      iscsi_abort_task_cb, NULL);
                     82: 
                     83:     /* then also cancel the task locally in libiscsi */
                     84:     iscsi_scsi_task_cancel(iscsilun->iscsi, acb->task);
                     85: }
                     86: 
                     87: static AIOPool iscsi_aio_pool = {
                     88:     .aiocb_size         = sizeof(IscsiAIOCB),
                     89:     .cancel             = iscsi_aio_cancel,
                     90: };
                     91: 
                     92: 
                     93: static void iscsi_process_read(void *arg);
                     94: static void iscsi_process_write(void *arg);
                     95: 
                     96: static int iscsi_process_flush(void *arg)
                     97: {
                     98:     IscsiLun *iscsilun = arg;
                     99: 
                    100:     return iscsi_queue_length(iscsilun->iscsi) > 0;
                    101: }
                    102: 
                    103: static void
                    104: iscsi_set_events(IscsiLun *iscsilun)
                    105: {
                    106:     struct iscsi_context *iscsi = iscsilun->iscsi;
                    107: 
                    108:     qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read,
                    109:                            (iscsi_which_events(iscsi) & POLLOUT)
                    110:                            ? iscsi_process_write : NULL,
                    111:                            iscsi_process_flush, NULL, iscsilun);
                    112: }
                    113: 
                    114: static void
                    115: iscsi_process_read(void *arg)
                    116: {
                    117:     IscsiLun *iscsilun = arg;
                    118:     struct iscsi_context *iscsi = iscsilun->iscsi;
                    119: 
                    120:     iscsi_service(iscsi, POLLIN);
                    121:     iscsi_set_events(iscsilun);
                    122: }
                    123: 
                    124: static void
                    125: iscsi_process_write(void *arg)
                    126: {
                    127:     IscsiLun *iscsilun = arg;
                    128:     struct iscsi_context *iscsi = iscsilun->iscsi;
                    129: 
                    130:     iscsi_service(iscsi, POLLOUT);
                    131:     iscsi_set_events(iscsilun);
                    132: }
                    133: 
                    134: 
                    135: static int
                    136: iscsi_schedule_bh(QEMUBHFunc *cb, IscsiAIOCB *acb)
                    137: {
                    138:     acb->bh = qemu_bh_new(cb, acb);
                    139:     if (!acb->bh) {
                    140:         error_report("oom: could not create iscsi bh");
                    141:         return -EIO;
                    142:     }
                    143: 
                    144:     qemu_bh_schedule(acb->bh);
                    145:     return 0;
                    146: }
                    147: 
                    148: static void
                    149: iscsi_readv_writev_bh_cb(void *p)
                    150: {
                    151:     IscsiAIOCB *acb = p;
                    152: 
                    153:     qemu_bh_delete(acb->bh);
                    154: 
                    155:     if (acb->canceled == 0) {
                    156:         acb->common.cb(acb->common.opaque, acb->status);
                    157:     }
                    158: 
                    159:     qemu_aio_release(acb);
                    160: }
                    161: 
                    162: 
                    163: static void
                    164: iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status,
                    165:                      void *command_data, void *opaque)
                    166: {
                    167:     IscsiAIOCB *acb = opaque;
                    168: 
                    169:     trace_iscsi_aio_write10_cb(iscsi, status, acb, acb->canceled);
                    170: 
                    171:     g_free(acb->buf);
                    172: 
                    173:     if (acb->canceled != 0) {
                    174:         qemu_aio_release(acb);
                    175:         scsi_free_scsi_task(acb->task);
                    176:         acb->task = NULL;
                    177:         return;
                    178:     }
                    179: 
                    180:     acb->status = 0;
                    181:     if (status < 0) {
                    182:         error_report("Failed to write10 data to iSCSI lun. %s",
                    183:                      iscsi_get_error(iscsi));
                    184:         acb->status = -EIO;
                    185:     }
                    186: 
                    187:     iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
                    188:     scsi_free_scsi_task(acb->task);
                    189:     acb->task = NULL;
                    190: }
                    191: 
                    192: static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
                    193: {
                    194:     return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
                    195: }
                    196: 
                    197: static BlockDriverAIOCB *
                    198: iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
                    199:                  QEMUIOVector *qiov, int nb_sectors,
                    200:                  BlockDriverCompletionFunc *cb,
                    201:                  void *opaque)
                    202: {
                    203:     IscsiLun *iscsilun = bs->opaque;
                    204:     struct iscsi_context *iscsi = iscsilun->iscsi;
                    205:     IscsiAIOCB *acb;
                    206:     size_t size;
                    207:     int fua = 0;
                    208: 
                    209:     /* set FUA on writes when cache mode is write through */
                    210:     if (!(bs->open_flags & BDRV_O_CACHE_WB)) {
                    211:         fua = 1;
                    212:     }
                    213: 
                    214:     acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
                    215:     trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
                    216: 
                    217:     acb->iscsilun = iscsilun;
                    218:     acb->qiov     = qiov;
                    219: 
                    220:     acb->canceled   = 0;
                    221: 
                    222:     /* XXX we should pass the iovec to write10 to avoid the extra copy */
                    223:     /* this will allow us to get rid of 'buf' completely */
                    224:     size = nb_sectors * BDRV_SECTOR_SIZE;
                    225:     acb->buf = g_malloc(size);
                    226:     qemu_iovec_to_buffer(acb->qiov, acb->buf);
                    227:     acb->task = iscsi_write10_task(iscsi, iscsilun->lun, acb->buf, size,
                    228:                               sector_qemu2lun(sector_num, iscsilun),
                    229:                               fua, 0, iscsilun->block_size,
                    230:                               iscsi_aio_write10_cb, acb);
                    231:     if (acb->task == NULL) {
                    232:         error_report("iSCSI: Failed to send write10 command. %s",
                    233:                      iscsi_get_error(iscsi));
                    234:         g_free(acb->buf);
                    235:         qemu_aio_release(acb);
                    236:         return NULL;
                    237:     }
                    238: 
                    239:     iscsi_set_events(iscsilun);
                    240: 
                    241:     return &acb->common;
                    242: }
                    243: 
                    244: static void
                    245: iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status,
                    246:                     void *command_data, void *opaque)
                    247: {
                    248:     IscsiAIOCB *acb = opaque;
                    249: 
                    250:     trace_iscsi_aio_read10_cb(iscsi, status, acb, acb->canceled);
                    251: 
                    252:     if (acb->canceled != 0) {
                    253:         qemu_aio_release(acb);
                    254:         scsi_free_scsi_task(acb->task);
                    255:         acb->task = NULL;
                    256:         return;
                    257:     }
                    258: 
                    259:     acb->status = 0;
                    260:     if (status != 0) {
                    261:         error_report("Failed to read10 data from iSCSI lun. %s",
                    262:                      iscsi_get_error(iscsi));
                    263:         acb->status = -EIO;
                    264:     }
                    265: 
                    266:     iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
                    267:     scsi_free_scsi_task(acb->task);
                    268:     acb->task = NULL;
                    269: }
                    270: 
                    271: static BlockDriverAIOCB *
                    272: iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
                    273:                 QEMUIOVector *qiov, int nb_sectors,
                    274:                 BlockDriverCompletionFunc *cb,
                    275:                 void *opaque)
                    276: {
                    277:     IscsiLun *iscsilun = bs->opaque;
                    278:     struct iscsi_context *iscsi = iscsilun->iscsi;
                    279:     IscsiAIOCB *acb;
                    280:     size_t qemu_read_size, lun_read_size;
                    281:     int i;
                    282: 
                    283:     qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
                    284: 
                    285:     acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
                    286:     trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
                    287: 
                    288:     acb->iscsilun = iscsilun;
                    289:     acb->qiov     = qiov;
                    290: 
                    291:     acb->canceled    = 0;
                    292:     acb->read_size   = qemu_read_size;
                    293:     acb->buf         = NULL;
                    294: 
                    295:     /* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU
                    296:      * may be misaligned to the LUN, so we may need to read some extra
                    297:      * data.
                    298:      */
                    299:     acb->read_offset = 0;
                    300:     if (iscsilun->block_size > BDRV_SECTOR_SIZE) {
                    301:         uint64_t bdrv_offset = BDRV_SECTOR_SIZE * sector_num;
                    302: 
                    303:         acb->read_offset  = bdrv_offset % iscsilun->block_size;
                    304:     }
                    305: 
                    306:     lun_read_size  = (qemu_read_size + iscsilun->block_size
                    307:                      + acb->read_offset - 1)
                    308:                      / iscsilun->block_size * iscsilun->block_size;
                    309:     acb->task = iscsi_read10_task(iscsi, iscsilun->lun,
                    310:                              sector_qemu2lun(sector_num, iscsilun),
                    311:                              lun_read_size, iscsilun->block_size,
                    312:                              iscsi_aio_read10_cb, acb);
                    313:     if (acb->task == NULL) {
                    314:         error_report("iSCSI: Failed to send read10 command. %s",
                    315:                      iscsi_get_error(iscsi));
                    316:         qemu_aio_release(acb);
                    317:         return NULL;
                    318:     }
                    319: 
                    320:     for (i = 0; i < acb->qiov->niov; i++) {
                    321:         scsi_task_add_data_in_buffer(acb->task,
                    322:                 acb->qiov->iov[i].iov_len,
                    323:                 acb->qiov->iov[i].iov_base);
                    324:     }
                    325: 
                    326:     iscsi_set_events(iscsilun);
                    327: 
                    328:     return &acb->common;
                    329: }
                    330: 
                    331: 
                    332: static void
                    333: iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
                    334:                      void *command_data, void *opaque)
                    335: {
                    336:     IscsiAIOCB *acb = opaque;
                    337: 
                    338:     if (acb->canceled != 0) {
                    339:         qemu_aio_release(acb);
                    340:         scsi_free_scsi_task(acb->task);
                    341:         acb->task = NULL;
                    342:         return;
                    343:     }
                    344: 
                    345:     acb->status = 0;
                    346:     if (status < 0) {
                    347:         error_report("Failed to sync10 data on iSCSI lun. %s",
                    348:                      iscsi_get_error(iscsi));
                    349:         acb->status = -EIO;
                    350:     }
                    351: 
                    352:     iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
                    353:     scsi_free_scsi_task(acb->task);
                    354:     acb->task = NULL;
                    355: }
                    356: 
                    357: static BlockDriverAIOCB *
                    358: iscsi_aio_flush(BlockDriverState *bs,
                    359:                 BlockDriverCompletionFunc *cb, void *opaque)
                    360: {
                    361:     IscsiLun *iscsilun = bs->opaque;
                    362:     struct iscsi_context *iscsi = iscsilun->iscsi;
                    363:     IscsiAIOCB *acb;
                    364: 
                    365:     acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
                    366: 
                    367:     acb->iscsilun = iscsilun;
                    368:     acb->canceled   = 0;
                    369: 
                    370:     acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun,
                    371:                                          0, 0, 0, 0,
                    372:                                          iscsi_synccache10_cb,
                    373:                                          acb);
                    374:     if (acb->task == NULL) {
                    375:         error_report("iSCSI: Failed to send synchronizecache10 command. %s",
                    376:                      iscsi_get_error(iscsi));
                    377:         qemu_aio_release(acb);
                    378:         return NULL;
                    379:     }
                    380: 
                    381:     iscsi_set_events(iscsilun);
                    382: 
                    383:     return &acb->common;
                    384: }
                    385: 
                    386: static int64_t
                    387: iscsi_getlength(BlockDriverState *bs)
                    388: {
                    389:     IscsiLun *iscsilun = bs->opaque;
                    390:     int64_t len;
                    391: 
                    392:     len  = iscsilun->num_blocks;
                    393:     len *= iscsilun->block_size;
                    394: 
                    395:     return len;
                    396: }
                    397: 
                    398: static void
                    399: iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
                    400:                         void *command_data, void *opaque)
                    401: {
                    402:     struct IscsiTask *itask = opaque;
                    403:     struct scsi_readcapacity10 *rc10;
                    404:     struct scsi_task *task = command_data;
                    405: 
                    406:     if (status != 0) {
                    407:         error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
                    408:                      iscsi_get_error(iscsi));
                    409:         itask->status   = 1;
                    410:         itask->complete = 1;
                    411:         scsi_free_scsi_task(task);
                    412:         return;
                    413:     }
                    414: 
                    415:     rc10 = scsi_datain_unmarshall(task);
                    416:     if (rc10 == NULL) {
                    417:         error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
                    418:         itask->status   = 1;
                    419:         itask->complete = 1;
                    420:         scsi_free_scsi_task(task);
                    421:         return;
                    422:     }
                    423: 
                    424:     itask->iscsilun->block_size = rc10->block_size;
                    425:     itask->iscsilun->num_blocks = rc10->lba;
                    426:     itask->bs->total_sectors = (uint64_t)rc10->lba *
                    427:                                rc10->block_size / BDRV_SECTOR_SIZE ;
                    428: 
                    429:     itask->status   = 0;
                    430:     itask->complete = 1;
                    431:     scsi_free_scsi_task(task);
                    432: }
                    433: 
                    434: 
                    435: static void
                    436: iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
                    437:                  void *opaque)
                    438: {
                    439:     struct IscsiTask *itask = opaque;
                    440:     struct scsi_task *task;
                    441: 
                    442:     if (status != 0) {
                    443:         itask->status   = 1;
                    444:         itask->complete = 1;
                    445:         return;
                    446:     }
                    447: 
                    448:     task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun, 0, 0,
                    449:                                    iscsi_readcapacity10_cb, opaque);
                    450:     if (task == NULL) {
                    451:         error_report("iSCSI: failed to send readcapacity command.");
                    452:         itask->status   = 1;
                    453:         itask->complete = 1;
                    454:         return;
                    455:     }
                    456: }
                    457: 
                    458: /*
                    459:  * We support iscsi url's on the form
                    460:  * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
                    461:  */
                    462: static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
                    463: {
                    464:     IscsiLun *iscsilun = bs->opaque;
                    465:     struct iscsi_context *iscsi = NULL;
                    466:     struct iscsi_url *iscsi_url = NULL;
                    467:     struct IscsiTask task;
                    468:     int ret;
                    469: 
                    470:     if ((BDRV_SECTOR_SIZE % 512) != 0) {
                    471:         error_report("iSCSI: Invalid BDRV_SECTOR_SIZE. "
                    472:                      "BDRV_SECTOR_SIZE(%lld) is not a multiple "
                    473:                      "of 512", BDRV_SECTOR_SIZE);
                    474:         return -EINVAL;
                    475:     }
                    476: 
                    477:     memset(iscsilun, 0, sizeof(IscsiLun));
                    478: 
                    479:     /* Should really append the KVM name after the ':' here */
                    480:     iscsi = iscsi_create_context("iqn.2008-11.org.linux-kvm:");
                    481:     if (iscsi == NULL) {
                    482:         error_report("iSCSI: Failed to create iSCSI context.");
                    483:         ret = -ENOMEM;
                    484:         goto failed;
                    485:     }
                    486: 
                    487:     iscsi_url = iscsi_parse_full_url(iscsi, filename);
                    488:     if (iscsi_url == NULL) {
                    489:         error_report("Failed to parse URL : %s %s", filename,
                    490:                      iscsi_get_error(iscsi));
                    491:         ret = -EINVAL;
                    492:         goto failed;
                    493:     }
                    494: 
                    495:     if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
                    496:         error_report("iSCSI: Failed to set target name.");
                    497:         ret = -EINVAL;
                    498:         goto failed;
                    499:     }
                    500: 
                    501:     if (iscsi_url->user != NULL) {
                    502:         ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user,
                    503:                                               iscsi_url->passwd);
                    504:         if (ret != 0) {
                    505:             error_report("Failed to set initiator username and password");
                    506:             ret = -EINVAL;
                    507:             goto failed;
                    508:         }
                    509:     }
                    510:     if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
                    511:         error_report("iSCSI: Failed to set session type to normal.");
                    512:         ret = -EINVAL;
                    513:         goto failed;
                    514:     }
                    515: 
                    516:     iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
                    517: 
                    518:     task.iscsilun = iscsilun;
                    519:     task.status = 0;
                    520:     task.complete = 0;
                    521:     task.bs = bs;
                    522: 
                    523:     iscsilun->iscsi = iscsi;
                    524:     iscsilun->lun   = iscsi_url->lun;
                    525: 
                    526:     if (iscsi_full_connect_async(iscsi, iscsi_url->portal, iscsi_url->lun,
                    527:                                  iscsi_connect_cb, &task)
                    528:         != 0) {
                    529:         error_report("iSCSI: Failed to start async connect.");
                    530:         ret = -EINVAL;
                    531:         goto failed;
                    532:     }
                    533: 
                    534:     while (!task.complete) {
                    535:         iscsi_set_events(iscsilun);
                    536:         qemu_aio_wait();
                    537:     }
                    538:     if (task.status != 0) {
                    539:         error_report("iSCSI: Failed to connect to LUN : %s",
                    540:                      iscsi_get_error(iscsi));
                    541:         ret = -EINVAL;
                    542:         goto failed;
                    543:     }
                    544: 
                    545:     if (iscsi_url != NULL) {
                    546:         iscsi_destroy_url(iscsi_url);
                    547:     }
                    548:     return 0;
                    549: 
                    550: failed:
                    551:     if (iscsi_url != NULL) {
                    552:         iscsi_destroy_url(iscsi_url);
                    553:     }
                    554:     if (iscsi != NULL) {
                    555:         iscsi_destroy_context(iscsi);
                    556:     }
                    557:     memset(iscsilun, 0, sizeof(IscsiLun));
                    558:     return ret;
                    559: }
                    560: 
                    561: static void iscsi_close(BlockDriverState *bs)
                    562: {
                    563:     IscsiLun *iscsilun = bs->opaque;
                    564:     struct iscsi_context *iscsi = iscsilun->iscsi;
                    565: 
                    566:     qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL, NULL);
                    567:     iscsi_destroy_context(iscsi);
                    568:     memset(iscsilun, 0, sizeof(IscsiLun));
                    569: }
                    570: 
                    571: static BlockDriver bdrv_iscsi = {
                    572:     .format_name     = "iscsi",
                    573:     .protocol_name   = "iscsi",
                    574: 
                    575:     .instance_size   = sizeof(IscsiLun),
                    576:     .bdrv_file_open  = iscsi_open,
                    577:     .bdrv_close      = iscsi_close,
                    578: 
                    579:     .bdrv_getlength  = iscsi_getlength,
                    580: 
                    581:     .bdrv_aio_readv  = iscsi_aio_readv,
                    582:     .bdrv_aio_writev = iscsi_aio_writev,
                    583:     .bdrv_aio_flush  = iscsi_aio_flush,
                    584: };
                    585: 
                    586: static void iscsi_block_init(void)
                    587: {
                    588:     bdrv_register(&bdrv_iscsi);
                    589: }
                    590: 
                    591: block_init(iscsi_block_init);

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.