Skip to contentSkip to conversation

Block patches for master

GIT PULL New Kevin Wolf 3 participants 16 messages Feb 10, 2011 – Feb 16, 2011 Block layer

lore
Share & tools
lore

Kevin Wolf

author
#0 lore raw

The following changes since commit 6c5f738daec123020d32543fe90a6633a4f6643e:

microblaze: Handle singlestepping over direct jmps (2011-02-10 00:46:09 +0100)

are available in the git repository at:
git://repo.or.cz/qemu/kevin.git for-anthony

Chunqiang Tang (1):
QCOW2: bug fix - read base image beyond its size

Jes Sorensen (1):
Change snapshot_blkdev hmp to use correct argument type for device

Kevin Wolf (7):
qcow2: Fix error handling for immediate backing file read failure
qcow2: Fix error handling for reading compressed clusters
qerror: Add QERR_UNKNOWN_BLOCK_FORMAT_FEATURE
qcow2: Report error for version > 2
qed: Report error for unsupported features
qemu-img: Improve error messages for failed bdrv_open
qcow2: Fix order in L2 table COW

Markus Armbruster (2):
blockdev: Plug memory leak in drive_uninit()
blockdev: Plug memory leak in drive_init() error paths

 block/qcow2-cluster.c |   13 ++++++++-----
 block/qcow2.c         |   26 +++++++++++++++++++-------
 block/qed.c           |    9 ++++++++-
 blockdev.c            |   12 ++++++++++--
 cutils.c              |   31 +++++++++++++++++++++++++++++++
 hmp-commands.hx       |    2 +-
 qemu-common.h         |    2 ++
 qemu-img.c            |   10 +++++++---
 qerror.c              |    5 +++++
 qerror.h              |    3 +++
 10 files changed, 94 insertions(+), 19 deletions(-)
author
#1 lore raw

PATCH 1/11 Change snapshot_blkdev hmp to use correct argument type for device

From: Jes Sorensen <[email protected]>

Pointed out by Markus

---
 hmp-commands.hx |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
hmp-commands.hx +1 -1
index 38e1eb7..372bef4 100644
@@ -822,7 +822,7 @@ ETEXI
 
     {
         .name       = "snapshot_blkdev",
-        .args_type  = "device:s,snapshot_file:s?,format:s?",
+        .args_type  = "device:B,snapshot_file:s?,format:s?",
         .params     = "device [new-image-file] [format]",
         .help       = "initiates a live snapshot\n\t\t\t"
                       "of device. If a new image file is specified, the\n\t\t\t"
Signature · 1 line
1.7.2.3
author
#2 lore raw

PATCH 2/11 QCOW2: bug fix - read base image beyond its size

In reply to Kevin Wolf

From: Chunqiang Tang <[email protected]>

This patch fixes the following bug in QCOW2. For a QCOW2 image that is larger than its base image, when handling a read request straddling over the end of the base image, the QCOW2 driver attempts to read beyond the end of the base image and the request would fail.

This bug was found by Fast Virtual Disk (FVD)'s fully automated testing tool. The following test triggered the bug.

dd if=/dev/zero of=/var/ramdisk/truth.raw count=0 bs=1 seek=1098561536
dd if=/dev/zero of=/var/ramdisk/zero-500M.raw count=0 bs=1 seek=593099264
./qemu-img create -f qcow2 -ocluster_size=65536,backing_fmt=blksim -b /var/ramdisk/zero-500M.raw /var/ramdisk/test.qcow2 1098561536
./qemu-io --auto --seed=30477694 --truth=/var/ramdisk/truth.raw --format=qcow2 --test=blksim:/var/ramdisk/test.qcow2 --verify_write=true --compare_before=false --compare_after=true --round=100000 --parallel=100 --io_size=10485760 --fail_prob=0 --cancel_prob=0 --instant_qemubh=true

---
 block/qcow2.c |    5 ++---
 cutils.c      |   31 +++++++++++++++++++++++++++++++
 qemu-common.h |    2 ++
 3 files changed, 35 insertions(+), 3 deletions(-)
block/qcow2.c +2 -3
index a1773e4..28338bf 100644
@@ -355,7 +355,7 @@ int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
     else
         n1 = bs->total_sectors - sector_num;
 
-    qemu_iovec_memset(qiov, 0, 512 * (nb_sectors - n1));
+    qemu_iovec_memset_skip(qiov, 0, 512 * (nb_sectors - n1), 512 * n1);
 
     return n1;
 }
@@ -478,8 +478,7 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
             if (n1 > 0) {
                 BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
                 acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
-                                    &acb->hd_qiov, acb->cur_nr_sectors,
-				    qcow2_aio_read_cb, acb);
+                                    &acb->hd_qiov, n1, qcow2_aio_read_cb, acb);
                 if (acb->hd_aiocb == NULL)
                     goto done;
             } else {
cutils.c +31 -0
index 8d562b2..f9a7e36 100644
@@ -267,6 +267,37 @@ void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count)
     }
 }
 
+void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
+                            size_t skip)
+{
+    int i;
+    size_t done;
+    void *iov_base;
+    uint64_t iov_len;
+
+    done = 0;
+    for (i = 0; (i < qiov->niov) && (done != count); i++) {
+        if (skip >= qiov->iov[i].iov_len) {
+            /* Skip the whole iov */
+            skip -= qiov->iov[i].iov_len;
+            continue;
+        } else {
+            /* Skip only part (or nothing) of the iov */
+            iov_base = (uint8_t*) qiov->iov[i].iov_base + skip;
+            iov_len = qiov->iov[i].iov_len - skip;
+            skip = 0;
+        }
+
+        if (done + iov_len > count) {
+            memset(iov_base, c, count - done);
+            break;
+        } else {
+            memset(iov_base, c, iov_len);
+        }
+        done += iov_len;
+    }
+}
+
 #ifndef _WIN32
 /* Sets a specific flag */
 int fcntl_setfl(int fd, int flag)
qemu-common.h +2 -0
index c7ff280..cb4b7e0 100644
@@ -322,6 +322,8 @@ void qemu_iovec_reset(QEMUIOVector *qiov);
 void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf);
 void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count);
 void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count);
+void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
+                            size_t skip);
 
 struct Monitor;
 typedef struct Monitor Monitor;
Signature · 1 line
1.7.2.3
author
#3 lore raw

PATCH 3/11 qcow2: Fix error handling for immediate backing file read failure

In reply to Kevin Wolf

Requests could return success even though they failed when bdrv_aio_readv returned NULL for a backing file read.

---
 block/qcow2.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
block/qcow2.c +3 -1
index 28338bf..647c2a4 100644
@@ -479,8 +479,10 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
                 BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
                 acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
                                     &acb->hd_qiov, n1, qcow2_aio_read_cb, acb);
-                if (acb->hd_aiocb == NULL)
+                if (acb->hd_aiocb == NULL) {
+                    ret = -EIO;
                     goto done;
+                }
             } else {
                 ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
                 if (ret < 0)
Signature · 1 line
1.7.2.3
author
#4 lore raw

PATCH 4/11 qcow2: Fix error handling for reading compressed clusters

In reply to Kevin Wolf

When reading a compressed cluster failed, qcow2 falsely returned success.

---
 block/qcow2-cluster.c |    4 ++--
 block/qcow2.c         |    4 +++-
 2 files changed, 5 insertions(+), 3 deletions(-)
block/qcow2-cluster.c +2 -2
index 5fb8c66..437aaa8 100644
@@ -878,11 +878,11 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
         BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
         ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data, nb_csectors);
         if (ret < 0) {
-            return -1;
+            return ret;
         }
         if (decompress_buffer(s->cluster_cache, s->cluster_size,
                               s->cluster_data + sector_offset, csize) < 0) {
-            return -1;
+            return -EIO;
         }
         s->cluster_cache_offset = coffset;
     }
block/qcow2.c +3 -1
index 647c2a4..551b3c2 100644
@@ -497,8 +497,10 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
         }
     } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
         /* add AIO support for compressed blocks ? */
-        if (qcow2_decompress_cluster(bs, acb->cluster_offset) < 0)
+        ret = qcow2_decompress_cluster(bs, acb->cluster_offset);
+        if (ret < 0) {
             goto done;
+        }
 
         qemu_iovec_from_buffer(&acb->hd_qiov,
             s->cluster_cache + index_in_cluster * 512,
Signature · 1 line
1.7.2.3
author
#5 lore raw

PATCH 5/11 qerror: Add QERR_UNKNOWN_BLOCK_FORMAT_FEATURE

In reply to Kevin Wolf
---
 qerror.c |    5 +++++
 qerror.h |    3 +++
 2 files changed, 8 insertions(+), 0 deletions(-)
qerror.c +5 -0
index 9d0cdeb..4855604 100644
@@ -201,6 +201,11 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "An undefined error has ocurred",
     },
     {
+        .error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+        .desc      = "'%(device)' uses a %(format) feature which is not "
+                     "supported by this qemu version: %(feature)",
+    },
+    {
         .error_fmt = QERR_VNC_SERVER_FAILED,
         .desc      = "Could not start VNC server on %(target)",
     },
qerror.h +3 -0
index b0f69da..f732d45 100644
@@ -165,6 +165,9 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_UNDEFINED_ERROR \
     "{ 'class': 'UndefinedError', 'data': {} }"
 
+#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
+    "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
+
 #define QERR_VNC_SERVER_FAILED \
     "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
 
Signature · 1 line
1.7.2.3
author
#6 lore raw

PATCH 6/11 qcow2: Report error for version > 2

In reply to Kevin Wolf

The qcow2 driver is now declared responsible for any QCOW image that has version 2 or greater (before this, version 3 would be detected as raw).

For everything newer than version 2, an error is reported.

---
 block/qcow2.c |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)
block/qcow2.c +11 -2
index 551b3c2..75b8bec 100644
@@ -28,6 +28,7 @@
 #include "aes.h"
 #include "block/qcow2.h"
 #include "qemu-error.h"
+#include "qerror.h"
 
 /*
   Differences with QCOW:
@@ -59,7 +60,7 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
 
     if (buf_size >= sizeof(QCowHeader) &&
         be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
-        be32_to_cpu(cow_header->version) == QCOW_VERSION)
+        be32_to_cpu(cow_header->version) >= QCOW_VERSION)
         return 100;
     else
         return 0;
@@ -163,10 +164,18 @@ static int qcow2_open(BlockDriverState *bs, int flags)
     be64_to_cpus(&header.snapshots_offset);
     be32_to_cpus(&header.nb_snapshots);
 
-    if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION) {
+    if (header.magic != QCOW_MAGIC) {
         ret = -EINVAL;
         goto fail;
     }
+    if (header.version != QCOW_VERSION) {
+        char version[64];
+        snprintf(version, sizeof(version), "QCOW version %d", header.version);
+        qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+            bs->device_name, "qcow2", version);
+        ret = -ENOTSUP;
+        goto fail;
+    }
     if (header.cluster_bits < MIN_CLUSTER_BITS ||
         header.cluster_bits > MAX_CLUSTER_BITS) {
         ret = -EINVAL;
Signature · 1 line
1.7.2.3
author
#7 lore raw

PATCH 7/11 qed: Report error for unsupported features

In reply to Kevin Wolf

Instead of just returning -ENOTSUP, generate a more detailed error.

Unfortunately we don't have a helpful text for features that we don't know yet, so just print the feature mask. It might be useful at least if someone asks for help.

---
 block/qed.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)
block/qed.c +8 -1
index 3273448..75ae244 100644
@@ -14,6 +14,7 @@
 
 #include "trace.h"
 #include "qed.h"
+#include "qerror.h"
 
 static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
 {
@@ -311,7 +312,13 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
         return -EINVAL;
     }
     if (s->header.features & ~QED_FEATURE_MASK) {
-        return -ENOTSUP; /* image uses unsupported feature bits */
+        /* image uses unsupported feature bits */
+        char buf[64];
+        snprintf(buf, sizeof(buf), "%" PRIx64,
+            s->header.features & ~QED_FEATURE_MASK);
+        qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+            bs->device_name, "QED", buf);
+        return -ENOTSUP;
     }
     if (!qed_is_cluster_size_valid(s->header.cluster_size)) {
         return -EINVAL;
Signature · 1 line
1.7.2.3
author
#8 lore raw

PATCH 8/11 qemu-img: Improve error messages for failed bdrv_open

In reply to Kevin Wolf

Output the error message string of the bdrv_open return code. Also set a non-empty device name for the images because the unknown feature error message includes it.

---
 qemu-img.c |   10 +++++++---
 1 files changed, 7 insertions(+), 3 deletions(-)
qemu-img.c +7 -3
index 4a37358..7e3cc4c 100644
@@ -213,8 +213,9 @@ static BlockDriverState *bdrv_new_open(const char *filename,
     BlockDriverState *bs;
     BlockDriver *drv;
     char password[256];
+    int ret;
 
-    bs = bdrv_new("");
+    bs = bdrv_new("image");
 
     if (fmt) {
         drv = bdrv_find_format(fmt);
@@ -225,10 +226,13 @@ static BlockDriverState *bdrv_new_open(const char *filename,
     } else {
         drv = NULL;
     }
-    if (bdrv_open(bs, filename, flags, drv) < 0) {
-        error_report("Could not open '%s'", filename);
+
+    ret = bdrv_open(bs, filename, flags, drv);
+    if (ret < 0) {
+        error_report("Could not open '%s': %s", filename, strerror(-ret));
         goto fail;
     }
+
     if (bdrv_is_encrypted(bs)) {
         printf("Disk image '%s' is encrypted.\n", filename);
         if (read_password(password, sizeof(password)) < 0) {
Signature · 1 line
1.7.2.3
author
#9 lore raw

PATCH 9/11 blockdev: Plug memory leak in drive_uninit()

In reply to Kevin Wolf

From: Markus Armbruster <[email protected]>

Started leaking in commit 1dae12e6.

---
 blockdev.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
blockdev.c +1 -0
index ecfadc1..24d7658 100644
@@ -182,6 +182,7 @@ static void drive_uninit(DriveInfo *dinfo)
 {
     qemu_opts_del(dinfo->opts);
     bdrv_delete(dinfo->bdrv);
+    qemu_free(dinfo->id);
     QTAILQ_REMOVE(&drives, dinfo, next);
     qemu_free(dinfo);
 }
Signature · 1 line
1.7.2.3
author
#10 lore raw

PATCH 10/11 blockdev: Plug memory leak in drive_init() error paths

In reply to Kevin Wolf

From: Markus Armbruster <[email protected]>

Should have spotted this when doing commit 319ae529.

---
 blockdev.c |   11 +++++++++--
 1 files changed, 9 insertions(+), 2 deletions(-)
blockdev.c +9 -2
index 24d7658..0690cc8 100644
@@ -526,7 +526,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
     } else if (ro == 1) {
         if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) {
             error_report("readonly not supported by this bus type");
-            return NULL;
+            goto err;
         }
     }
 
@@ -536,12 +536,19 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
     if (ret < 0) {
         error_report("could not open disk image %s: %s",
                      file, strerror(-ret));
-        return NULL;
+        goto err;
     }
 
     if (bdrv_key_required(dinfo->bdrv))
         autostart = 0;
     return dinfo;
+
+err:
+    bdrv_delete(dinfo->bdrv);
+    qemu_free(dinfo->id);
+    QTAILQ_REMOVE(&drives, dinfo, next);
+    qemu_free(dinfo);
+    return NULL;
 }
 
 void do_commit(Monitor *mon, const QDict *qdict)
Signature · 1 line
1.7.2.3
author
#11 lore raw

PATCH 11/11 qcow2: Fix order in L2 table COW

In reply to Kevin Wolf

When copying L2 tables (this happens only with internal snapshots), the order wasn't completely safe, so that after a crash you could end up with a L2 table that has too low refcount, possibly leading to corruption in the long run.

This patch puts the operations in the right order: First allocate the new L2 table and replace the reference, and only then decrease the refcount of the old table.

---
 block/qcow2-cluster.c |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)
block/qcow2-cluster.c +6 -3
index 437aaa8..750abe3 100644
@@ -515,13 +515,16 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
             return ret;
         }
     } else {
-        /* FIXME Order */
-        if (l2_offset)
-            qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
+        /* First allocate a new L2 table (and do COW if needed) */
         ret = l2_allocate(bs, l1_index, &l2_table);
         if (ret < 0) {
             return ret;
         }
+
+        /* Then decrease the refcount of the old table */
+        if (l2_offset) {
+            qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
+        }
         l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
     }
 
Signature · 1 line
1.7.2.3
#12 lore raw
In reply to Kevin Wolf
Quoted 7 lines · Kevin Wolf

The following changes since commit 6c5f738daec123020d32543fe90a6633a4f6643e:

microblaze: Handle singlestepping over direct jmps (2011-02-10 00:46:09 +0100)

are available in the git repository at:
git://repo.or.cz/qemu/kevin.git for-anthony

Pulled. Thanks.

Regards,

Anthony Liguori

Quoted 33 lines

Chunqiang Tang (1):
QCOW2: bug fix - read base image beyond its size

Jes Sorensen (1):
Change snapshot_blkdev hmp to use correct argument type for device

Kevin Wolf (7):
qcow2: Fix error handling for immediate backing file read failure
qcow2: Fix error handling for reading compressed clusters
qerror: Add QERR_UNKNOWN_BLOCK_FORMAT_FEATURE
qcow2: Report error for version> 2
qed: Report error for unsupported features
qemu-img: Improve error messages for failed bdrv_open
qcow2: Fix order in L2 table COW

Markus Armbruster (2):
blockdev: Plug memory leak in drive_uninit()
blockdev: Plug memory leak in drive_init() error paths

  block/qcow2-cluster.c |   13 ++++++++-----
  block/qcow2.c         |   26 +++++++++++++++++++-------
  block/qed.c           |    9 ++++++++-
  blockdev.c            |   12 ++++++++++--
  cutils.c              |   31 +++++++++++++++++++++++++++++++
  hmp-commands.hx       |    2 +-
  qemu-common.h         |    2 ++
  qemu-img.c            |   10 +++++++---
  qerror.c              |    5 +++++
  qerror.h              |    3 +++
  10 files changed, 94 insertions(+), 19 deletions(-)
author
#13 lore raw

Am 14.02.2011 21:17, schrieb Anthony Liguori:

Quoted 10 lines · Kevin Wolf
Quoted 7 lines

The following changes since commit 6c5f738daec123020d32543fe90a6633a4f6643e:

microblaze: Handle singlestepping over direct jmps (2011-02-10 00:46:09 +0100)

are available in the git repository at:
git://repo.or.cz/qemu/kevin.git for-anthony

Pulled. Thanks.

Are you sure? I don't see the commits in master.

Kevin

Quoted 30 lines
Quoted 30 lines

Chunqiang Tang (1):
QCOW2: bug fix - read base image beyond its size

Jes Sorensen (1):
Change snapshot_blkdev hmp to use correct argument type for device

Kevin Wolf (7):
qcow2: Fix error handling for immediate backing file read failure
qcow2: Fix error handling for reading compressed clusters
qerror: Add QERR_UNKNOWN_BLOCK_FORMAT_FEATURE
qcow2: Report error for version> 2
qed: Report error for unsupported features
qemu-img: Improve error messages for failed bdrv_open
qcow2: Fix order in L2 table COW

Markus Armbruster (2):
blockdev: Plug memory leak in drive_uninit()
blockdev: Plug memory leak in drive_init() error paths

  block/qcow2-cluster.c |   13 ++++++++-----
  block/qcow2.c         |   26 +++++++++++++++++++-------
  block/qed.c           |    9 ++++++++-
  blockdev.c            |   12 ++++++++++--
  cutils.c              |   31 +++++++++++++++++++++++++++++++
  hmp-commands.hx       |    2 +-
  qemu-common.h         |    2 ++
  qemu-img.c            |   10 +++++++---
  qerror.c              |    5 +++++
  qerror.h              |    3 +++
  10 files changed, 94 insertions(+), 19 deletions(-)
#14 lore raw
Quoted 6 lines · Kevin Wolf

Am 14.02.2011 21:17, schrieb Anthony Liguori:

Quoted 5 lines · Kevin Wolf
Quoted 4 lines

The following changes since commit 6c5f738daec123020d32543fe90a6633a4f6643e:

    microblaze: Handle singlestepping over direct jmps (2011-02-10 00:46:09 +0100)
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

are available in the git repository at:
git://repo.or.cz/qemu/kevin.git for-anthony

Pulled. Thanks.

Are you sure? I don't see the commits in master.

The commits from the uq/master pull aren't there, either.

Paolo

#15 lore raw
Quoted 12 lines · Paolo Bonzini
Quoted 11 lines · Kevin Wolf

Am 14.02.2011 21:17, schrieb Anthony Liguori:

Quoted 10 lines · Kevin Wolf
Quoted 8 lines

The following changes since commit 6c5f738daec123020d32543fe90a6633a4f6643e:

microblaze: Handle singlestepping over direct jmps (2011-02-10
00:46:09 +0100)

are available in the git repository at:
git://repo.or.cz/qemu/kevin.git for-anthony

Quoted 5 lines
Quoted 3 lines
Quoted 1 line

Pulled. Thanks.

Are you sure? I don't see the commits in master.

The commits from the uq/master pull aren't there, either.

Yeah, I messed up locally and pushed the wrong branch. Fixed now.

Regards,

Anthony Liguori

Quoted 3 lines

Paolo