9ae3a8
From 2865e534fce4969a316a5ba764b65e540da08cee Mon Sep 17 00:00:00 2001
9ae3a8
Message-Id: <2865e534fce4969a316a5ba764b65e540da08cee.1389014116.git.minovotn@redhat.com>
9ae3a8
In-Reply-To: <c8cc35838d42aa286242772d97e3a9be7bb786ba.1389014116.git.minovotn@redhat.com>
9ae3a8
References: <c8cc35838d42aa286242772d97e3a9be7bb786ba.1389014116.git.minovotn@redhat.com>
9ae3a8
From: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
Date: Mon, 9 Dec 2013 14:08:53 +0100
9ae3a8
Subject: [PATCH 05/50] iscsi: split discard requests in multiple parts
9ae3a8
9ae3a8
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
Message-id: <1386598178-11845-8-git-send-email-pbonzini@redhat.com>
9ae3a8
Patchwork-id: 56044
9ae3a8
O-Subject: [RHEL 7.0 qemu-kvm PATCH 07/52] iscsi: split discard requests in multiple parts
9ae3a8
Bugzilla: 1007815
9ae3a8
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
9ae3a8
RH-Acked-by: Fam Zheng <famz@redhat.com>
9ae3a8
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
9ae3a8
From: Peter Lieven <pl@kamp.de>
9ae3a8
9ae3a8
Replace .bdrv_aio_discard with .bdrv_co_discard so that discard
9ae3a8
requests can be split in multiple parts, each for a small amount
9ae3a8
of sectors.
9ae3a8
9ae3a8
This is useful because we expose a generic API with no limit
9ae3a8
on the amount of sectors that can be unmapped in one request.
9ae3a8
9ae3a8
Signed-off-by: Peter Lieven <pl@kamp.de>
9ae3a8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
(cherry picked from commit 65f3e33964bc4bb634d61463814a4ccca794e3c0)
9ae3a8
---
9ae3a8
 block/iscsi.c | 156 +++++++++++++++++++++++++++-------------------------------
9ae3a8
 1 file changed, 73 insertions(+), 83 deletions(-)
9ae3a8
9ae3a8
Signed-off-by: Michal Novotny <minovotn@redhat.com>
9ae3a8
---
9ae3a8
 block/iscsi.c | 156 +++++++++++++++++++++++++++-------------------------------
9ae3a8
 1 file changed, 73 insertions(+), 83 deletions(-)
9ae3a8
9ae3a8
diff --git a/block/iscsi.c b/block/iscsi.c
9ae3a8
index f8d021a..3a34eb7 100644
9ae3a8
--- a/block/iscsi.c
9ae3a8
+++ b/block/iscsi.c
9ae3a8
@@ -87,6 +87,7 @@ typedef struct IscsiAIOCB {
9ae3a8
 #define NOP_INTERVAL 5000
9ae3a8
 #define MAX_NOP_FAILURES 3
9ae3a8
 #define ISCSI_CMD_RETRIES 5
9ae3a8
+#define ISCSI_MAX_UNMAP 131072
9ae3a8
 
9ae3a8
 static void
9ae3a8
 iscsi_bh_cb(void *p)
9ae3a8
@@ -624,88 +625,6 @@ iscsi_aio_flush(BlockDriverState *bs,
9ae3a8
     return &acb->common;
9ae3a8
 }
9ae3a8
 
9ae3a8
-static int iscsi_aio_discard_acb(IscsiAIOCB *acb);
9ae3a8
-
9ae3a8
-static void
9ae3a8
-iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
9ae3a8
-                     void *command_data, void *opaque)
9ae3a8
-{
9ae3a8
-    IscsiAIOCB *acb = opaque;
9ae3a8
-
9ae3a8
-    if (acb->canceled != 0) {
9ae3a8
-        return;
9ae3a8
-    }
9ae3a8
-
9ae3a8
-    acb->status = 0;
9ae3a8
-    if (status != 0) {
9ae3a8
-        if (status == SCSI_STATUS_CHECK_CONDITION
9ae3a8
-            && acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
9ae3a8
-            && acb->retries-- > 0) {
9ae3a8
-            scsi_free_scsi_task(acb->task);
9ae3a8
-            acb->task = NULL;
9ae3a8
-            if (iscsi_aio_discard_acb(acb) == 0) {
9ae3a8
-                iscsi_set_events(acb->iscsilun);
9ae3a8
-                return;
9ae3a8
-            }
9ae3a8
-        }
9ae3a8
-        error_report("Failed to unmap data on iSCSI lun. %s",
9ae3a8
-                     iscsi_get_error(iscsi));
9ae3a8
-        acb->status = -EIO;
9ae3a8
-    }
9ae3a8
-
9ae3a8
-    iscsi_schedule_bh(acb);
9ae3a8
-}
9ae3a8
-
9ae3a8
-static int iscsi_aio_discard_acb(IscsiAIOCB *acb) {
9ae3a8
-    struct iscsi_context *iscsi = acb->iscsilun->iscsi;
9ae3a8
-    struct unmap_list list[1];
9ae3a8
-
9ae3a8
-    acb->canceled   = 0;
9ae3a8
-    acb->bh         = NULL;
9ae3a8
-    acb->status     = -EINPROGRESS;
9ae3a8
-    acb->buf        = NULL;
9ae3a8
-
9ae3a8
-    list[0].lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
9ae3a8
-    list[0].num = acb->nb_sectors * BDRV_SECTOR_SIZE / acb->iscsilun->block_size;
9ae3a8
-
9ae3a8
-    acb->task = iscsi_unmap_task(iscsi, acb->iscsilun->lun,
9ae3a8
-                                 0, 0, &list[0], 1,
9ae3a8
-                                 iscsi_unmap_cb,
9ae3a8
-                                 acb);
9ae3a8
-    if (acb->task == NULL) {
9ae3a8
-        error_report("iSCSI: Failed to send unmap command. %s",
9ae3a8
-                     iscsi_get_error(iscsi));
9ae3a8
-        return -1;
9ae3a8
-    }
9ae3a8
-
9ae3a8
-    return 0;
9ae3a8
-}
9ae3a8
-
9ae3a8
-static BlockDriverAIOCB *
9ae3a8
-iscsi_aio_discard(BlockDriverState *bs,
9ae3a8
-                  int64_t sector_num, int nb_sectors,
9ae3a8
-                  BlockDriverCompletionFunc *cb, void *opaque)
9ae3a8
-{
9ae3a8
-    IscsiLun *iscsilun = bs->opaque;
9ae3a8
-    IscsiAIOCB *acb;
9ae3a8
-
9ae3a8
-    acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
9ae3a8
-
9ae3a8
-    acb->iscsilun    = iscsilun;
9ae3a8
-    acb->nb_sectors  = nb_sectors;
9ae3a8
-    acb->sector_num  = sector_num;
9ae3a8
-    acb->retries     = ISCSI_CMD_RETRIES;
9ae3a8
-
9ae3a8
-    if (iscsi_aio_discard_acb(acb) != 0) {
9ae3a8
-        qemu_aio_release(acb);
9ae3a8
-        return NULL;
9ae3a8
-    }
9ae3a8
-
9ae3a8
-    iscsi_set_events(iscsilun);
9ae3a8
-
9ae3a8
-    return &acb->common;
9ae3a8
-}
9ae3a8
-
9ae3a8
 #ifdef __linux__
9ae3a8
 static void
9ae3a8
 iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
9ae3a8
@@ -988,6 +907,77 @@ out:
9ae3a8
     return ret;
9ae3a8
 }
9ae3a8
 
9ae3a8
+static int
9ae3a8
+coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,
9ae3a8
+                                   int nb_sectors)
9ae3a8
+{
9ae3a8
+    IscsiLun *iscsilun = bs->opaque;
9ae3a8
+    struct IscsiTask iTask;
9ae3a8
+    struct unmap_list list;
9ae3a8
+    uint32_t nb_blocks;
9ae3a8
+    uint32_t max_unmap;
9ae3a8
+
9ae3a8
+    if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
9ae3a8
+        return -EINVAL;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    if (!iscsilun->lbp.lbpu) {
9ae3a8
+        /* UNMAP is not supported by the target */
9ae3a8
+        return 0;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    list.lba = sector_qemu2lun(sector_num, iscsilun);
9ae3a8
+    nb_blocks = sector_qemu2lun(nb_sectors, iscsilun);
9ae3a8
+
9ae3a8
+    max_unmap = iscsilun->bl.max_unmap;
9ae3a8
+    if (max_unmap == 0xffffffff) {
9ae3a8
+        max_unmap = ISCSI_MAX_UNMAP;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    while (nb_blocks > 0) {
9ae3a8
+        iscsi_co_init_iscsitask(iscsilun, &iTask);
9ae3a8
+        list.num = nb_blocks;
9ae3a8
+        if (list.num > max_unmap) {
9ae3a8
+            list.num = max_unmap;
9ae3a8
+        }
9ae3a8
+retry:
9ae3a8
+        if (iscsi_unmap_task(iscsilun->iscsi, iscsilun->lun, 0, 0, &list, 1,
9ae3a8
+                         iscsi_co_generic_cb, &iTask) == NULL) {
9ae3a8
+            return -EIO;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        while (!iTask.complete) {
9ae3a8
+            iscsi_set_events(iscsilun);
9ae3a8
+            qemu_coroutine_yield();
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        if (iTask.task != NULL) {
9ae3a8
+            scsi_free_scsi_task(iTask.task);
9ae3a8
+            iTask.task = NULL;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        if (iTask.do_retry) {
9ae3a8
+            goto retry;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        if (iTask.status == SCSI_STATUS_CHECK_CONDITION) {
9ae3a8
+            /* the target might fail with a check condition if it
9ae3a8
+               is not happy with the alignment of the UNMAP request
9ae3a8
+               we silently fail in this case */
9ae3a8
+            return 0;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        if (iTask.status != SCSI_STATUS_GOOD) {
9ae3a8
+            return -EIO;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        list.lba += list.num;
9ae3a8
+        nb_blocks -= list.num;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    return 0;
9ae3a8
+}
9ae3a8
+
9ae3a8
 static int parse_chap(struct iscsi_context *iscsi, const char *target)
9ae3a8
 {
9ae3a8
     QemuOptsList *list;
9ae3a8
@@ -1541,12 +1531,12 @@ static BlockDriver bdrv_iscsi = {
9ae3a8
     .bdrv_truncate   = iscsi_truncate,
9ae3a8
 
9ae3a8
     .bdrv_co_get_block_status = iscsi_co_get_block_status,
9ae3a8
+    .bdrv_co_discard      = iscsi_co_discard,
9ae3a8
 
9ae3a8
     .bdrv_aio_readv  = iscsi_aio_readv,
9ae3a8
     .bdrv_aio_writev = iscsi_aio_writev,
9ae3a8
     .bdrv_aio_flush  = iscsi_aio_flush,
9ae3a8
 
9ae3a8
-    .bdrv_aio_discard = iscsi_aio_discard,
9ae3a8
     .bdrv_has_zero_init = iscsi_has_zero_init,
9ae3a8
 
9ae3a8
 #ifdef __linux__
9ae3a8
-- 
9ae3a8
1.7.11.7
9ae3a8