Home | History | Annotate | Download | only in block
      1 /*
      2  * QEMU Block driver for  NBD
      3  *
      4  * Copyright (C) 2008 Bull S.A.S.
      5  *     Author: Laurent Vivier <Laurent.Vivier (at) bull.net>
      6  *
      7  * Some parts:
      8  *    Copyright (C) 2007 Anthony Liguori <anthony (at) 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 #include "module.h"
     32 
     33 #include <sys/types.h>
     34 #include <unistd.h>
     35 
     36 typedef struct BDRVNBDState {
     37     int sock;
     38     off_t size;
     39     size_t blocksize;
     40 } BDRVNBDState;
     41 
     42 static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
     43 {
     44     BDRVNBDState *s = bs->opaque;
     45     const char *host;
     46     const char *unixpath;
     47     int sock;
     48     off_t size;
     49     size_t blocksize;
     50     int ret;
     51 
     52     if (!strstart(filename, "nbd:", &host))
     53         return -EINVAL;
     54 
     55     if (strstart(host, "unix:", &unixpath)) {
     56 
     57         if (unixpath[0] != '/')
     58             return -EINVAL;
     59 
     60         sock = unix_socket_outgoing(unixpath);
     61 
     62     } else {
     63         uint16_t port;
     64         char *p, *r;
     65         char hostname[128];
     66 
     67         pstrcpy(hostname, 128, host);
     68 
     69         p = strchr(hostname, ':');
     70         if (p == NULL)
     71             return -EINVAL;
     72 
     73         *p = '\0';
     74         p++;
     75 
     76         port = strtol(p, &r, 0);
     77         if (r == p)
     78             return -EINVAL;
     79         sock = tcp_socket_outgoing(hostname, port);
     80     }
     81 
     82     if (sock == -1)
     83         return -errno;
     84 
     85     ret = nbd_receive_negotiate(sock, &size, &blocksize);
     86     if (ret == -1)
     87         return -errno;
     88 
     89     s->sock = sock;
     90     s->size = size;
     91     s->blocksize = blocksize;
     92 
     93     return 0;
     94 }
     95 
     96 static int nbd_read(BlockDriverState *bs, int64_t sector_num,
     97                     uint8_t *buf, int nb_sectors)
     98 {
     99     BDRVNBDState *s = bs->opaque;
    100     struct nbd_request request;
    101     struct nbd_reply reply;
    102 
    103     request.type = NBD_CMD_READ;
    104     request.handle = (uint64_t)(intptr_t)bs;
    105     request.from = sector_num * 512;;
    106     request.len = nb_sectors * 512;
    107 
    108     if (nbd_send_request(s->sock, &request) == -1)
    109         return -errno;
    110 
    111     if (nbd_receive_reply(s->sock, &reply) == -1)
    112         return -errno;
    113 
    114     if (reply.error !=0)
    115         return -reply.error;
    116 
    117     if (reply.handle != request.handle)
    118         return -EIO;
    119 
    120     if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len)
    121         return -EIO;
    122 
    123     return 0;
    124 }
    125 
    126 static int nbd_write(BlockDriverState *bs, int64_t sector_num,
    127                      const uint8_t *buf, int nb_sectors)
    128 {
    129     BDRVNBDState *s = bs->opaque;
    130     struct nbd_request request;
    131     struct nbd_reply reply;
    132 
    133     request.type = NBD_CMD_WRITE;
    134     request.handle = (uint64_t)(intptr_t)bs;
    135     request.from = sector_num * 512;;
    136     request.len = nb_sectors * 512;
    137 
    138     if (nbd_send_request(s->sock, &request) == -1)
    139         return -errno;
    140 
    141     if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len)
    142         return -EIO;
    143 
    144     if (nbd_receive_reply(s->sock, &reply) == -1)
    145         return -errno;
    146 
    147     if (reply.error !=0)
    148         return -reply.error;
    149 
    150     if (reply.handle != request.handle)
    151         return -EIO;
    152 
    153     return 0;
    154 }
    155 
    156 static void nbd_close(BlockDriverState *bs)
    157 {
    158     BDRVNBDState *s = bs->opaque;
    159     struct nbd_request request;
    160 
    161     request.type = NBD_CMD_DISC;
    162     request.handle = (uint64_t)(intptr_t)bs;
    163     request.from = 0;
    164     request.len = 0;
    165     nbd_send_request(s->sock, &request);
    166 
    167     close(s->sock);
    168 }
    169 
    170 static int64_t nbd_getlength(BlockDriverState *bs)
    171 {
    172     BDRVNBDState *s = bs->opaque;
    173 
    174     return s->size;
    175 }
    176 
    177 static BlockDriver bdrv_nbd = {
    178     .format_name	= "nbd",
    179     .instance_size	= sizeof(BDRVNBDState),
    180     .bdrv_file_open	= nbd_open,
    181     .bdrv_read		= nbd_read,
    182     .bdrv_write		= nbd_write,
    183     .bdrv_close		= nbd_close,
    184     .bdrv_getlength	= nbd_getlength,
    185     .protocol_name	= "nbd",
    186 };
    187 
    188 static void bdrv_nbd_init(void)
    189 {
    190     bdrv_register(&bdrv_nbd);
    191 }
    192 
    193 block_init(bdrv_nbd_init);
    194