symbian-qemu-0.9.1-12/qemu-symbian-svp/block-nbd.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * QEMU Block driver for  NBD
       
     3  *
       
     4  * Copyright (C) 2008 Bull S.A.S.
       
     5  *     Author: Laurent Vivier <Laurent.Vivier@bull.net>
       
     6  *
       
     7  * Some parts:
       
     8  *    Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws>
       
     9  *
       
    10  * Permission is hereby granted, free of charge, to any person obtaining a copy
       
    11  * of this software and associated documentation files (the "Software"), to deal
       
    12  * in the Software without restriction, including without limitation the rights
       
    13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    14  * copies of the Software, and to permit persons to whom the Software is
       
    15  * furnished to do so, subject to the following conditions:
       
    16  *
       
    17  * The above copyright notice and this permission notice shall be included in
       
    18  * all copies or substantial portions of the Software.
       
    19  *
       
    20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
       
    23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    26  * THE SOFTWARE.
       
    27  */
       
    28 
       
    29 #include "qemu-common.h"
       
    30 #include "nbd.h"
       
    31 
       
    32 #include <sys/types.h>
       
    33 #include <unistd.h>
       
    34 
       
    35 typedef struct BDRVNBDState {
       
    36     int sock;
       
    37     off_t size;
       
    38     size_t blocksize;
       
    39 } BDRVNBDState;
       
    40 
       
    41 static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
       
    42 {
       
    43     BDRVNBDState *s = bs->opaque;
       
    44     const char *host;
       
    45     const char *unixpath;
       
    46     int sock;
       
    47     off_t size;
       
    48     size_t blocksize;
       
    49     int ret;
       
    50 
       
    51     if ((flags & BDRV_O_CREAT))
       
    52         return -EINVAL;
       
    53 
       
    54     if (!strstart(filename, "nbd:", &host))
       
    55         return -EINVAL;
       
    56 
       
    57     if (strstart(host, "unix:", &unixpath)) {
       
    58 
       
    59         if (unixpath[0] != '/')
       
    60             return -EINVAL;
       
    61 
       
    62         sock = unix_socket_outgoing(unixpath);
       
    63 
       
    64     } else {
       
    65         uint16_t port;
       
    66         char *p, *r;
       
    67         char hostname[128];
       
    68 
       
    69         pstrcpy(hostname, 128, host);
       
    70 
       
    71         p = strchr(hostname, ':');
       
    72         if (p == NULL)
       
    73             return -EINVAL;
       
    74 
       
    75         *p = '\0';
       
    76         p++;
       
    77 
       
    78         port = strtol(p, &r, 0);
       
    79         if (r == p)
       
    80             return -EINVAL;
       
    81         sock = tcp_socket_outgoing(hostname, port);
       
    82     }
       
    83 
       
    84     if (sock == -1)
       
    85         return -errno;
       
    86 
       
    87     ret = nbd_receive_negotiate(sock, &size, &blocksize);
       
    88     if (ret == -1)
       
    89         return -errno;
       
    90 
       
    91     s->sock = sock;
       
    92     s->size = size;
       
    93     s->blocksize = blocksize;
       
    94 
       
    95     return 0;
       
    96 }
       
    97 
       
    98 static int nbd_read(BlockDriverState *bs, int64_t sector_num,
       
    99                     uint8_t *buf, int nb_sectors)
       
   100 {
       
   101     BDRVNBDState *s = bs->opaque;
       
   102     struct nbd_request request;
       
   103     struct nbd_reply reply;
       
   104 
       
   105     request.type = NBD_CMD_READ;
       
   106     request.handle = (uint64_t)(intptr_t)bs;
       
   107     request.from = sector_num * 512;;
       
   108     request.len = nb_sectors * 512;
       
   109 
       
   110     if (nbd_send_request(s->sock, &request) == -1)
       
   111         return -errno;
       
   112 
       
   113     if (nbd_receive_reply(s->sock, &reply) == -1)
       
   114         return -errno;
       
   115 
       
   116     if (reply.error !=0)
       
   117         return -reply.error;
       
   118 
       
   119     if (reply.handle != request.handle)
       
   120         return -EIO;
       
   121 
       
   122     if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len)
       
   123         return -EIO;
       
   124 
       
   125     return 0;
       
   126 }
       
   127 
       
   128 static int nbd_write(BlockDriverState *bs, int64_t sector_num,
       
   129                      const uint8_t *buf, int nb_sectors)
       
   130 {
       
   131     BDRVNBDState *s = bs->opaque;
       
   132     struct nbd_request request;
       
   133     struct nbd_reply reply;
       
   134 
       
   135     request.type = NBD_CMD_WRITE;
       
   136     request.handle = (uint64_t)(intptr_t)bs;
       
   137     request.from = sector_num * 512;;
       
   138     request.len = nb_sectors * 512;
       
   139 
       
   140     if (nbd_send_request(s->sock, &request) == -1)
       
   141         return -errno;
       
   142 
       
   143     if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len)
       
   144         return -EIO;
       
   145 
       
   146     if (nbd_receive_reply(s->sock, &reply) == -1)
       
   147         return -errno;
       
   148 
       
   149     if (reply.error !=0)
       
   150         return -reply.error;
       
   151 
       
   152     if (reply.handle != request.handle)
       
   153         return -EIO;
       
   154 
       
   155     return 0;
       
   156 }
       
   157 
       
   158 static void nbd_close(BlockDriverState *bs)
       
   159 {
       
   160     BDRVNBDState *s = bs->opaque;
       
   161     struct nbd_request request;
       
   162 
       
   163     request.type = NBD_CMD_DISC;
       
   164     request.handle = (uint64_t)(intptr_t)bs;
       
   165     request.from = 0;
       
   166     request.len = 0;
       
   167     nbd_send_request(s->sock, &request);
       
   168 
       
   169     close(s->sock);
       
   170 }
       
   171 
       
   172 static int64_t nbd_getlength(BlockDriverState *bs)
       
   173 {
       
   174     BDRVNBDState *s = bs->opaque;
       
   175 
       
   176     return s->size;
       
   177 }
       
   178 
       
   179 BlockDriver bdrv_nbd = {
       
   180     "nbd",
       
   181     sizeof(BDRVNBDState),
       
   182     NULL, /* no probe for protocols */
       
   183     nbd_open,
       
   184     nbd_read,
       
   185     nbd_write,
       
   186     nbd_close,
       
   187     .bdrv_getlength = nbd_getlength,
       
   188     .protocol_name = "nbd",
       
   189 };