summaryrefslogtreecommitdiffstats
path: root/nbd/nbd-internal.h
blob: 03549e3f39b146226f34281026a09995a3611f61 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
 * NBD Internal Declarations
 *
 * Copyright (C) 2016 Red Hat, Inc.
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 * See the COPYING file in the top-level directory.
 */

#ifndef NBD_INTERNAL_H
#define NBD_INTERNAL_H
#include "block/nbd.h"
#include "sysemu/block-backend.h"
#include "io/channel-tls.h"

#include "qemu/coroutine.h"
#include "qemu/iov.h"

#ifndef _WIN32
#include <sys/ioctl.h>
#endif
#if defined(__sun__) || defined(__HAIKU__)
#include <sys/ioccom.h>
#endif

#ifdef __linux__
#include <linux/fs.h>
#endif

#include "qemu/bswap.h"
#include "qemu/queue.h"
#include "qemu/main-loop.h"

/* This is all part of the "official" NBD API.
 *
 * The most up-to-date documentation is available at:
 * https://github.com/yoe/nbd/blob/master/doc/proto.md
 */

/* Size of all NBD_OPT_*, without payload */
#define NBD_REQUEST_SIZE            (4 + 2 + 2 + 8 + 8 + 4)
/* Size of all NBD_REP_* sent in answer to most NBD_OPT_*, without payload */
#define NBD_REPLY_SIZE              (4 + 4 + 8)
/* Size of reply to NBD_OPT_EXPORT_NAME */
#define NBD_REPLY_EXPORT_NAME_SIZE  (8 + 2 + 124)
/* Size of oldstyle negotiation */
#define NBD_OLDSTYLE_NEGOTIATE_SIZE (8 + 8 + 8 + 4 + 124)

#define NBD_REQUEST_MAGIC       0x25609513
#define NBD_REPLY_MAGIC         0x67446698
#define NBD_OPTS_MAGIC          0x49484156454F5054LL
#define NBD_CLIENT_MAGIC        0x0000420281861253LL
#define NBD_REP_MAGIC           0x0003e889045565a9LL

#define NBD_SET_SOCK            _IO(0xab, 0)
#define NBD_SET_BLKSIZE         _IO(0xab, 1)
#define NBD_SET_SIZE            _IO(0xab, 2)
#define NBD_DO_IT               _IO(0xab, 3)
#define NBD_CLEAR_SOCK          _IO(0xab, 4)
#define NBD_CLEAR_QUE           _IO(0xab, 5)
#define NBD_PRINT_DEBUG         _IO(0xab, 6)
#define NBD_SET_SIZE_BLOCKS     _IO(0xab, 7)
#define NBD_DISCONNECT          _IO(0xab, 8)
#define NBD_SET_TIMEOUT         _IO(0xab, 9)
#define NBD_SET_FLAGS           _IO(0xab, 10)

/* NBD errors are based on errno numbers, so there is a 1:1 mapping,
 * but only a limited set of errno values is specified in the protocol.
 * Everything else is squashed to EINVAL.
 */
#define NBD_SUCCESS    0
#define NBD_EPERM      1
#define NBD_EIO        5
#define NBD_ENOMEM     12
#define NBD_EINVAL     22
#define NBD_ENOSPC     28
#define NBD_ESHUTDOWN  108

/* nbd_read_eof
 * Tries to read @size bytes from @ioc.
 * Returns 1 on success
 *         0 on eof, when no data was read (errp is not set)
 *         negative errno on failure (errp is set)
 */
static inline int nbd_read_eof(QIOChannel *ioc, void *buffer, size_t size,
                               Error **errp)
{
    struct iovec iov = { .iov_base = buffer, .iov_len = size };
    ssize_t ret;

    /* Sockets are kept in blocking mode in the negotiation phase.  After
     * that, a non-readable socket simply means that another thread stole
     * our request/reply.  Synchronization is done with recv_coroutine, so
     * that this is coroutine-safe.
     */

    assert(size);

    ret = nbd_rwv(ioc, &iov, 1, size, true, errp);
    if (ret <= 0) {
        return ret;
    }

    if (ret != size) {
        error_setg(errp, "End of file");
        return -EINVAL;
    }

    return 1;
}

/* nbd_read
 * Reads @size bytes from @ioc. Returns 0 on success.
 */
static inline int nbd_read(QIOChannel *ioc, void *buffer, size_t size,
                           Error **errp)
{
    int ret = nbd_read_eof(ioc, buffer, size, errp);

    if (ret == 0) {
        ret = -EINVAL;
        error_setg(errp, "End of file");
    }

    return ret < 0 ? ret : 0;
}

/* nbd_write
 * Writes @size bytes to @ioc. Returns 0 on success.
 */
static inline int nbd_write(QIOChannel *ioc, const void *buffer, size_t size,
                            Error **errp)
{
    struct iovec iov = { .iov_base = (void *) buffer, .iov_len = size };

    ssize_t ret = nbd_rwv(ioc, &iov, 1, size, false, errp);

    assert(ret < 0 || ret == size);

    return ret < 0 ? ret : 0;
}

struct NBDTLSHandshakeData {
    GMainLoop *loop;
    bool complete;
    Error *error;
};


void nbd_tls_handshake(QIOTask *task,
                       void *opaque);
const char *nbd_opt_lookup(uint32_t opt);
const char *nbd_rep_lookup(uint32_t rep);
const char *nbd_info_lookup(uint16_t info);
const char *nbd_cmd_lookup(uint16_t info);

int nbd_drop(QIOChannel *ioc, size_t size, Error **errp);

#endif