diff mbox

[2/2] iscsi: add intelligent has_zero_init check

Message ID 1371752409-16313-3-git-send-email-pl@kamp.de
State New
Headers show

Commit Message

Peter Lieven June 20, 2013, 6:20 p.m. UTC
iscsi targets are not created by bdrv_create and thus we cannot
blindly assume that a target is empty. to avoid writing and allocating
blocks of zeroes we now check if all blocks of an existing target
are unallocated and return 1 for bdrv_has_zero_init if the
target is completely unalloacted and unallocated blocks read
as zeroes.

Signed-off-by: Peter Lieven <pl@kamp.de>
---
 block/iscsi.c |   25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

Comments

Paolo Bonzini June 21, 2013, 8 p.m. UTC | #1
Il 20/06/2013 20:20, Peter Lieven ha scritto:
> +    for (lba = 0; lba < iscsilun->num_blocks; lba += 1 << 26) {
> +        nb_sectors = 1 << 26;
> +        if (lba + nb_sectors > iscsilun->num_blocks) {
> +            nb_sectors = iscsilun->num_blocks - lba;
> +        }
> +        nb_sectors *= (iscsilun->block_size / BDRV_SECTOR_SIZE);
> +        n = 0;
> +        ret = iscsi_co_is_allocated(bs, lba, nb_sectors, &n);
> +        if (ret || n != nb_sectors) {
> +            return 0;
> +        }

I would just do lba += n in the for loop, and only exit if n == 0.  The
SCSI spec does not forbid splitting a single allocated area into
multiple descriptors, or only returning part of an allocated area into
the last descriptor.

Otherwise looks good, but you may want to cache the result.  It would
not be 1 anymore after the first write.

Paolo
Peter Lieven June 21, 2013, 8:25 p.m. UTC | #2
Von meinem iPhone gesendet

Am 21.06.2013 um 22:00 schrieb Paolo Bonzini <pbonzini@redhat.com>:

> Il 20/06/2013 20:20, Peter Lieven ha scritto:
>> +    for (lba = 0; lba < iscsilun->num_blocks; lba += 1 << 26) {
>> +        nb_sectors = 1 << 26;
>> +        if (lba + nb_sectors > iscsilun->num_blocks) {
>> +            nb_sectors = iscsilun->num_blocks - lba;
>> +        }
>> +        nb_sectors *= (iscsilun->block_size / BDRV_SECTOR_SIZE);
>> +        n = 0;
>> +        ret = iscsi_co_is_allocated(bs, lba, nb_sectors, &n);
>> +        if (ret || n != nb_sectors) {
>> +            return 0;
>> +        }
> 
> I would just do lba += n in the for loop, and only exit if n == 0.  The
> SCSI spec does not forbid splitting a single allocated area into
> multiple descriptors, or only returning part of an allocated area into
> the last descriptor.
> 
> Otherwise looks good, but you may want to cache the result.  It would
> not be 1 anymore after the first write.
> 

Of course, but after some discussions with Kevin we might have found a better Solution than extending has_zero_init this far. 

Let you know soon :-)

> Paolo
diff mbox

Patch

diff --git a/block/iscsi.c b/block/iscsi.c
index e6b966d..fe41d9a 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -50,6 +50,7 @@  typedef struct IscsiLun {
     int events;
     QEMUTimer *nop_timer;
     uint8_t lbpme;
+    uint8_t lbprz;
 } IscsiLun;
 
 typedef struct IscsiAIOCB {
@@ -1004,6 +1005,7 @@  static int iscsi_readcapacity_sync(IscsiLun *iscsilun)
                     iscsilun->block_size = rc16->block_length;
                     iscsilun->num_blocks = rc16->returned_lba + 1;
                     iscsilun->lbpme = rc16->lbpme;
+                    iscsilun->lbprz = rc16->lbprz;
                 }
             }
             break;
@@ -1249,7 +1251,28 @@  static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
 
 static int iscsi_has_zero_init(BlockDriverState *bs)
 {
-    return 0;
+    IscsiLun *iscsilun = bs->opaque;
+    uint64_t lba;
+    int n, ret, nb_sectors;
+
+    if (iscsilun->lbprz == 0) {
+        return 0;
+    }
+
+    for (lba = 0; lba < iscsilun->num_blocks; lba += 1 << 26) {
+        nb_sectors = 1 << 26;
+        if (lba + nb_sectors > iscsilun->num_blocks) {
+            nb_sectors = iscsilun->num_blocks - lba;
+        }
+        nb_sectors *= (iscsilun->block_size / BDRV_SECTOR_SIZE);
+        n = 0;
+        ret = iscsi_co_is_allocated(bs, lba, nb_sectors, &n);
+        if (ret || n != nb_sectors) {
+            return 0;
+        }
+    }
+
+    return 1;
 }
 
 static int iscsi_create(const char *filename, QEMUOptionParameter *options)