]> git.proxmox.com Git - qemu.git/blame - buffered_file.c
block: move include files to include/block/
[qemu.git] / buffered_file.c
CommitLineData
39b65c2e
AL
1/*
2 * QEMU buffered QEMUFile
3 *
4 * Copyright IBM, Corp. 2008
5 *
6 * Authors:
7 * Anthony Liguori <aliguori@us.ibm.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
11 *
6b620ca3
PB
12 * Contributions after 2012-01-13 are licensed under the terms of the
13 * GNU GPL, version 2 or (at your option) any later version.
39b65c2e
AL
14 */
15
16#include "qemu-common.h"
17#include "hw/hw.h"
18#include "qemu-timer.h"
39b65c2e
AL
19#include "buffered_file.h"
20
21//#define DEBUG_BUFFERED_FILE
22
23typedef struct QEMUFileBuffered
24{
c7a8f0cd 25 MigrationState *migration_state;
39b65c2e 26 QEMUFile *file;
39b65c2e
AL
27 int freeze_output;
28 size_t bytes_xfer;
29 size_t xfer_limit;
30 uint8_t *buffer;
31 size_t buffer_size;
32 size_t buffer_capacity;
33 QEMUTimer *timer;
34} QEMUFileBuffered;
35
36#ifdef DEBUG_BUFFERED_FILE
d0f2c4c6 37#define DPRINTF(fmt, ...) \
39b65c2e
AL
38 do { printf("buffered-file: " fmt, ## __VA_ARGS__); } while (0)
39#else
d0f2c4c6 40#define DPRINTF(fmt, ...) \
39b65c2e
AL
41 do { } while (0)
42#endif
43
44static void buffered_append(QEMUFileBuffered *s,
45 const uint8_t *buf, size_t size)
46{
47 if (size > (s->buffer_capacity - s->buffer_size)) {
d0f2c4c6 48 DPRINTF("increasing buffer capacity from %zu by %zu\n",
39b65c2e
AL
49 s->buffer_capacity, size + 1024);
50
51 s->buffer_capacity += size + 1024;
52
05e72dc5 53 s->buffer = g_realloc(s->buffer, s->buffer_capacity);
39b65c2e
AL
54 }
55
56 memcpy(s->buffer + s->buffer_size, buf, size);
57 s->buffer_size += size;
58}
59
d2dbc8e6 60static ssize_t buffered_flush(QEMUFileBuffered *s)
39b65c2e
AL
61{
62 size_t offset = 0;
d2dbc8e6 63 ssize_t ret = 0;
39b65c2e 64
d0f2c4c6 65 DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size);
39b65c2e 66
2dddf6f4 67 while (s->bytes_xfer < s->xfer_limit && offset < s->buffer_size) {
39b65c2e 68
c87b015b
JQ
69 ret = migrate_fd_put_buffer(s->migration_state, s->buffer + offset,
70 s->buffer_size - offset);
39b65c2e 71 if (ret == -EAGAIN) {
d0f2c4c6 72 DPRINTF("backend not ready, freezing\n");
d2dbc8e6 73 ret = 0;
39b65c2e
AL
74 s->freeze_output = 1;
75 break;
76 }
77
78 if (ret <= 0) {
d0f2c4c6 79 DPRINTF("error flushing data, %zd\n", ret);
39b65c2e
AL
80 break;
81 } else {
d0f2c4c6 82 DPRINTF("flushed %zd byte(s)\n", ret);
39b65c2e 83 offset += ret;
2dddf6f4 84 s->bytes_xfer += ret;
39b65c2e
AL
85 }
86 }
87
d0f2c4c6 88 DPRINTF("flushed %zu of %zu byte(s)\n", offset, s->buffer_size);
39b65c2e
AL
89 memmove(s->buffer, s->buffer + offset, s->buffer_size - offset);
90 s->buffer_size -= offset;
d2dbc8e6
JQ
91
92 if (ret < 0) {
93 return ret;
94 }
95 return offset;
39b65c2e
AL
96}
97
98static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
99{
100 QEMUFileBuffered *s = opaque;
d2dbc8e6 101 ssize_t error;
39b65c2e 102
d0f2c4c6 103 DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos);
39b65c2e 104
42802d47
JQ
105 error = qemu_file_get_error(s->file);
106 if (error) {
107 DPRINTF("flush when error, bailing: %s\n", strerror(-error));
108 return error;
39b65c2e
AL
109 }
110
d0f2c4c6 111 DPRINTF("unfreezing output\n");
39b65c2e
AL
112 s->freeze_output = 0;
113
2dddf6f4 114 if (size > 0) {
d0f2c4c6 115 DPRINTF("buffering %d bytes\n", size - offset);
2dddf6f4 116 buffered_append(s, buf, size);
39b65c2e
AL
117 }
118
d2dbc8e6
JQ
119 error = buffered_flush(s);
120 if (error < 0) {
121 DPRINTF("buffered flush error. bailing: %s\n", strerror(-error));
d2dbc8e6
JQ
122 return error;
123 }
2dddf6f4 124
5e77aaa0
AK
125 if (pos == 0 && size == 0) {
126 DPRINTF("file is ready\n");
2dddf6f4 127 if (!s->freeze_output && s->bytes_xfer < s->xfer_limit) {
5e77aaa0 128 DPRINTF("notifying client\n");
2c9adcb8 129 migrate_fd_put_ready(s->migration_state);
5e77aaa0
AK
130 }
131 }
132
2dddf6f4 133 return size;
39b65c2e
AL
134}
135
136static int buffered_close(void *opaque)
137{
138 QEMUFileBuffered *s = opaque;
d2dbc8e6
JQ
139 ssize_t ret = 0;
140 int ret2;
39b65c2e 141
d0f2c4c6 142 DPRINTF("closing\n");
39b65c2e 143
2dddf6f4 144 s->xfer_limit = INT_MAX;
624b9cc2 145 while (!qemu_file_get_error(s->file) && s->buffer_size) {
d2dbc8e6
JQ
146 ret = buffered_flush(s);
147 if (ret < 0) {
148 break;
149 }
9499743f
JQ
150 if (s->freeze_output) {
151 ret = migrate_fd_wait_for_unfreeze(s->migration_state);
152 if (ret < 0) {
153 break;
154 }
155 }
39b65c2e
AL
156 }
157
d2dbc8e6
JQ
158 ret2 = migrate_fd_close(s->migration_state);
159 if (ret >= 0) {
160 ret = ret2;
161 }
39b65c2e
AL
162 qemu_del_timer(s->timer);
163 qemu_free_timer(s->timer);
7267c094
AL
164 g_free(s->buffer);
165 g_free(s);
39b65c2e
AL
166
167 return ret;
168}
169
4fc7d819
JQ
170/*
171 * The meaning of the return values is:
172 * 0: We can continue sending
173 * 1: Time to stop
42802d47 174 * negative: There has been an error
4fc7d819 175 */
70eb6330
PB
176static int buffered_get_fd(void *opaque)
177{
178 QEMUFileBuffered *s = opaque;
179
180 return qemu_get_fd(s->file);
181}
182
39b65c2e
AL
183static int buffered_rate_limit(void *opaque)
184{
185 QEMUFileBuffered *s = opaque;
42802d47 186 int ret;
39b65c2e 187
42802d47
JQ
188 ret = qemu_file_get_error(s->file);
189 if (ret) {
190 return ret;
4fc7d819 191 }
39b65c2e
AL
192 if (s->freeze_output)
193 return 1;
194
195 if (s->bytes_xfer > s->xfer_limit)
196 return 1;
197
198 return 0;
199}
200
3d002df3 201static int64_t buffered_set_rate_limit(void *opaque, int64_t new_rate)
19629537
GC
202{
203 QEMUFileBuffered *s = opaque;
624b9cc2 204 if (qemu_file_get_error(s->file)) {
19629537 205 goto out;
624b9cc2 206 }
3d002df3
MT
207 if (new_rate > SIZE_MAX) {
208 new_rate = SIZE_MAX;
209 }
210
19629537
GC
211 s->xfer_limit = new_rate / 10;
212
213out:
214 return s->xfer_limit;
215}
216
3d002df3 217static int64_t buffered_get_rate_limit(void *opaque)
c163b5ca 218{
219 QEMUFileBuffered *s = opaque;
220
221 return s->xfer_limit;
222}
223
39b65c2e
AL
224static void buffered_rate_tick(void *opaque)
225{
226 QEMUFileBuffered *s = opaque;
227
624b9cc2 228 if (qemu_file_get_error(s->file)) {
e447b1a6 229 buffered_close(s);
39b65c2e 230 return;
e447b1a6 231 }
39b65c2e 232
7bd427d8 233 qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 100);
39b65c2e
AL
234
235 if (s->freeze_output)
236 return;
237
238 s->bytes_xfer = 0;
239
2dddf6f4 240 buffered_put_buffer(s, NULL, 0, 0);
39b65c2e
AL
241}
242
9229bf3c 243static const QEMUFileOps buffered_file_ops = {
70eb6330 244 .get_fd = buffered_get_fd,
9229bf3c
PB
245 .put_buffer = buffered_put_buffer,
246 .close = buffered_close,
247 .rate_limit = buffered_rate_limit,
248 .get_rate_limit = buffered_get_rate_limit,
249 .set_rate_limit = buffered_set_rate_limit,
250};
251
796b4b0f 252QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state)
39b65c2e
AL
253{
254 QEMUFileBuffered *s;
255
7267c094 256 s = g_malloc0(sizeof(*s));
39b65c2e 257
c7a8f0cd 258 s->migration_state = migration_state;
796b4b0f 259 s->xfer_limit = migration_state->bandwidth_limit / 10;
39b65c2e 260
9229bf3c 261 s->file = qemu_fopen_ops(s, &buffered_file_ops);
39b65c2e 262
7bd427d8 263 s->timer = qemu_new_timer_ms(rt_clock, buffered_rate_tick, s);
39b65c2e 264
7bd427d8 265 qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 100);
39b65c2e
AL
266
267 return s->file;
268}