|
|
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);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.