]> Git Repo - qemu.git/blob - block/iscsi.c
Merge remote-tracking branch 'bonzini/scsi-next' into staging
[qemu.git] / block / iscsi.c
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, 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 void
387 iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
388                      void *command_data, void *opaque)
389 {
390     IscsiAIOCB *acb = opaque;
391
392     if (acb->canceled != 0) {
393         qemu_aio_release(acb);
394         scsi_free_scsi_task(acb->task);
395         acb->task = NULL;
396         return;
397     }
398
399     acb->status = 0;
400     if (status < 0) {
401         error_report("Failed to unmap data on iSCSI lun. %s",
402                      iscsi_get_error(iscsi));
403         acb->status = -EIO;
404     }
405
406     iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
407     scsi_free_scsi_task(acb->task);
408     acb->task = NULL;
409 }
410
411 static BlockDriverAIOCB *
412 iscsi_aio_discard(BlockDriverState *bs,
413                   int64_t sector_num, int nb_sectors,
414                   BlockDriverCompletionFunc *cb, void *opaque)
415 {
416     IscsiLun *iscsilun = bs->opaque;
417     struct iscsi_context *iscsi = iscsilun->iscsi;
418     IscsiAIOCB *acb;
419     struct unmap_list list[1];
420
421     acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
422
423     acb->iscsilun = iscsilun;
424     acb->canceled   = 0;
425
426     list[0].lba = sector_qemu2lun(sector_num, iscsilun);
427     list[0].num = nb_sectors * BDRV_SECTOR_SIZE / iscsilun->block_size;
428
429     acb->task = iscsi_unmap_task(iscsi, iscsilun->lun,
430                                  0, 0, &list[0], 1,
431                                  iscsi_unmap_cb,
432                                  acb);
433     if (acb->task == NULL) {
434         error_report("iSCSI: Failed to send unmap command. %s",
435                      iscsi_get_error(iscsi));
436         qemu_aio_release(acb);
437         return NULL;
438     }
439
440     iscsi_set_events(iscsilun);
441
442     return &acb->common;
443 }
444
445 static int64_t
446 iscsi_getlength(BlockDriverState *bs)
447 {
448     IscsiLun *iscsilun = bs->opaque;
449     int64_t len;
450
451     len  = iscsilun->num_blocks;
452     len *= iscsilun->block_size;
453
454     return len;
455 }
456
457 static void
458 iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
459                         void *command_data, void *opaque)
460 {
461     struct IscsiTask *itask = opaque;
462     struct scsi_readcapacity16 *rc16;
463     struct scsi_task *task = command_data;
464
465     if (status != 0) {
466         error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
467                      iscsi_get_error(iscsi));
468         itask->status   = 1;
469         itask->complete = 1;
470         scsi_free_scsi_task(task);
471         return;
472     }
473
474     rc16 = scsi_datain_unmarshall(task);
475     if (rc16 == NULL) {
476         error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
477         itask->status   = 1;
478         itask->complete = 1;
479         scsi_free_scsi_task(task);
480         return;
481     }
482
483     itask->iscsilun->block_size = rc16->block_length;
484     itask->iscsilun->num_blocks = rc16->returned_lba + 1;
485     itask->bs->total_sectors    = itask->iscsilun->num_blocks *
486                                itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;
487
488     itask->status   = 0;
489     itask->complete = 1;
490     scsi_free_scsi_task(task);
491 }
492
493 static void
494 iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
495                  void *opaque)
496 {
497     struct IscsiTask *itask = opaque;
498     struct scsi_task *task;
499
500     if (status != 0) {
501         itask->status   = 1;
502         itask->complete = 1;
503         return;
504     }
505
506     task = iscsi_readcapacity16_task(iscsi, itask->iscsilun->lun,
507                                    iscsi_readcapacity16_cb, opaque);
508     if (task == NULL) {
509         error_report("iSCSI: failed to send readcapacity16 command.");
510         itask->status   = 1;
511         itask->complete = 1;
512         return;
513     }
514 }
515
516 static int parse_chap(struct iscsi_context *iscsi, const char *target)
517 {
518     QemuOptsList *list;
519     QemuOpts *opts;
520     const char *user = NULL;
521     const char *password = NULL;
522
523     list = qemu_find_opts("iscsi");
524     if (!list) {
525         return 0;
526     }
527
528     opts = qemu_opts_find(list, target);
529     if (opts == NULL) {
530         opts = QTAILQ_FIRST(&list->head);
531         if (!opts) {
532             return 0;
533         }
534     }
535
536     user = qemu_opt_get(opts, "user");
537     if (!user) {
538         return 0;
539     }
540
541     password = qemu_opt_get(opts, "password");
542     if (!password) {
543         error_report("CHAP username specified but no password was given");
544         return -1;
545     }
546
547     if (iscsi_set_initiator_username_pwd(iscsi, user, password)) {
548         error_report("Failed to set initiator username and password");
549         return -1;
550     }
551
552     return 0;
553 }
554
555 static void parse_header_digest(struct iscsi_context *iscsi, const char *target)
556 {
557     QemuOptsList *list;
558     QemuOpts *opts;
559     const char *digest = NULL;
560
561     list = qemu_find_opts("iscsi");
562     if (!list) {
563         return;
564     }
565
566     opts = qemu_opts_find(list, target);
567     if (opts == NULL) {
568         opts = QTAILQ_FIRST(&list->head);
569         if (!opts) {
570             return;
571         }
572     }
573
574     digest = qemu_opt_get(opts, "header-digest");
575     if (!digest) {
576         return;
577     }
578
579     if (!strcmp(digest, "CRC32C")) {
580         iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C);
581     } else if (!strcmp(digest, "NONE")) {
582         iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE);
583     } else if (!strcmp(digest, "CRC32C-NONE")) {
584         iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C_NONE);
585     } else if (!strcmp(digest, "NONE-CRC32C")) {
586         iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
587     } else {
588         error_report("Invalid header-digest setting : %s", digest);
589     }
590 }
591
592 static char *parse_initiator_name(const char *target)
593 {
594     QemuOptsList *list;
595     QemuOpts *opts;
596     const char *name = NULL;
597
598     list = qemu_find_opts("iscsi");
599     if (!list) {
600         return g_strdup("iqn.2008-11.org.linux-kvm");
601     }
602
603     opts = qemu_opts_find(list, target);
604     if (opts == NULL) {
605         opts = QTAILQ_FIRST(&list->head);
606         if (!opts) {
607             return g_strdup("iqn.2008-11.org.linux-kvm");
608         }
609     }
610
611     name = qemu_opt_get(opts, "initiator-name");
612     if (!name) {
613         return g_strdup("iqn.2008-11.org.linux-kvm");
614     }
615
616     return g_strdup(name);
617 }
618
619 /*
620  * We support iscsi url's on the form
621  * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
622  */
623 static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
624 {
625     IscsiLun *iscsilun = bs->opaque;
626     struct iscsi_context *iscsi = NULL;
627     struct iscsi_url *iscsi_url = NULL;
628     struct IscsiTask task;
629     char *initiator_name = NULL;
630     int ret;
631
632     if ((BDRV_SECTOR_SIZE % 512) != 0) {
633         error_report("iSCSI: Invalid BDRV_SECTOR_SIZE. "
634                      "BDRV_SECTOR_SIZE(%lld) is not a multiple "
635                      "of 512", BDRV_SECTOR_SIZE);
636         return -EINVAL;
637     }
638
639     iscsi_url = iscsi_parse_full_url(iscsi, filename);
640     if (iscsi_url == NULL) {
641         error_report("Failed to parse URL : %s %s", filename,
642                      iscsi_get_error(iscsi));
643         ret = -EINVAL;
644         goto failed;
645     }
646
647     memset(iscsilun, 0, sizeof(IscsiLun));
648
649     initiator_name = parse_initiator_name(iscsi_url->target);
650
651     iscsi = iscsi_create_context(initiator_name);
652     if (iscsi == NULL) {
653         error_report("iSCSI: Failed to create iSCSI context.");
654         ret = -ENOMEM;
655         goto failed;
656     }
657
658     if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
659         error_report("iSCSI: Failed to set target name.");
660         ret = -EINVAL;
661         goto failed;
662     }
663
664     if (iscsi_url->user != NULL) {
665         ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user,
666                                               iscsi_url->passwd);
667         if (ret != 0) {
668             error_report("Failed to set initiator username and password");
669             ret = -EINVAL;
670             goto failed;
671         }
672     }
673
674     /* check if we got CHAP username/password via the options */
675     if (parse_chap(iscsi, iscsi_url->target) != 0) {
676         error_report("iSCSI: Failed to set CHAP user/password");
677         ret = -EINVAL;
678         goto failed;
679     }
680
681     if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
682         error_report("iSCSI: Failed to set session type to normal.");
683         ret = -EINVAL;
684         goto failed;
685     }
686
687     iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
688
689     /* check if we got HEADER_DIGEST via the options */
690     parse_header_digest(iscsi, iscsi_url->target);
691
692     task.iscsilun = iscsilun;
693     task.status = 0;
694     task.complete = 0;
695     task.bs = bs;
696
697     iscsilun->iscsi = iscsi;
698     iscsilun->lun   = iscsi_url->lun;
699
700     if (iscsi_full_connect_async(iscsi, iscsi_url->portal, iscsi_url->lun,
701                                  iscsi_connect_cb, &task)
702         != 0) {
703         error_report("iSCSI: Failed to start async connect.");
704         ret = -EINVAL;
705         goto failed;
706     }
707
708     while (!task.complete) {
709         iscsi_set_events(iscsilun);
710         qemu_aio_wait();
711     }
712     if (task.status != 0) {
713         error_report("iSCSI: Failed to connect to LUN : %s",
714                      iscsi_get_error(iscsi));
715         ret = -EINVAL;
716         goto failed;
717     }
718
719     if (iscsi_url != NULL) {
720         iscsi_destroy_url(iscsi_url);
721     }
722     return 0;
723
724 failed:
725     if (initiator_name != NULL) {
726         g_free(initiator_name);
727     }
728     if (iscsi_url != NULL) {
729         iscsi_destroy_url(iscsi_url);
730     }
731     if (iscsi != NULL) {
732         iscsi_destroy_context(iscsi);
733     }
734     memset(iscsilun, 0, sizeof(IscsiLun));
735     return ret;
736 }
737
738 static void iscsi_close(BlockDriverState *bs)
739 {
740     IscsiLun *iscsilun = bs->opaque;
741     struct iscsi_context *iscsi = iscsilun->iscsi;
742
743     qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL);
744     iscsi_destroy_context(iscsi);
745     memset(iscsilun, 0, sizeof(IscsiLun));
746 }
747
748 static BlockDriver bdrv_iscsi = {
749     .format_name     = "iscsi",
750     .protocol_name   = "iscsi",
751
752     .instance_size   = sizeof(IscsiLun),
753     .bdrv_file_open  = iscsi_open,
754     .bdrv_close      = iscsi_close,
755
756     .bdrv_getlength  = iscsi_getlength,
757
758     .bdrv_aio_readv  = iscsi_aio_readv,
759     .bdrv_aio_writev = iscsi_aio_writev,
760     .bdrv_aio_flush  = iscsi_aio_flush,
761
762     .bdrv_aio_discard = iscsi_aio_discard,
763 };
764
765 static void iscsi_block_init(void)
766 {
767     bdrv_register(&bdrv_iscsi);
768 }
769
770 block_init(iscsi_block_init);
This page took 0.064297 seconds and 4 git commands to generate.