qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [7019] remove bdrv_aio_read/bdrv_aio_write (Christoph Hellw


From: Anthony Liguori
Subject: [Qemu-devel] [7019] remove bdrv_aio_read/bdrv_aio_write (Christoph Hellwig)
Date: Tue, 07 Apr 2009 18:43:21 +0000

Revision: 7019
          http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=7019
Author:   aliguori
Date:     2009-04-07 18:43:20 +0000 (Tue, 07 Apr 2009)
Log Message:
-----------
remove bdrv_aio_read/bdrv_aio_write (Christoph Hellwig)

Always use the vectored APIs to reduce code churn once we switch the BlockDriver
API to be vectored.


Signed-off-by: Christoph Hellwig <address@hidden>
Signed-off-by: Anthony Liguori <address@hidden>

Modified Paths:
--------------
    trunk/block-qcow.c
    trunk/block-qcow2.c
    trunk/block.c
    trunk/block.h
    trunk/hw/ide.c
    trunk/hw/scsi-disk.c

Modified: trunk/block-qcow.c
===================================================================
--- trunk/block-qcow.c  2009-04-07 18:23:51 UTC (rev 7018)
+++ trunk/block-qcow.c  2009-04-07 18:43:20 UTC (rev 7019)
@@ -530,6 +530,8 @@
     int n;
     uint64_t cluster_offset;
     uint8_t *cluster_data;
+    struct iovec hd_iov;
+    QEMUIOVector hd_qiov;
     BlockDriverAIOCB *hd_aiocb;
 } QCowAIOCB;
 
@@ -584,8 +586,11 @@
     if (!acb->cluster_offset) {
         if (bs->backing_hd) {
             /* read from the base image */
-            acb->hd_aiocb = bdrv_aio_read(bs->backing_hd,
-                acb->sector_num, acb->buf, acb->n, qcow_aio_read_cb, acb);
+            acb->hd_iov.iov_base = acb->buf;
+            acb->hd_iov.iov_len = acb->n * 512;
+            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+            acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
+                &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
             if (acb->hd_aiocb == NULL)
                 goto fail;
         } else {
@@ -605,9 +610,12 @@
             ret = -EIO;
             goto fail;
         }
-        acb->hd_aiocb = bdrv_aio_read(s->hd,
+        acb->hd_iov.iov_base = acb->buf;
+        acb->hd_iov.iov_len = acb->n * 512;
+        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+        acb->hd_aiocb = bdrv_aio_readv(s->hd,
                             (acb->cluster_offset >> 9) + index_in_cluster,
-                            acb->buf, acb->n, qcow_aio_read_cb, acb);
+                            &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
         if (acb->hd_aiocb == NULL)
             goto fail;
     }
@@ -687,10 +695,14 @@
     } else {
         src_buf = acb->buf;
     }
-    acb->hd_aiocb = bdrv_aio_write(s->hd,
-                                   (cluster_offset >> 9) + index_in_cluster,
-                                   src_buf, acb->n,
-                                   qcow_aio_write_cb, acb);
+
+    acb->hd_iov.iov_base = (void *)src_buf;
+    acb->hd_iov.iov_len = acb->n * 512;
+    qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+    acb->hd_aiocb = bdrv_aio_writev(s->hd,
+                                    (cluster_offset >> 9) + index_in_cluster,
+                                    &acb->hd_qiov, acb->n,
+                                    qcow_aio_write_cb, acb);
     if (acb->hd_aiocb == NULL)
         goto fail;
 }

Modified: trunk/block-qcow2.c
===================================================================
--- trunk/block-qcow2.c 2009-04-07 18:23:51 UTC (rev 7018)
+++ trunk/block-qcow2.c 2009-04-07 18:43:20 UTC (rev 7019)
@@ -1270,6 +1270,8 @@
     uint64_t cluster_offset;
     uint8_t *cluster_data;
     BlockDriverAIOCB *hd_aiocb;
+    struct iovec hd_iov;
+    QEMUIOVector hd_qiov;
     QEMUBH *bh;
     QCowL2Meta l2meta;
 } QCowAIOCB;
@@ -1347,8 +1349,12 @@
             n1 = backing_read1(bs->backing_hd, acb->sector_num,
                                acb->buf, acb->n);
             if (n1 > 0) {
-                acb->hd_aiocb = bdrv_aio_read(bs->backing_hd, acb->sector_num,
-                                    acb->buf, acb->n, qcow_aio_read_cb, acb);
+                acb->hd_iov.iov_base = acb->buf;
+                acb->hd_iov.iov_len = acb->n * 512;
+                qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+                acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
+                                    &acb->hd_qiov, acb->n,
+                                   qcow_aio_read_cb, acb);
                 if (acb->hd_aiocb == NULL)
                     goto fail;
             } else {
@@ -1377,9 +1383,13 @@
             ret = -EIO;
             goto fail;
         }
-        acb->hd_aiocb = bdrv_aio_read(s->hd,
+
+        acb->hd_iov.iov_base = acb->buf;
+        acb->hd_iov.iov_len = acb->n * 512;
+        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+        acb->hd_aiocb = bdrv_aio_readv(s->hd,
                             (acb->cluster_offset >> 9) + index_in_cluster,
-                            acb->buf, acb->n, qcow_aio_read_cb, acb);
+                            &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
         if (acb->hd_aiocb == NULL)
             goto fail;
     }
@@ -1476,10 +1486,13 @@
     } else {
         src_buf = acb->buf;
     }
-    acb->hd_aiocb = bdrv_aio_write(s->hd,
-                                   (acb->cluster_offset >> 9) + 
index_in_cluster,
-                                   src_buf, acb->n,
-                                   qcow_aio_write_cb, acb);
+    acb->hd_iov.iov_base = (void *)src_buf;
+    acb->hd_iov.iov_len = acb->n * 512;
+    qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+    acb->hd_aiocb = bdrv_aio_writev(s->hd,
+                                    (acb->cluster_offset >> 9) + 
index_in_cluster,
+                                    &acb->hd_qiov, acb->n,
+                                    qcow_aio_write_cb, acb);
     if (acb->hd_aiocb == NULL)
         goto fail;
 }

Modified: trunk/block.c
===================================================================
--- trunk/block.c       2009-04-07 18:23:51 UTC (rev 7018)
+++ trunk/block.c       2009-04-07 18:43:20 UTC (rev 7019)
@@ -55,6 +55,12 @@
     int ret;
 } BlockDriverAIOCBSync;
 
+static BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+static BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs,
+        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
 static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
         int64_t sector_num, uint8_t *buf, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
@@ -1370,7 +1376,7 @@
                               cb, opaque, 1);
 }
 
-BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
+static BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t 
sector_num,
                                 uint8_t *buf, int nb_sectors,
                                 BlockDriverCompletionFunc *cb, void *opaque)
 {
@@ -1393,7 +1399,7 @@
     return ret;
 }
 
-BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
+static BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t 
sector_num,
                                  const uint8_t *buf, int nb_sectors,
                                  BlockDriverCompletionFunc *cb, void *opaque)
 {

Modified: trunk/block.h
===================================================================
--- trunk/block.h       2009-04-07 18:23:51 UTC (rev 7018)
+++ trunk/block.h       2009-04-07 18:43:20 UTC (rev 7019)
@@ -96,13 +96,6 @@
 BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
                                   QEMUIOVector *iov, int nb_sectors,
                                   BlockDriverCompletionFunc *cb, void *opaque);
-
-BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
-                                uint8_t *buf, int nb_sectors,
-                                BlockDriverCompletionFunc *cb, void *opaque);
-BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
-                                 const uint8_t *buf, int nb_sectors,
-                                 BlockDriverCompletionFunc *cb, void *opaque);
 void bdrv_aio_cancel(BlockDriverAIOCB *acb);
 
 /* sg packet commands */

Modified: trunk/hw/ide.c
===================================================================
--- trunk/hw/ide.c      2009-04-07 18:23:51 UTC (rev 7018)
+++ trunk/hw/ide.c      2009-04-07 18:43:20 UTC (rev 7019)
@@ -496,6 +496,8 @@
     IDEState *ide_if;
     BlockDriverCompletionFunc *dma_cb;
     BlockDriverAIOCB *aiocb;
+    struct iovec iov;
+    QEMUIOVector qiov;
     int64_t sector_num;
     uint32_t nsector;
 } BMDMAState;
@@ -1467,9 +1469,11 @@
 #ifdef DEBUG_AIO
     printf("aio_read_cd: lba=%u n=%d\n", s->lba, n);
 #endif
-    bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2,
-                              s->io_buffer + data_offset, n * 4,
-                              ide_atapi_cmd_read_dma_cb, bm);
+    bm->iov.iov_base = s->io_buffer + data_offset;
+    bm->iov.iov_len = n * 4 * 512;
+    qemu_iovec_init_external(&bm->qiov, &bm->iov, 1);
+    bm->aiocb = bdrv_aio_readv(s->bs, (int64_t)s->lba << 2, &bm->qiov,
+                               n * 4, ide_atapi_cmd_read_dma_cb, bm);
     if (!bm->aiocb) {
         /* Note: media not present is the most likely case */
         ide_atapi_cmd_error(s, SENSE_NOT_READY,

Modified: trunk/hw/scsi-disk.c
===================================================================
--- trunk/hw/scsi-disk.c        2009-04-07 18:23:51 UTC (rev 7018)
+++ trunk/hw/scsi-disk.c        2009-04-07 18:43:20 UTC (rev 7019)
@@ -52,9 +52,8 @@
     /* Both sector and sector_count are in terms of qemu 512 byte blocks.  */
     uint64_t sector;
     uint32_t sector_count;
-    /* The amounnt of data in the buffer.  */
-    int buf_len;
-    uint8_t *dma_buf;
+    struct iovec iov;
+    QEMUIOVector qiov;
     BlockDriverAIOCB *aiocb;
     struct SCSIRequest *next;
     uint32_t status;
@@ -89,12 +88,12 @@
         free_requests = r->next;
     } else {
         r = qemu_malloc(sizeof(SCSIRequest));
-        r->dma_buf = qemu_memalign(512, SCSI_DMA_BUF_SIZE);
+        r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE);
     }
     r->dev = s;
     r->tag = tag;
     r->sector_count = 0;
-    r->buf_len = 0;
+    r->iov.iov_len = 0;
     r->aiocb = NULL;
     r->status = 0;
 
@@ -173,9 +172,9 @@
         scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NO_SENSE);
         return;
     }
-    DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, r->buf_len);
+    DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, r->iov.iov_len);
 
-    s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len);
+    s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->iov.iov_len);
 }
 
 /* Read more data from scsi device into buffer.  */
@@ -193,9 +192,9 @@
         return;
     }
     if (r->sector_count == (uint32_t)-1) {
-        DPRINTF("Read buf_len=%d\n", r->buf_len);
+        DPRINTF("Read buf_len=%d\n", r->iov.iov_len);
         r->sector_count = 0;
-        s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len);
+        s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->iov.iov_len);
         return;
     }
     DPRINTF("Read sector_count=%d\n", r->sector_count);
@@ -208,9 +207,10 @@
     if (n > SCSI_DMA_BUF_SIZE / 512)
         n = SCSI_DMA_BUF_SIZE / 512;
 
-    r->buf_len = n * 512;
-    r->aiocb = bdrv_aio_read(s->bdrv, r->sector, r->dma_buf, n,
-                             scsi_read_complete, r);
+    r->iov.iov_len = n * 512;
+    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+    r->aiocb = bdrv_aio_readv(s->bdrv, r->sector, &r->qiov, n,
+                              scsi_read_complete, r);
     if (r->aiocb == NULL)
         scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
     r->sector += n;
@@ -250,7 +250,7 @@
             return;
     }
 
-    n = r->buf_len / 512;
+    n = r->iov.iov_len / 512;
     r->sector += n;
     r->sector_count -= n;
     if (r->sector_count == 0) {
@@ -260,7 +260,7 @@
         if (len > SCSI_DMA_BUF_SIZE) {
             len = SCSI_DMA_BUF_SIZE;
         }
-        r->buf_len = len;
+        r->iov.iov_len = len;
         DPRINTF("Write complete tag=0x%x more=%d\n", r->tag, len);
         s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len);
     }
@@ -271,10 +271,11 @@
     SCSIDeviceState *s = r->dev;
     uint32_t n;
 
-    n = r->buf_len / 512;
+    n = r->iov.iov_len / 512;
     if (n) {
-        r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n,
-                                  scsi_write_complete, r);
+        qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+        r->aiocb = bdrv_aio_writev(s->bdrv, r->sector, &r->qiov, n,
+                                   scsi_write_complete, r);
         if (r->aiocb == NULL)
             scsi_command_complete(r, STATUS_CHECK_CONDITION,
                                   SENSE_HARDWARE_ERROR);
@@ -334,7 +335,7 @@
         BADF("Bad buffer tag 0x%x\n", tag);
         return NULL;
     }
-    return r->dma_buf;
+    return r->iov.iov_base;
 }
 
 /* Execute a scsi command.  Returns the length of the data expected by the
@@ -364,7 +365,7 @@
     /* ??? Tags are not unique for different luns.  We only implement a
        single lun, so this should not matter.  */
     r = scsi_new_request(s, tag);
-    outbuf = r->dma_buf;
+    outbuf = r->iov.iov_base;
     is_write = 0;
     DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
     switch (command >> 5) {
@@ -425,10 +426,10 @@
         if (len < 4)
             goto fail;
         memset(outbuf, 0, 4);
-        r->buf_len = 4;
+        r->iov.iov_len = 4;
         if (s->sense == SENSE_NOT_READY && len >= 18) {
             memset(outbuf, 0, 18);
-            r->buf_len = 18;
+            r->iov.iov_len = 18;
             outbuf[7] = 10;
             /* asc 0x3a, ascq 0: Medium not present */
             outbuf[12] = 0x3a;
@@ -461,20 +462,20 @@
                         DPRINTF("Inquiry EVPD[Supported pages] "
                                 "buffer size %d\n", len);
 
-                        r->buf_len = 0;
+                        r->iov.iov_len = 0;
 
                         if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
-                            outbuf[r->buf_len++] = 5;
+                            outbuf[r->iov.iov_len++] = 5;
                         } else {
-                            outbuf[r->buf_len++] = 0;
+                            outbuf[r->iov.iov_len++] = 0;
                         }
 
-                        outbuf[r->buf_len++] = 0x00; // this page
-                        outbuf[r->buf_len++] = 0x00;
-                        outbuf[r->buf_len++] = 3;    // number of pages
-                        outbuf[r->buf_len++] = 0x00; // list of supported 
pages (this page)
-                        outbuf[r->buf_len++] = 0x80; // unit serial number
-                        outbuf[r->buf_len++] = 0x83; // device identification
+                        outbuf[r->iov.iov_len++] = 0x00; // this page
+                        outbuf[r->iov.iov_len++] = 0x00;
+                        outbuf[r->iov.iov_len++] = 3;    // number of pages
+                        outbuf[r->iov.iov_len++] = 0x00; // list of supported 
pages (this page)
+                        outbuf[r->iov.iov_len++] = 0x80; // unit serial number
+                        outbuf[r->iov.iov_len++] = 0x83; // device 
identification
                     }
                     break;
                 case 0x80:
@@ -491,20 +492,20 @@
                         DPRINTF("Inquiry EVPD[Serial number] buffer size 
%d\n", len);
                         l = MIN(len, strlen(s->drive_serial_str));
 
-                        r->buf_len = 0;
+                        r->iov.iov_len = 0;
 
                         /* Supported page codes */
                         if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
-                            outbuf[r->buf_len++] = 5;
+                            outbuf[r->iov.iov_len++] = 5;
                         } else {
-                            outbuf[r->buf_len++] = 0;
+                            outbuf[r->iov.iov_len++] = 0;
                         }
 
-                        outbuf[r->buf_len++] = 0x80; // this page
-                        outbuf[r->buf_len++] = 0x00;
-                        outbuf[r->buf_len++] = l;
-                        memcpy(&outbuf[r->buf_len], s->drive_serial_str, l);
-                        r->buf_len += l;
+                        outbuf[r->iov.iov_len++] = 0x80; // this page
+                        outbuf[r->iov.iov_len++] = 0x00;
+                        outbuf[r->iov.iov_len++] = l;
+                        memcpy(&outbuf[r->iov.iov_len], s->drive_serial_str, 
l);
+                        r->iov.iov_len += l;
                     }
 
                     break;
@@ -518,25 +519,25 @@
 
                         DPRINTF("Inquiry EVPD[Device identification] "
                                 "buffer size %d\n", len);
-                        r->buf_len = 0;
+                        r->iov.iov_len = 0;
                         if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
-                            outbuf[r->buf_len++] = 5;
+                            outbuf[r->iov.iov_len++] = 5;
                         } else {
-                            outbuf[r->buf_len++] = 0;
+                            outbuf[r->iov.iov_len++] = 0;
                         }
 
-                        outbuf[r->buf_len++] = 0x83; // this page
-                        outbuf[r->buf_len++] = 0x00;
-                        outbuf[r->buf_len++] = 3 + id_len;
+                        outbuf[r->iov.iov_len++] = 0x83; // this page
+                        outbuf[r->iov.iov_len++] = 0x00;
+                        outbuf[r->iov.iov_len++] = 3 + id_len;
 
-                        outbuf[r->buf_len++] = 0x2; // ASCII
-                        outbuf[r->buf_len++] = 0;   // not officially assigned
-                        outbuf[r->buf_len++] = 0;   // reserved
-                        outbuf[r->buf_len++] = id_len; // length of data 
following
+                        outbuf[r->iov.iov_len++] = 0x2; // ASCII
+                        outbuf[r->iov.iov_len++] = 0;   // not officially 
assigned
+                        outbuf[r->iov.iov_len++] = 0;   // reserved
+                        outbuf[r->iov.iov_len++] = id_len; // length of data 
following
 
-                        memcpy(&outbuf[r->buf_len],
+                        memcpy(&outbuf[r->iov.iov_len],
                                bdrv_get_device_name(s->bdrv), id_len);
-                        r->buf_len += id_len;
+                        r->iov.iov_len += id_len;
                     }
                     break;
                 default:
@@ -592,7 +593,7 @@
        outbuf[4] = len - 5; /* Additional Length = (Len - 1) - 4 */
         /* Sync data transfer and TCQ.  */
         outbuf[7] = 0x10 | (s->tcq ? 0x02 : 0);
-       r->buf_len = len;
+       r->iov.iov_len = len;
        break;
     case 0x16:
         DPRINTF("Reserve(6)\n");
@@ -727,10 +728,10 @@
                 p[21] = (16 * 176) & 0xff;
                 p += 22;
             }
-            r->buf_len = p - outbuf;
-            outbuf[0] = r->buf_len - 4;
-            if (r->buf_len > len)
-                r->buf_len = len;
+            r->iov.iov_len = p - outbuf;
+            outbuf[0] = r->iov.iov_len - 4;
+            if (r->iov.iov_len > len)
+                r->iov.iov_len = len;
         }
         break;
     case 0x1b:
@@ -766,7 +767,7 @@
             outbuf[5] = 0;
             outbuf[6] = s->cluster_size * 2;
             outbuf[7] = 0;
-            r->buf_len = 8;
+            r->iov.iov_len = 8;
         } else {
         notready:
             scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY);
@@ -827,7 +828,7 @@
             if (toclen > 0) {
                 if (len > toclen)
                   len = toclen;
-                r->buf_len = len;
+                r->iov.iov_len = len;
                 break;
             }
         error_cmd:
@@ -840,7 +841,7 @@
         /* ??? This should probably return much more information.  For now
            just return the basic header indicating the CD-ROM profile.  */
         outbuf[7] = 8; // CD-ROM
-        r->buf_len = 8;
+        r->iov.iov_len = 8;
         break;
     case 0x56:
         DPRINTF("Reserve(10)\n");
@@ -877,7 +878,7 @@
                 outbuf[10] = s->cluster_size * 2;
                 outbuf[11] = 0;
                 /* Protection, exponent and lowest lba field left blank. */
-                r->buf_len = len;
+                r->iov.iov_len = len;
             } else {
                 scsi_command_complete(r, STATUS_CHECK_CONDITION, 
SENSE_NOT_READY);
                 return 0;
@@ -892,7 +893,7 @@
             goto fail;
         memset(outbuf, 0, 16);
         outbuf[3] = 8;
-        r->buf_len = 16;
+        r->iov.iov_len = 16;
         break;
     case 0x2f:
         DPRINTF("Verify (sector %d, count %d)\n", lba, len);
@@ -906,10 +907,10 @@
         scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
         return 0;
     }
-    if (r->sector_count == 0 && r->buf_len == 0) {
+    if (r->sector_count == 0 && r->iov.iov_len == 0) {
         scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
     }
-    len = r->sector_count * 512 + r->buf_len;
+    len = r->sector_count * 512 + r->iov.iov_len;
     if (is_write) {
         return -len;
     } else {





reply via email to

[Prev in Thread] Current Thread [Next in Thread]