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

[Xen-changelog] [linux-2.6.18-xen] pvSCSI: Sanity check for REPORT_LUN emulation



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1216203554 -3600
# Node ID bd4b58143713a9d379570707a755079c7cb4f62d
# Parent  a682229d0eacf0bdd25b87a27143d451792f251b
pvSCSI: Sanity check for REPORT_LUN emulation

- Sanity check for REPORT_LUN emulation.
- Return "residual" value from backend to frontend. The residual value
  is used to represent difference between request size the frontend
  requested and size backend actually responded.

Signed-off-by: Tomonari Horikoshi <t.horikoshi@xxxxxxxxxxxxxx>
Signed-off-by: Jun Kamada <kama@xxxxxxxxxxxxxx>
---
 drivers/xen/scsiback/common.h      |    3 -
 drivers/xen/scsiback/emulate.c     |   83 ++++++++++++++++++++++++++-----------
 drivers/xen/scsiback/scsiback.c    |   16 ++++---
 drivers/xen/scsifront/scsifront.c  |    2 
 include/xen/interface/io/vscsiif.h |    4 +
 5 files changed, 76 insertions(+), 32 deletions(-)

diff -r a682229d0eac -r bd4b58143713 drivers/xen/scsiback/common.h
--- a/drivers/xen/scsiback/common.h     Tue Jul 15 16:39:39 2008 +0100
+++ b/drivers/xen/scsiback/common.h     Wed Jul 16 11:19:14 2008 +0100
@@ -124,6 +124,7 @@ typedef struct {
        grant_ref_t gref[VSCSIIF_SG_TABLESIZE];
 
        int32_t rslt;
+       uint32_t resid;
        uint8_t sense_buffer[VSCSIIF_SENSE_BUFFERSIZE];
 
        struct list_head free_list;
@@ -169,7 +170,7 @@ void scsiback_release_translation_entry(
 
 void scsiback_cmd_exec(pending_req_t *pending_req);
 void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result,
-                               pending_req_t *pending_req);
+                       uint32_t resid, pending_req_t *pending_req);
 void scsiback_fast_flush_area(pending_req_t *req);
 
 void scsiback_rsp_emulation(pending_req_t *pending_req);
diff -r a682229d0eac -r bd4b58143713 drivers/xen/scsiback/emulate.c
--- a/drivers/xen/scsiback/emulate.c    Tue Jul 15 16:39:39 2008 +0100
+++ b/drivers/xen/scsiback/emulate.c    Wed Jul 16 11:19:14 2008 +0100
@@ -73,6 +73,10 @@
 #define VSCSI_MAX_SCSI_OP_CODE         256
 static unsigned char bitmap[VSCSI_MAX_SCSI_OP_CODE];
 
+/* REPORT LUNS Header*/
+#define VSCSI_REPORT_LUNS_HEADER       8
+
+
 /*
   Emulation routines for each SCSI op_code.
 */
@@ -97,7 +101,8 @@ static void resp_not_supported_cmd(pendi
 {
        scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST,
                INVALID_OPCODE, 0);
-       pending_req->rslt = check_condition_result;
+       pending_req->resid = 0;
+       pending_req->rslt  = check_condition_result;
 }
 
 
@@ -180,6 +185,21 @@ static int __copy_from_sg(struct scatter
        return 0;
 }
 
+static int __nr_luns_under_host(struct vscsibk_info *info)
+{
+       struct v2p_entry *entry;
+       struct list_head *head = &(info->v2p_entry_lists);
+       unsigned long flags;
+       int lun_cnt = 0;
+
+       spin_lock_irqsave(&info->v2p_lock, flags);
+       list_for_each_entry(entry, head, l) {
+                       lun_cnt++;
+       }
+       spin_unlock_irqrestore(&info->v2p_lock, flags);
+
+       return (lun_cnt);
+}
 
 /* quoted scsi_debug.c/resp_report_luns() */
 static void __report_luns(pending_req_t *pending_req, void *data)
@@ -190,9 +210,11 @@ static void __report_luns(pending_req_t 
        unsigned int        nr_seg  = pending_req->nr_segments;
        unsigned char *cmd = (unsigned char *)pending_req->cmnd;
        
-       unsigned char *rq_buff = NULL;
+       unsigned char *buff = NULL;
        unsigned char alloc_len;
-       unsigned int buff_len = 0;
+       unsigned int alloc_luns = 0;
+       unsigned int req_bufflen = 0;
+       unsigned int actual_len = 0;
        int select_report = (int)cmd[2];
        int i, lun_cnt = 0, lun, upper, err = 0;
        
@@ -202,25 +224,31 @@ static void __report_luns(pending_req_t 
        
        struct scsi_lun *one_lun;
 
-       alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
-       if ((alloc_len < 4) || (select_report != 0))
+       req_bufflen = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
+       if ((req_bufflen < 4) || (select_report != 0))
                goto fail;
-       
-       for (i = 0; i < nr_seg; i++)
-               buff_len += pending_req->sgl[i].length;
-
-       if ((rq_buff = kmalloc(buff_len, GFP_KERNEL)) == NULL) {
+
+       alloc_luns = __nr_luns_under_host(info);
+       alloc_len  = sizeof(struct scsi_lun) * alloc_luns
+                               + VSCSI_REPORT_LUNS_HEADER;
+
+       if ((buff = kmalloc(alloc_len, GFP_KERNEL)) == NULL) {
                printk(KERN_ERR "scsiback:%s kmalloc err\n", __FUNCTION__);
                goto fail;
        }
 
-       memset(rq_buff, 0, buff_len);
-
-       one_lun = (struct scsi_lun *) &rq_buff[8];
+       memset(buff, 0, alloc_len);
+
+       one_lun = (struct scsi_lun *) &buff[8];
        spin_lock_irqsave(&info->v2p_lock, flags);
        list_for_each_entry(entry, head, l) {
                if ((entry->v.chn == channel) &&
                    (entry->v.tgt == target)) {
+                       
+                       /* check overflow */
+                       if (lun_cnt >= alloc_luns)
+                               goto fail;
+
                        lun = entry->v.lun;
                        upper = (lun >> 8) & 0x3f;
                        if (upper)
@@ -232,25 +260,34 @@ static void __report_luns(pending_req_t 
 
        spin_unlock_irqrestore(&info->v2p_lock, flags);
 
-       rq_buff[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff;
-       rq_buff[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff;
-
-       err = __copy_to_sg(pending_req->sgl, nr_seg, rq_buff, buff_len);
+       buff[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff;
+       buff[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff;
+
+       actual_len = lun_cnt * sizeof(struct scsi_lun) 
+                               + VSCSI_REPORT_LUNS_HEADER;
+       req_bufflen = 0;
+       for (i = 0; i < nr_seg; i++)
+               req_bufflen += pending_req->sgl[i].length;
+
+       err = __copy_to_sg(pending_req->sgl, nr_seg, buff, 
+                               min(req_bufflen, actual_len));
        if (err)
                goto fail;
 
        memset(pending_req->sense_buffer, 0, VSCSIIF_SENSE_BUFFERSIZE);
        pending_req->rslt = 0x00;
-
-       kfree(rq_buff);
+       pending_req->resid = req_bufflen - min(req_bufflen, actual_len);
+
+       kfree(buff);
        return;
 
 fail:
        scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST,
                INVALID_FIELD_IN_CDB, 0);
-       pending_req->rslt = check_condition_result;
-       if (rq_buff)
-               kfree(rq_buff);
+       pending_req->rslt  = check_condition_result;
+       pending_req->resid = 0;
+       if (buff)
+               kfree(buff);
        return;
 }
 
@@ -294,7 +331,7 @@ void scsiback_req_emulation_or_cmdexec(p
        else {
                scsiback_fast_flush_area(pending_req);
                scsiback_do_resp_with_sense(pending_req->sense_buffer,
-                       pending_req->rslt, pending_req);
+                 pending_req->rslt, pending_req->resid, pending_req);
        }
 }
 
diff -r a682229d0eac -r bd4b58143713 drivers/xen/scsiback/scsiback.c
--- a/drivers/xen/scsiback/scsiback.c   Tue Jul 15 16:39:39 2008 +0100
+++ b/drivers/xen/scsiback/scsiback.c   Wed Jul 16 11:19:14 2008 +0100
@@ -142,7 +142,7 @@ static void scsiback_notify_work(struct 
 }
 
 void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result,
-                               pending_req_t *pending_req)
+                       uint32_t resid, pending_req_t *pending_req)
 {
        vscsiif_response_t *ring_res;
        struct vscsibk_info *info = pending_req->info;
@@ -167,6 +167,8 @@ void scsiback_do_resp_with_sense(char *s
        } else {
                ring_res->sense_len = 0;
        }
+
+       ring_res->residual_len = resid;
 
        RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&info->ring, notify);
        if (info->ring.rsp_prod_pvt == info->ring.req_cons) {
@@ -209,8 +211,10 @@ static void scsiback_cmd_done(struct req
 {
        pending_req_t *pending_req = req->end_io_data;
        unsigned char *sense_buffer;
+       unsigned int resid;
 
        sense_buffer = req->sense;
+       resid        = req->data_len;
 
        if (errors != 0) {
                if (log_print_stat)
@@ -220,7 +224,7 @@ static void scsiback_cmd_done(struct req
        scsiback_rsp_emulation(pending_req);
 
        scsiback_fast_flush_area(pending_req);
-       scsiback_do_resp_with_sense(sense_buffer, errors, pending_req);
+       scsiback_do_resp_with_sense(sense_buffer, errors, resid, pending_req);
        scsiback_put(pending_req->info);
 
        __blk_put_request(req->q, req);
@@ -473,7 +477,7 @@ static void scsiback_device_reset_exec(p
        scsiback_get(info);
        err = scsi_reset_provider(sdev, SCSI_TRY_RESET_DEVICE);
 
-       scsiback_do_resp_with_sense(NULL, err, pending_req);
+       scsiback_do_resp_with_sense(NULL, err, 0, pending_req);
        scsiback_put(info);
 
        return;
@@ -592,11 +596,11 @@ static int scsiback_do_cmd_fn(struct vsc
                                                pending_req);
                if (err == -EINVAL) {
                        scsiback_do_resp_with_sense(NULL, (DRIVER_ERROR << 24),
-                               pending_req);
+                               0, pending_req);
                        continue;
                } else if (err == -ENODEV) {
                        scsiback_do_resp_with_sense(NULL, (DID_NO_CONNECT << 
16),
-                               pending_req);
+                               0, pending_req);
                        continue;
                }
 
@@ -607,7 +611,7 @@ static int scsiback_do_cmd_fn(struct vsc
                } else {
                        printk(KERN_ERR "scsiback: invalid parameter for 
request\n");
                        scsiback_do_resp_with_sense(NULL, (DRIVER_ERROR << 24),
-                               pending_req);
+                               0, pending_req);
                        continue;
                }
        }
diff -r a682229d0eac -r bd4b58143713 drivers/xen/scsifront/scsifront.c
--- a/drivers/xen/scsifront/scsifront.c Tue Jul 15 16:39:39 2008 +0100
+++ b/drivers/xen/scsifront/scsifront.c Wed Jul 16 11:19:14 2008 +0100
@@ -147,7 +147,7 @@ static void scsifront_cdb_cmd_done(struc
        add_id_to_freelist(info, id);
 
        sc->result = ring_res->rslt;
-       sc->resid  = 0;
+       sc->resid  = ring_res->residual_len;
 
        if (ring_res->sense_len > VSCSIIF_SENSE_BUFFERSIZE)
                sense_len = VSCSIIF_SENSE_BUFFERSIZE;
diff -r a682229d0eac -r bd4b58143713 include/xen/interface/io/vscsiif.h
--- a/include/xen/interface/io/vscsiif.h        Tue Jul 15 16:39:39 2008 +0100
+++ b/include/xen/interface/io/vscsiif.h        Wed Jul 16 11:19:14 2008 +0100
@@ -84,7 +84,9 @@ struct vscsiif_response {
     uint8_t sense_len;
     uint8_t sense_buffer[VSCSIIF_SENSE_BUFFERSIZE];
     int32_t rslt;
-    uint32_t reserved[37];
+    uint32_t residual_len;     /* request bufflen - 
+                                  return the value from physical device */
+    uint32_t reserved[36];
 };
 typedef struct vscsiif_response vscsiif_response_t;
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.