socket shutdown
Add QEMUFile interface to allow a socket to be 'shut down' - i.e. any reads/writes will fail (and any blocking read/write will be woken). Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Amit Shah <amit.shah@redhat.com>
This commit is contained in:
parent
8580b06498
commit
e1a8c9b67f
@ -84,6 +84,14 @@ typedef size_t (QEMURamSaveFunc)(QEMUFile *f, void *opaque,
|
|||||||
size_t size,
|
size_t size,
|
||||||
int *bytes_sent);
|
int *bytes_sent);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop any read or write (depending on flags) on the underlying
|
||||||
|
* transport on the QEMUFile.
|
||||||
|
* Existing blocking reads/writes must be woken
|
||||||
|
* Returns 0 on success, -err on error
|
||||||
|
*/
|
||||||
|
typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
|
||||||
|
|
||||||
typedef struct QEMUFileOps {
|
typedef struct QEMUFileOps {
|
||||||
QEMUFilePutBufferFunc *put_buffer;
|
QEMUFilePutBufferFunc *put_buffer;
|
||||||
QEMUFileGetBufferFunc *get_buffer;
|
QEMUFileGetBufferFunc *get_buffer;
|
||||||
@ -94,6 +102,7 @@ typedef struct QEMUFileOps {
|
|||||||
QEMURamHookFunc *after_ram_iterate;
|
QEMURamHookFunc *after_ram_iterate;
|
||||||
QEMURamHookFunc *hook_ram_load;
|
QEMURamHookFunc *hook_ram_load;
|
||||||
QEMURamSaveFunc *save_page;
|
QEMURamSaveFunc *save_page;
|
||||||
|
QEMUFileShutdownFunc *shut_down;
|
||||||
} QEMUFileOps;
|
} QEMUFileOps;
|
||||||
|
|
||||||
struct QEMUSizedBuffer {
|
struct QEMUSizedBuffer {
|
||||||
@ -177,6 +186,7 @@ void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
|
|||||||
int64_t qemu_file_get_rate_limit(QEMUFile *f);
|
int64_t qemu_file_get_rate_limit(QEMUFile *f);
|
||||||
int qemu_file_get_error(QEMUFile *f);
|
int qemu_file_get_error(QEMUFile *f);
|
||||||
void qemu_file_set_error(QEMUFile *f, int ret);
|
void qemu_file_set_error(QEMUFile *f, int ret);
|
||||||
|
int qemu_file_shutdown(QEMUFile *f);
|
||||||
void qemu_fflush(QEMUFile *f);
|
void qemu_fflush(QEMUFile *f);
|
||||||
|
|
||||||
static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
|
static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
|
||||||
|
@ -44,6 +44,13 @@ int socket_set_fast_reuse(int fd);
|
|||||||
int send_all(int fd, const void *buf, int len1);
|
int send_all(int fd, const void *buf, int len1);
|
||||||
int recv_all(int fd, void *buf, int len1, bool single_read);
|
int recv_all(int fd, void *buf, int len1, bool single_read);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
/* Windows has different names for the same constants with the same values */
|
||||||
|
#define SHUT_RD 0
|
||||||
|
#define SHUT_WR 1
|
||||||
|
#define SHUT_RDWR 2
|
||||||
|
#endif
|
||||||
|
|
||||||
/* callback function for nonblocking connect
|
/* callback function for nonblocking connect
|
||||||
* valid fd on success, negative error code on failure
|
* valid fd on success, negative error code on failure
|
||||||
*/
|
*/
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
#include "block/coroutine.h"
|
#include "block/coroutine.h"
|
||||||
#include "migration/qemu-file.h"
|
#include "migration/qemu-file.h"
|
||||||
|
#include "migration/qemu-file-internal.h"
|
||||||
|
|
||||||
typedef struct QEMUFileSocket {
|
typedef struct QEMUFileSocket {
|
||||||
int fd;
|
int fd;
|
||||||
@ -84,6 +85,17 @@ static int socket_close(void *opaque)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int socket_shutdown(void *opaque, bool rd, bool wr)
|
||||||
|
{
|
||||||
|
QEMUFileSocket *s = opaque;
|
||||||
|
|
||||||
|
if (shutdown(s->fd, rd ? (wr ? SHUT_RDWR : SHUT_RD) : SHUT_WR)) {
|
||||||
|
return -errno;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
|
static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
|
||||||
int64_t pos)
|
int64_t pos)
|
||||||
{
|
{
|
||||||
@ -194,13 +206,16 @@ QEMUFile *qemu_fdopen(int fd, const char *mode)
|
|||||||
static const QEMUFileOps socket_read_ops = {
|
static const QEMUFileOps socket_read_ops = {
|
||||||
.get_fd = socket_get_fd,
|
.get_fd = socket_get_fd,
|
||||||
.get_buffer = socket_get_buffer,
|
.get_buffer = socket_get_buffer,
|
||||||
.close = socket_close
|
.close = socket_close,
|
||||||
|
.shut_down = socket_shutdown
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const QEMUFileOps socket_write_ops = {
|
static const QEMUFileOps socket_write_ops = {
|
||||||
.get_fd = socket_get_fd,
|
.get_fd = socket_get_fd,
|
||||||
.writev_buffer = socket_writev_buffer,
|
.writev_buffer = socket_writev_buffer,
|
||||||
.close = socket_close
|
.close = socket_close,
|
||||||
|
.shut_down = socket_shutdown
|
||||||
};
|
};
|
||||||
|
|
||||||
QEMUFile *qemu_fopen_socket(int fd, const char *mode)
|
QEMUFile *qemu_fopen_socket(int fd, const char *mode)
|
||||||
|
@ -30,6 +30,18 @@
|
|||||||
#include "migration/qemu-file-internal.h"
|
#include "migration/qemu-file-internal.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop a file from being read/written - not all backing files can do this
|
||||||
|
* typically only sockets can.
|
||||||
|
*/
|
||||||
|
int qemu_file_shutdown(QEMUFile *f)
|
||||||
|
{
|
||||||
|
if (!f->ops->shut_down) {
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
return f->ops->shut_down(f->opaque, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
bool qemu_file_mode_is_not_valid(const char *mode)
|
bool qemu_file_mode_is_not_valid(const char *mode)
|
||||||
{
|
{
|
||||||
if (mode == NULL ||
|
if (mode == NULL ||
|
||||||
|
Loading…
x
Reference in New Issue
Block a user