static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) { QEMUFileBuffered *s = opaque; int offset = 0, error; ssize_t ret; DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos); error = qemu_file_get_error(s->file); if (error) { DPRINTF("flush when error, bailing: %s\n", strerror(-error)); return error; } DPRINTF("unfreezing output\n"); s->freeze_output = 0; buffered_flush(s); while (!s->freeze_output && offset < size) { if (s->bytes_xfer > s->xfer_limit) { DPRINTF("transfer limit exceeded when putting\n"); break; } ret = s->put_buffer(s->opaque, buf + offset, size - offset); if (ret == -EAGAIN) { DPRINTF("backend not ready, freezing\n"); s->freeze_output = 1; break; } if (ret <= 0) { DPRINTF("error putting\n"); qemu_file_set_error(s->file, ret); offset = -EINVAL; break; } DPRINTF("put %zd byte(s)\n", ret); offset += ret; s->bytes_xfer += ret; } if (offset >= 0) { DPRINTF("buffering %d bytes\n", size - offset); buffered_append(s, buf + offset, size - offset); offset = size; } if (pos == 0 && size == 0) { DPRINTF("file is ready\n"); if (s->bytes_xfer <= s->xfer_limit) { DPRINTF("notifying client\n"); s->put_ready(s->opaque); } } return offset; }
static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) { QEMUFileBuffered *s = opaque; int offset = 0; ssize_t ret; DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos); if (s->has_error) { DPRINTF("flush when error, bailing\n"); return -EINVAL; } DPRINTF("unfreezing output\n"); s->freeze_output = 0; buffered_flush(s); while (!s->freeze_output && offset < size) { if (s->bytes_xfer > s->xfer_limit) { DPRINTF("transfer limit exceeded when putting\n"); break; } ret = s->put_buffer(s->opaque, buf + offset, size - offset); if (ret == -EAGAIN) { DPRINTF("backend not ready, freezing\n"); s->freeze_output = 1; break; } if (ret <= 0) { DPRINTF("error putting\n"); s->has_error = 1; offset = -EINVAL; break; } DPRINTF("put %zd byte(s)\n", ret); offset += ret; s->bytes_xfer += ret; } if (offset >= 0) { DPRINTF("buffering %d bytes\n", size - offset); buffered_append(s, buf + offset, size - offset); offset = size; } return offset; }
QEMUFile *qemu_fopen_ops_buffered(void *opaque, size_t bytes_per_sec, BufferedPutFunc *put_buffer, BufferedPutReadyFunc *put_ready, BufferedWaitForUnfreezeFunc *wait_for_unfreeze, BufferedCloseFunc *close) { // dummy functions & dummy calls buffered_append(NULL, NULL, 0); buffered_flush(NULL); buffered_put_buffer(opaque, NULL, 0, 0); buffered_close(opaque); buffered_rate_limit(opaque); buffered_set_rate_limit(opaque, 0); buffered_get_rate_limit(opaque); buffered_rate_tick(opaque); return NULL; }
static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) { QEMUFileBuffered *s = opaque; ssize_t error; DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos); error = qemu_file_get_error(s->file); if (error) { DPRINTF("flush when error, bailing: %s\n", strerror(-error)); return error; } DPRINTF("unfreezing output\n"); s->freeze_output = 0; if (size > 0) { DPRINTF("buffering %d bytes\n", size); buffered_append(s, buf, size); } error = buffered_flush(s); if (error < 0) { DPRINTF("buffered flush error. bailing: %s\n", strerror(-error)); return error; } if (pos == 0 && size == 0) { DPRINTF("file is ready\n"); if (!s->freeze_output && s->bytes_xfer < s->xfer_limit) { DPRINTF("notifying client\n"); migrate_fd_put_ready(s->migration_state); } } return size; }