* updated if it changes (eg by writing at the end of the file).
*/
LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+ /* Used to warn if 'flush' is not supported. */
+ char *hostport;
+ bool unsafe_flush_warning;
} BDRVSSHState;
static void ssh_state_init(BDRVSSHState *s)
static void ssh_state_free(BDRVSSHState *s)
{
+ g_free(s->hostport);
if (s->sftp_handle) {
libssh2_sftp_close(s->sftp_handle);
}
Error *err = NULL;
const char *host, *user, *path, *host_key_check;
int port;
- char *hostport = NULL;
host = qdict_get_str(options, "host");
host_key_check = "yes";
}
+ /* Construct the host:port name for inet_connect. */
+ g_free(s->hostport);
+ s->hostport = g_strdup_printf("%s:%d", host, port);
+
/* Open the socket and connect. */
- hostport = g_strdup_printf("%s:%d", host, port);
- s->sock = inet_connect(hostport, &err);
+ s->sock = inet_connect(s->hostport, &err);
if (err != NULL) {
ret = -errno;
qerror_report_err(err);
qdict_del(options, "path");
qdict_del(options, "host_key_check");
- g_free(hostport);
return 0;
err:
libssh2_session_free(s->session);
}
s->session = NULL;
- g_free(hostport);
return ret;
}
return ret;
}
+static void unsafe_flush_warning(BDRVSSHState *s, const char *what)
+{
+ if (!s->unsafe_flush_warning) {
+ error_report("warning: ssh server %s does not support fsync",
+ s->hostport);
+ if (what) {
+ error_report("to support fsync, you need %s", what);
+ }
+ s->unsafe_flush_warning = true;
+ }
+}
+
+#ifdef HAS_LIBSSH2_SFTP_FSYNC
+
+static coroutine_fn int ssh_flush(BDRVSSHState *s)
+{
+ int r;
+
+ DPRINTF("fsync");
+ again:
+ r = libssh2_sftp_fsync(s->sftp_handle);
+ if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
+ co_yield(s);
+ goto again;
+ }
+ if (r == LIBSSH2_ERROR_SFTP_PROTOCOL &&
+ libssh2_sftp_last_error(s->sftp) == LIBSSH2_FX_OP_UNSUPPORTED) {
+ unsafe_flush_warning(s, "OpenSSH >= 6.3");
+ return 0;
+ }
+ if (r < 0) {
+ sftp_error_report(s, "fsync failed");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static coroutine_fn int ssh_co_flush(BlockDriverState *bs)
+{
+ BDRVSSHState *s = bs->opaque;
+ int ret;
+
+ qemu_co_mutex_lock(&s->lock);
+ ret = ssh_flush(s);
+ qemu_co_mutex_unlock(&s->lock);
+
+ return ret;
+}
+
+#else /* !HAS_LIBSSH2_SFTP_FSYNC */
+
+static coroutine_fn int ssh_co_flush(BlockDriverState *bs)
+{
+ BDRVSSHState *s = bs->opaque;
+
+ unsafe_flush_warning(s, "libssh2 >= 1.4.4");
+ return 0;
+}
+
+#endif /* !HAS_LIBSSH2_SFTP_FSYNC */
+
static int64_t ssh_getlength(BlockDriverState *bs)
{
BDRVSSHState *s = bs->opaque;
.bdrv_co_readv = ssh_co_readv,
.bdrv_co_writev = ssh_co_writev,
.bdrv_getlength = ssh_getlength,
+ .bdrv_co_flush_to_disk = ssh_co_flush,
.create_options = ssh_create_options,
};
fi
fi
+##########################################
+# libssh2_sftp_fsync probe
+
+if test "$libssh2" = "yes"; then
+ cat > $TMPC <<EOF
+#include <stdio.h>
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+int main(void) {
+ LIBSSH2_SESSION *session;
+ LIBSSH2_SFTP *sftp;
+ LIBSSH2_SFTP_HANDLE *sftp_handle;
+ session = libssh2_session_init ();
+ sftp = libssh2_sftp_init (session);
+ sftp_handle = libssh2_sftp_open (sftp, "/", 0, 0);
+ libssh2_sftp_fsync (sftp_handle);
+ return 0;
+}
+EOF
+ # libssh2_cflags/libssh2_libs defined in previous test.
+ if compile_prog "$libssh2_cflags" "$libssh2_libs" ; then
+ QEMU_CFLAGS="-DHAS_LIBSSH2_SFTP_FSYNC $QEMU_CFLAGS"
+ fi
+fi
+
##########################################
# linux-aio probe
Currently authentication must be done using ssh-agent. Other
authentication methods may be supported in future.
-Note: The ssh driver does not obey disk flush requests (ie. to commit
-data to the backing disk when the guest requests it). This is because
-the underlying protocol (SFTP) does not support this. Thus there is a
-risk of guest disk corruption if the remote server or network goes
-down during writes.
+Note: Many ssh servers do not support an @code{fsync}-style operation.
+The ssh driver cannot guarantee that disk flush requests are
+obeyed, and this causes a risk of disk corruption if the remote
+server or network goes down during writes. The driver will
+print a warning when @code{fsync} is not supported:
+
+warning: ssh server @code{ssh.example.com:22} does not support fsync
+
+With sufficiently new versions of libssh2 and OpenSSH, @code{fsync} is
+supported.
@node pcsys_network
@section Network emulation