Page MenuHomeFreeBSD

D8215.diff
No OneTemporary

D8215.diff

Index: contrib/hyperv/tools/hv_kvp_daemon.c
===================================================================
--- contrib/hyperv/tools/hv_kvp_daemon.c
+++ contrib/hyperv/tools/hv_kvp_daemon.c
@@ -54,7 +54,7 @@
#include <unistd.h>
#include "hv_kvp.h"
-
+#include "hv_common.h"
typedef uint8_t __u8;
typedef uint16_t __u16;
typedef uint32_t __u32;
@@ -782,11 +782,11 @@
}
if ((length - *offset) < addr_length + 1) {
- return (HV_KVP_E_FAIL);
+ return (HV_E_FAIL);
}
if (str == NULL) {
strlcpy(buffer, "inet_ntop failed\n", length);
- return (HV_KVP_E_FAIL);
+ return (HV_E_FAIL);
}
if (*offset == 0) {
strlcpy(buffer, tmp, length);
@@ -832,7 +832,7 @@
if (getifaddrs(&ifap)) {
strlcpy(buffer, "getifaddrs failed\n", buffer_length);
- return (HV_KVP_E_FAIL);
+ return (HV_E_FAIL);
}
curp = ifap;
@@ -954,7 +954,7 @@
ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
if (ret < 0) {
- return (HV_KVP_E_FAIL);
+ return (HV_E_FAIL);
}
return (0);
@@ -979,7 +979,7 @@
if (file == NULL) {
KVP_LOG(LOG_ERR, "FreeBSD Failed to open config file\n");
- return (HV_KVP_E_FAIL);
+ return (HV_E_FAIL);
}
/*
@@ -988,7 +988,7 @@
mac_addr = kvp_if_name_to_mac(if_name);
if (mac_addr == NULL) {
- error = HV_KVP_E_FAIL;
+ error = HV_E_FAIL;
goto kvp_set_ip_info_error;
}
/* MAC Address */
@@ -1096,13 +1096,13 @@
KVP_LOG(LOG_DEBUG, "In kvp_op_getipinfo.\n");
ip_val = &op_msg->body.kvp_ip_val;
- op_msg->hdr.error = HV_KVP_S_OK;
+ op_msg->hdr.error = HV_S_OK;
if_name = kvp_mac_to_if_name((char *)ip_val->adapter_id);
if (if_name == NULL) {
/* No interface found with the mac address. */
- op_msg->hdr.error = HV_KVP_E_FAIL;
+ op_msg->hdr.error = HV_E_FAIL;
goto kvp_op_getipinfo_done;
}
@@ -1126,13 +1126,13 @@
KVP_LOG(LOG_DEBUG, "In kvp_op_setipinfo.\n");
ip_val = &op_msg->body.kvp_ip_val;
- op_msg->hdr.error = HV_KVP_S_OK;
+ op_msg->hdr.error = HV_S_OK;
if_name = (char *)ip_val->adapter_id;
if (if_name == NULL) {
/* No adapter provided. */
- op_msg->hdr.error = HV_KVP_GUID_NOTFOUND;
+ op_msg->hdr.error = HV_GUID_NOTFOUND;
goto kvp_op_setipinfo_done;
}
@@ -1154,7 +1154,7 @@
assert(op_hdlr != NULL);
op_pool = op_msg->hdr.kvp_hdr.pool;
- op_msg->hdr.error = HV_KVP_S_OK;
+ op_msg->hdr.error = HV_S_OK;
switch(op_hdlr->kvp_op_key) {
case HV_KVP_OP_SET:
@@ -1198,7 +1198,7 @@
}
if (error != 0)
- op_msg->hdr.error = HV_KVP_S_CONT;
+ op_msg->hdr.error = HV_S_CONT;
return(error);
}
@@ -1216,7 +1216,7 @@
op = op_msg->hdr.kvp_hdr.operation;
op_pool = op_msg->hdr.kvp_hdr.pool;
- op_msg->hdr.error = HV_KVP_S_OK;
+ op_msg->hdr.error = HV_S_OK;
/*
* If the pool is not HV_KVP_POOL_AUTO, read from the appropriate
@@ -1229,7 +1229,7 @@
HV_KVP_EXCHANGE_MAX_KEY_SIZE,
op_msg->body.kvp_enum_data.data.msg_value.value,
HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) {
- op_msg->hdr.error = HV_KVP_S_CONT;
+ op_msg->hdr.error = HV_S_CONT;
error = -1;
}
goto kvp_op_enumerate_done;
@@ -1298,7 +1298,7 @@
KVP_LOG(LOG_ERR, "Auto pool Index %d not found.\n",
op_msg->body.kvp_enum_data.index);
#endif
- op_msg->hdr.error = HV_KVP_S_CONT;
+ op_msg->hdr.error = HV_S_CONT;
error = -1;
break;
}
@@ -1496,7 +1496,7 @@
*/
error = kvp_op_hdlrs[op].kvp_op_exec(hv_msg,
(void *)&kvp_op_hdlrs[op]);
- if (error != 0 && hv_msg->hdr.error != HV_KVP_S_CONT)
+ if (error != 0 && hv_msg->hdr.error != HV_S_CONT)
KVP_LOG(LOG_WARNING,
"Operation failed OP = %d, error = 0x%x\n",
op, error);
Index: contrib/hyperv/tools/hv_vss_daemon.c
===================================================================
--- /dev/null
+++ contrib/hyperv/tools/hv_vss_daemon.c
@@ -0,0 +1,251 @@
+#include <string.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <poll.h>
+#include <stdint.h>
+#include <syslog.h>
+#include <errno.h>
+#include <err.h>
+#include <fcntl.h>
+#include <ufs/ffs/fs.h>
+
+#include "hv_snapshot.h"
+#include "hv_common.h"
+
+#define _PATH_UFSSUSPEND "/dev/ufssuspend"
+#define UNDEF_FREEZE_THAW (0)
+#define FREEZE (1)
+#define THAW (2)
+#define UNOPENED_HANDLE (-2)
+
+#define VSS_LOG(priority, format, args...) do { \
+ if (is_debugging == 1) { \
+ if (is_daemon == 1) \
+ syslog(priority, format, ## args); \
+ else \
+ printf(format, ## args); \
+ } else { \
+ if (priority < LOG_DEBUG) { \
+ if (is_daemon == 1) \
+ syslog(priority, format, ## args); \
+ else \
+ printf(format, ## args); \
+ } \
+ } \
+ } while(0)
+
+static int is_daemon = 1;
+static int is_debugging = 0;
+static int g_ufs_suspend_handle = UNOPENED_HANDLE;
+
+static int
+freeze()
+{
+ struct statfs *mntbuf, *statfsp;
+ int mntsize;
+ int fso;
+ int error;
+ int i;
+ const char *dev = "/dev";
+
+ if (g_ufs_suspend_handle == UNOPENED_HANDLE)
+ g_ufs_suspend_handle = open(_PATH_UFSSUSPEND, O_RDWR);
+ if (g_ufs_suspend_handle == -1) {
+ VSS_LOG(LOG_ERR, "unable to open %s", _PATH_UFSSUSPEND);
+ error = 1;
+ goto handle_error;
+ }
+
+ mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+ if (mntsize == 0) {
+ VSS_LOG(LOG_ERR, "There is no mount information\n");
+ error = 1;
+ goto handle_error;
+ }
+ for(i = mntsize - 1; i >= 0; --i)
+ {
+ statfsp = &mntbuf[i];
+
+ if (strncmp(statfsp->f_mntonname, dev, strlen(dev)) == 0) {
+ continue; /* skip to freeze '/dev' */
+ } else if (statfsp->f_flags & MNT_RDONLY) {
+ continue; /* skip to freeze RDONLY partition */
+ } else if (strncmp(statfsp->f_fstypename, "ufs", 3) != 0) {
+ continue; /* only UFS can be freezed */
+ }
+ /* We have ensure that all disk writes have been completed */
+ sync();
+ error = ioctl(g_ufs_suspend_handle, UFSSUSPEND, &statfsp->f_fsid);
+ if (error != 0) {
+ VSS_LOG(LOG_ERR, "error: %d\n", errno);
+ } else {
+ VSS_LOG(LOG_INFO, "Successfully suspend fs: %s\n",
+ statfsp->f_mntonname);
+ }
+ }
+
+ return (0);
+handle_error:
+ return (error);
+}
+
+/**
+ * close the opened handle will thaw the FS.
+ */
+static int
+thaw()
+{
+ int error = 0;
+ if (g_ufs_suspend_handle != UNOPENED_HANDLE &&
+ g_ufs_suspend_handle != -1) {
+ error = close(g_ufs_suspend_handle);
+ if (!error) {
+ g_ufs_suspend_handle = UNOPENED_HANDLE;
+ VSS_LOG(LOG_INFO, "Successfully thaw the fs\n");
+ return (0);
+ } else {
+ VSS_LOG(LOG_ERR, "Fail to thaw the fs: "
+ "%d %s\n", errno, strerror(errno));
+ }
+ } else {
+ VSS_LOG(LOG_INFO, "The fs has already been thawed\n");
+ }
+
+ return (error);
+}
+
+static void usage(const char* cmd) {
+ fprintf(stderr, "%s -f : freeze the filesystem\n"
+ " -t : thaw the filesystem\n", cmd);
+ exit(1);
+}
+
+int main(int argc, char* argv[]) {
+ struct hv_vss_req hv_vss_buf;
+
+ struct pollfd hv_vss_poll_fd[1];
+ int ch, r, len, op, error;
+ int hv_vss_dev_fd;
+
+ int freeze_thaw = UNDEF_FREEZE_THAW;
+ while ((ch = getopt(argc, argv, "dn")) != -1) {
+ switch (ch) {
+ case 'n':
+ /* Run as regular process for debugging purpose. */
+ is_daemon = 0;
+ break;
+ case 'd':
+ /* Generate debugging output */
+ is_debugging = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ openlog("HV_VSS", 0, LOG_USER);
+
+ /* Become daemon first. */
+ if (is_daemon == 1)
+ daemon(1, 0);
+ else
+ VSS_LOG(LOG_DEBUG, "Run as regular process.\n");
+
+ VSS_LOG(LOG_INFO, "HV_VSS starting; pid is: %d\n", getpid());
+
+ hv_vss_dev_fd = open("/dev/hv_vss_dev", O_RDWR);
+
+ if (hv_vss_dev_fd < 0) {
+ VSS_LOG(LOG_ERR, "Fail to open /dev/hv_vss_dev, error: %d %s\n",
+ errno, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ hv_vss_poll_fd[0].fd = hv_vss_dev_fd;
+ hv_vss_poll_fd[0].events = (POLLIN | POLLRDNORM);
+
+ memset(&hv_vss_buf, 0, sizeof(hv_vss_buf));
+ hv_vss_buf.msg.hdr.vss_hdr.operation = VSS_OP_REGISTER;
+ len = write(hv_vss_dev_fd, &hv_vss_buf, sizeof(hv_vss_buf));
+ VSS_LOG(LOG_INFO, "register to kernel\n");
+
+ while (1) {
+ r = poll(hv_vss_poll_fd, 1, INFTIM);
+
+ VSS_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n",
+ r, hv_vss_poll_fd[0].revents);
+
+ if (r == 0 || (r < 0 && errno == EAGAIN) ||
+ (r < 0 && errno == EINTR)) {
+ /* Nothing to read */
+ continue;
+ }
+
+ if (r < 0) {
+ /*
+ * For poll return failure other than EAGAIN,
+ * we want to exit.
+ */
+ VSS_LOG(LOG_ERR, "Poll failed.\n");
+ perror("poll");
+ exit(EIO);
+ }
+
+ /* Read from character device */
+ len = pread(hv_vss_dev_fd, &hv_vss_buf,
+ sizeof(hv_vss_buf), 0);
+
+ if (len < 0) {
+ VSS_LOG(LOG_ERR, "Read failed.\n");
+ perror("pread");
+ exit(EIO);
+ }
+
+ if (len != sizeof(struct hv_vss_req)) {
+ VSS_LOG(LOG_ERR, "read len is: %d\n", len);
+ continue;
+ }
+
+ /*
+ * We will use the KVP header information to pass back
+ * the error from this daemon. So, first save the op
+ * and pool info to local variables.
+ */
+
+ op = hv_vss_buf.msg.hdr.vss_hdr.operation;
+
+ switch (op) {
+ case VSS_OP_FREEZE:
+ error = freeze();
+ break;
+ case VSS_OP_THAW:
+ error = thaw();
+ break;
+ default:
+ VSS_LOG(LOG_ERR, "Illegal operation: %d\n", op);
+ }
+ if (error != 0) {
+ error = HV_E_FAIL;
+ } else {
+ error = HV_S_OK;
+ }
+ hv_vss_buf.msg.hdr.error = error;
+ len = pwrite(hv_vss_dev_fd, &hv_vss_buf, sizeof(hv_vss_buf), 0);
+ if (len != sizeof(struct hv_vss_req)) {
+ VSS_LOG(LOG_ERR, "Fail to write to device:"
+ " %d != expect %ld\n", len, sizeof(struct hv_vss_req));
+ exit(EXIT_FAILURE);
+ } else {
+ VSS_LOG(LOG_INFO, "Send response %d for %s to kernel\n",
+ error, op == VSS_OP_FREEZE ? "Freeze" : "Thaw");
+ }
+ }
+
+ return (0);
+}
Index: etc/devd/hyperv.conf
===================================================================
--- etc/devd/hyperv.conf
+++ etc/devd/hyperv.conf
@@ -17,3 +17,19 @@
match "cdev" "hv_kvp_dev";
action "pkill -x hv_kvp_daemon";
};
+
+notify 11 {
+ match "system" "DEVFS";
+ match "subsystem" "CDEV";
+ match "type" "CREATE";
+ match "cdev" "hv_vss_dev";
+ action "/usr/sbin/hv_vss_daemon";
+};
+
+notify 11 {
+ match "system" "DEVFS";
+ match "subsystem" "CDEV";
+ match "type" "DESTROY";
+ match "cdev" "hv_vss_dev";
+ action "pkill -x hv_vss_daemon";
+};
Index: sys/conf/files.amd64
===================================================================
--- sys/conf/files.amd64
+++ sys/conf/files.amd64
@@ -297,6 +297,7 @@
dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c optional hyperv
dev/hyperv/utilities/hv_heartbeat.c optional hyperv
dev/hyperv/utilities/hv_kvp.c optional hyperv
+dev/hyperv/utilities/hv_snapshot.c optional hyperv
dev/hyperv/utilities/hv_shutdown.c optional hyperv
dev/hyperv/utilities/hv_timesync.c optional hyperv
dev/hyperv/utilities/hv_util.c optional hyperv
Index: sys/conf/files.i386
===================================================================
--- sys/conf/files.i386
+++ sys/conf/files.i386
@@ -254,6 +254,7 @@
dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c optional hyperv
dev/hyperv/utilities/hv_heartbeat.c optional hyperv
dev/hyperv/utilities/hv_kvp.c optional hyperv
+dev/hyperv/utilities/hv_snapshot.c optional hyperv
dev/hyperv/utilities/hv_shutdown.c optional hyperv
dev/hyperv/utilities/hv_timesync.c optional hyperv
dev/hyperv/utilities/hv_util.c optional hyperv
Index: sys/dev/hyperv/utilities/hv_common.h
===================================================================
--- sys/dev/hyperv/utilities/hv_common.h
+++ sys/dev/hyperv/utilities/hv_common.h
@@ -27,33 +27,32 @@
*
* $FreeBSD$
*/
-
-#ifndef _HVUTIL_H_
-#define _HVUTIL_H_
-
-#include <dev/hyperv/include/hyperv.h>
-#include <dev/hyperv/include/vmbus.h>
-
-/**
- * hv_util related structures
- *
+#ifndef _HVCOMMON_H_
+#define _HVCOMMON_H_
+/*
+ * Some Hyper-V status codes.
*/
-typedef struct hv_util_sc {
- device_t ic_dev;
- uint8_t *receive_buffer;
- int ic_buflen;
-} hv_util_sc;
+#define HV_S_OK 0x00000000
+#define HV_E_FAIL 0x80004005
+#define HV_S_CONT 0x80070103
+#define HV_ERROR_NOT_SUPPORTED 0x80070032
+#define HV_ERROR_MACHINE_LOCKED 0x800704F7
+#define HV_ERROR_DEVICE_NOT_CONNECTED 0x8007048F
+#define HV_INVALIDARG 0x80070057
+#define HV_GUID_NOTFOUND 0x80041002
-struct vmbus_ic_desc {
- const struct hyperv_guid ic_guid;
- const char *ic_desc;
-};
+/*
+ * Framework version for util services.
+ */
+#define UTIL_FW_MINOR 0
-#define VMBUS_IC_DESC_END { .ic_desc = NULL }
+#define UTIL_WS2K8_FW_MAJOR 1
+#define UTIL_WS2K8_FW_VERSION (UTIL_WS2K8_FW_MAJOR << 16 | UTIL_FW_MINOR)
-int hv_util_attach(device_t dev, vmbus_chan_callback_t cb);
-int hv_util_detach(device_t dev);
-int vmbus_ic_probe(device_t dev, const struct vmbus_ic_desc descs[]);
-int vmbus_ic_negomsg(struct hv_util_sc *, void *data, int *dlen);
+#define UTIL_FW_MAJOR 3
+#define UTIL_FW_VERSION (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR)
+/* status returned to daemon */
+#define SUCCESS (0)
+#define ERROR (1)
#endif
Index: sys/dev/hyperv/utilities/hv_kvp.h
===================================================================
--- sys/dev/hyperv/utilities/hv_kvp.h
+++ sys/dev/hyperv/utilities/hv_kvp.h
@@ -119,7 +119,13 @@
#define HV_REG_U32 4
#define HV_REG_U64 8
+#define ADDR_FAMILY_NONE 0x00
+#define ADDR_FAMILY_IPV4 0x01
+#define ADDR_FAMILY_IPV6 0x02
+#define MAX_ADAPTER_ID_SIZE 128
+#define MAX_IP_ADDR_SIZE 1024
+#define MAX_GATEWAY_SIZE 512
/*
* Daemon code supporting IP injection.
*/
@@ -145,28 +151,6 @@
HV_KVP_POOL_COUNT /* Number of pools, must be last. */
};
-
-/*
- * Some Hyper-V status codes.
- */
-#define HV_KVP_S_OK 0x00000000
-#define HV_KVP_E_FAIL 0x80004005
-#define HV_KVP_S_CONT 0x80070103
-#define HV_ERROR_NOT_SUPPORTED 0x80070032
-#define HV_ERROR_MACHINE_LOCKED 0x800704F7
-#define HV_ERROR_DEVICE_NOT_CONNECTED 0x8007048F
-#define HV_INVALIDARG 0x80070057
-#define HV_KVP_GUID_NOTFOUND 0x80041002
-
-#define ADDR_FAMILY_NONE 0x00
-#define ADDR_FAMILY_IPV4 0x01
-#define ADDR_FAMILY_IPV6 0x02
-
-#define MAX_ADAPTER_ID_SIZE 128
-#define MAX_IP_ADDR_SIZE 1024
-#define MAX_GATEWAY_SIZE 512
-
-
struct hv_kvp_ipaddr_value {
uint16_t adapter_id[MAX_ADAPTER_ID_SIZE];
uint8_t addr_family;
Index: sys/dev/hyperv/utilities/hv_kvp.c
===================================================================
--- sys/dev/hyperv/utilities/hv_kvp.c
+++ sys/dev/hyperv/utilities/hv_kvp.c
@@ -62,16 +62,32 @@
#include <dev/hyperv/include/hyperv.h>
#include <dev/hyperv/utilities/hv_utilreg.h>
+#include <dev/hyperv/include/vmbus.h>
#include "hv_util.h"
#include "unicode.h"
#include "hv_kvp.h"
+#include "hv_common.h"
#include "vmbus_if.h"
+/*
+ * Pre win8 version numbers used in ws2008 and ws 2008 r2 (win7)
+ */
+#define WS2008_SRV_MAJOR 1
+#define WS2008_SRV_MINOR 0
+#define WS2008_SRV_VERSION (WS2008_SRV_MAJOR << 16 | WS2008_SRV_MINOR)
+
+#define WIN7_SRV_MAJOR 3
+#define WIN7_SRV_MINOR 0
+#define WIN7_SRV_VERSION (WIN7_SRV_MAJOR << 16 | WIN7_SRV_MINOR)
+
+#define WIN8_SRV_MAJOR 4
+#define WIN8_SRV_MINOR 0
+#define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
+
+
/* hv_kvp defines */
#define BUFFERSIZE sizeof(struct hv_kvp_msg)
-#define KVP_SUCCESS 0
-#define KVP_ERROR 1
#define kvp_hdr hdr.kvp_hdr
/* hv_kvp debug control */
@@ -214,47 +230,6 @@
/*
- * hv_kvp - version neogtiation function
- */
-static void
-hv_kvp_negotiate_version(struct hv_vmbus_icmsg_hdr *icmsghdrp, uint8_t *buf)
-{
- struct hv_vmbus_icmsg_negotiate *negop;
- int icframe_vercnt;
- int icmsg_vercnt;
-
- icmsghdrp->icmsgsize = 0x10;
-
- negop = (struct hv_vmbus_icmsg_negotiate *)&buf[
- sizeof(struct hv_vmbus_pipe_hdr) +
- sizeof(struct hv_vmbus_icmsg_hdr)];
- icframe_vercnt = negop->icframe_vercnt;
- icmsg_vercnt = negop->icmsg_vercnt;
-
- /*
- * Select the framework version number we will support
- */
- if ((icframe_vercnt >= 2) && (negop->icversion_data[1].major == 3)) {
- icframe_vercnt = 3;
- if (icmsg_vercnt > 2)
- icmsg_vercnt = 4;
- else
- icmsg_vercnt = 3;
- } else {
- icframe_vercnt = 1;
- icmsg_vercnt = 1;
- }
-
- negop->icframe_vercnt = 1;
- negop->icmsg_vercnt = 1;
- negop->icversion_data[0].major = icframe_vercnt;
- negop->icversion_data[0].minor = 0;
- negop->icversion_data[1].major = icmsg_vercnt;
- negop->icversion_data[1].minor = 0;
-}
-
-
-/*
* Convert ip related info in umsg from utf8 to utf16 and store in hmsg
*/
static int
@@ -514,7 +489,7 @@
case HV_KVP_OP_SET_IP_INFO:
case HV_KVP_OP_SET:
case HV_KVP_OP_DELETE:
- return (KVP_SUCCESS);
+ return (SUCCESS);
case HV_KVP_OP_ENUMERATE:
host_exchg_data = &hmsg->body.kvp_enum_data.data;
@@ -535,9 +510,9 @@
host_exchg_data->value_type = HV_REG_SZ;
if ((hkey_len < 0) || (hvalue_len < 0))
- return (HV_KVP_E_FAIL);
+ return (HV_E_FAIL);
- return (KVP_SUCCESS);
+ return (SUCCESS);
case HV_KVP_OP_GET:
host_exchg_data = &hmsg->body.kvp_get.data;
@@ -553,12 +528,12 @@
host_exchg_data->value_type = HV_REG_SZ;
if ((hkey_len < 0) || (hvalue_len < 0))
- return (HV_KVP_E_FAIL);
+ return (HV_E_FAIL);
- return (KVP_SUCCESS);
+ return (SUCCESS);
default:
- return (HV_KVP_E_FAIL);
+ return (HV_E_FAIL);
}
}
@@ -575,7 +550,7 @@
&sc->rcv_buf[sizeof(struct hv_vmbus_pipe_hdr)];
if (error)
- error = HV_KVP_E_FAIL;
+ error = HV_E_FAIL;
hv_icmsg_hdrp->status = error;
hv_icmsg_hdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE;
@@ -623,11 +598,15 @@
uint64_t requestid;
struct hv_vmbus_icmsg_hdr *icmsghdrp;
int ret = 0;
- hv_kvp_sc *sc;
+ hv_kvp_sc *sc;
+ uint32_t vmbus_version;
+ int util_ver, kvp_ver;
hv_kvp_log_info("%s: entering hv_kvp_process_request\n", __func__);
sc = (hv_kvp_sc*)context;
+
+ vmbus_version = VMBUS_GET_VERSION(device_get_parent(sc->dev), sc->dev);
kvp_buf = sc->util_sc.receive_buffer;
channel = vmbus_get_channel(sc->dev);
@@ -643,7 +622,18 @@
hv_kvp_transaction_init(sc, recvlen, requestid, kvp_buf);
if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
- hv_kvp_negotiate_version(icmsghdrp, kvp_buf);
+ switch(vmbus_version) {
+ case VMBUS_VERSION_WS2008:
+ util_ver = UTIL_WS2K8_FW_VERSION;
+ kvp_ver = WS2008_SRV_VERSION;
+ case VMBUS_VERSION_WIN7:
+ util_ver = UTIL_FW_VERSION;
+ kvp_ver = WIN7_SRV_VERSION;
+ default:
+ util_ver = UTIL_FW_VERSION;
+ kvp_ver = WIN8_SRV_VERSION;
+ }
+ hv_util_negotiate_version(kvp_buf, util_ver, kvp_ver);
hv_kvp_respond_host(sc, ret);
/*
@@ -689,7 +679,7 @@
*/
if (hv_kvp_req_in_progress(sc)) {
hv_kvp_log_info("%s: request was still active after wait so failing\n", __func__);
- hv_kvp_respond_host(sc, HV_KVP_E_FAIL);
+ hv_kvp_respond_host(sc, HV_E_FAIL);
sc->req_in_progress = false;
}
@@ -771,7 +761,7 @@
/* Check hv_kvp daemon registration status*/
if (!sc->register_done)
- return (KVP_ERROR);
+ return (ERROR);
sema_wait(&sc->dev_sema);
@@ -821,7 +811,7 @@
}
else {
hv_kvp_log_info("%s, KVP Registration Failed\n", __func__);
- return (KVP_ERROR);
+ return (ERROR);
}
} else {
@@ -832,7 +822,7 @@
struct hv_kvp_msg *umsg = &sc->daemon_kvp_msg;
hv_kvp_convert_usermsg_to_hostmsg(umsg, hmsg);
- hv_kvp_respond_host(sc, KVP_SUCCESS);
+ hv_kvp_respond_host(sc, SUCCESS);
wakeup(sc);
sc->req_in_progress = false;
}
Index: sys/dev/hyperv/utilities/hv_snapshot.h
===================================================================
--- /dev/null
+++ sys/dev/hyperv/utilities/hv_snapshot.h
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2016 Microsoft Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _VSS_H
+#define _VSS_H
+
+#define VSS_MAJOR 5
+#define VSS_MINOR 0
+#define VSS_VERSION (VSS_MAJOR << 16 | VSS_MINOR)
+
+/*
+ * Implementation of host controlled snapshot of the guest.
+ */
+#define VSS_OP_REGISTER 128
+
+/*
+ Daemon code with full handshake support.
+ */
+#define VSS_OP_REGISTER1 129
+
+enum hv_vss_op {
+ VSS_OP_CREATE = 0,
+ VSS_OP_DELETE,
+ VSS_OP_HOT_BACKUP,
+ VSS_OP_GET_DM_INFO,
+ VSS_OP_BU_COMPLETE,
+ /*
+ * Following operations are only supported with IC version >= 5.0
+ */
+ VSS_OP_FREEZE, /* Freeze the file systems in the VM */
+ VSS_OP_THAW, /* Unfreeze the file systems */
+ VSS_OP_AUTO_RECOVER,
+ VSS_OP_COUNT /* Number of operations, must be last */
+};
+
+
+/*
+ * Header for all VSS messages.
+ */
+struct hv_vss_hdr {
+ uint8_t operation;
+ uint8_t reserved[7];
+} __attribute__((packed));
+
+
+/*
+ * Flag values for the hv_vss_check_feature. Here supports only
+ * one value.
+ */
+#define VSS_HBU_NO_AUTO_RECOVERY 0x00000005
+
+struct hv_vss_check_feature {
+ uint32_t flags;
+} __attribute__((packed));
+
+struct hv_vss_check_dm_info {
+ uint32_t flags;
+} __attribute__((packed));
+
+struct hv_vss_msg {
+ union {
+ struct hv_vss_hdr vss_hdr;
+ int error;
+ } hdr;
+ union {
+ struct hv_vss_check_feature vss_cf;
+ struct hv_vss_check_dm_info dm_info;
+ } body;
+} __attribute__((packed));
+
+struct hv_vss_req {
+ uint64_t req_id;
+ struct hv_vss_msg msg;
+} __attribute__((packed));
+#endif
Index: sys/dev/hyperv/utilities/hv_snapshot.c
===================================================================
--- /dev/null
+++ sys/dev/hyperv/utilities/hv_snapshot.c
@@ -0,0 +1,643 @@
+/*-
+ * Copyright (c) 2016 Microsoft Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/taskqueue.h>
+#include <sys/selinfo.h>
+#include <sys/sysctl.h>
+#include <sys/poll.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/kthread.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysproto.h>
+#include <sys/un.h>
+#include <sys/endian.h>
+#include <sys/sema.h>
+#include <sys/signal.h>
+#include <sys/syslog.h>
+#include <sys/systm.h>
+#include <sys/mutex.h>
+#include <sys/callout.h>
+
+#include <dev/hyperv/include/hyperv.h>
+#include <dev/hyperv/utilities/hv_utilreg.h>
+#include <dev/hyperv/utilities/vmbus_icreg.h>
+
+#include "hv_util.h"
+#include "hv_snapshot.h"
+#include "hv_common.h"
+#include "vmbus_if.h"
+
+#define BUFFERSIZE sizeof(struct hv_vss_req)
+
+/* hv_vss debug control */
+static int hv_vss_log = 0;
+
+#define hv_vss_log_error(...) do { \
+ if (hv_vss_log > 0) \
+ log(LOG_ERR, "hv_vss: " __VA_ARGS__); \
+} while (0)
+
+#define hv_vss_log_info(...) do { \
+ if (hv_vss_log > 1) \
+ log(LOG_INFO, "hv_vss: " __VA_ARGS__); \
+} while (0)
+
+static const struct vmbus_ic_desc vmbus_vss_descs[] = {
+ {
+ .ic_guid = { .hv_guid = {
+ 0x29, 0x2e, 0xfa, 0x35, 0x23, 0xea, 0x36, 0x42,
+ 0x96, 0xae, 0x3a, 0x6e, 0xba, 0xcb, 0xa4, 0x40} },
+ .ic_desc = "Hyper-V VSS"
+ },
+ VMBUS_IC_DESC_END
+};
+
+/* character device prototypes */
+static d_open_t hv_vss_dev_open;
+static d_close_t hv_vss_dev_close;
+static d_read_t hv_vss_dev_daemon_read;
+static d_write_t hv_vss_dev_daemon_write;
+static d_poll_t hv_vss_dev_daemon_poll;
+
+/* hv_vss character device structure */
+static struct cdevsw hv_vss_cdevsw =
+{
+ .d_version = D_VERSION,
+ .d_open = hv_vss_dev_open,
+ .d_close = hv_vss_dev_close,
+ .d_read = hv_vss_dev_daemon_read,
+ .d_write = hv_vss_dev_daemon_write,
+ .d_poll = hv_vss_dev_daemon_poll,
+ .d_name = "hv_vss_dev",
+};
+
+/*
+ * Global state to track and synchronize multiple
+ * KVP transaction requests from the host.
+ */
+typedef struct hv_vss_sc {
+ struct hv_util_sc util_sc;
+ device_t dev;
+
+ struct task task;
+
+ /*
+ * mutex is used to protect access of list/queue,
+ * callout in request is also used this mutex.
+ */
+ struct mtx pending_mutex;
+ /*
+ * req_free_list contains all free items
+ */
+ LIST_HEAD(, hv_vss_req_internal) req_free_list;
+ /*
+ * msg was transfered from host to daemon_read, and
+ * daemon_write. Finally, it was recyled to free list.
+ */
+ STAILQ_HEAD(, hv_vss_req_internal) to_daemon_msg_queue;
+ STAILQ_HEAD(, hv_vss_req_internal) to_host_msg_queue;
+
+ /* Indicates if daemon registered with driver */
+ boolean_t register_done;
+
+ /* Character device status */
+ boolean_t dev_accessed;
+
+ struct cdev *hv_vss_dev;
+
+ struct proc *daemon_task;
+
+ struct selinfo hv_vss_selinfo;
+} hv_vss_sc;
+
+typedef struct hv_vss_req_internal {
+ LIST_ENTRY(hv_vss_req_internal) link;
+ STAILQ_ENTRY(hv_vss_req_internal) slink;
+ struct hv_vss_req vss_req;
+
+ /* Rcv buffer for communicating with the host*/
+ uint8_t *rcv_buf;
+ /* Length of host message */
+ uint32_t host_msg_len;
+ /* Host message id */
+ uint64_t host_msg_id;
+
+ hv_vss_sc *sc;
+
+ struct callout callout;
+} hv_vss_req_internal;
+
+/*
+ * Callback routine that gets called whenever there is a message from host
+ */
+static void
+hv_vss_callback(struct vmbus_channel *chan __unused, void *context)
+{
+ hv_vss_sc *sc = (hv_vss_sc*)context;
+ /*
+ The first request from host will not be handled until daemon is registered.
+ when callback is triggered without a registered daemon, callback just return.
+ When a new daemon gets regsitered, this callbcak is trigged from _write op.
+ */
+ if (sc->register_done) {
+ hv_vss_log_info("%s: Queuing work item\n", __func__);
+ taskqueue_enqueue(taskqueue_thread, &sc->task);
+ }
+}
+/*
+ * Send the response back to the host.
+ */
+static void
+hv_vss_respond_host(uint8_t *rcv_buf, struct vmbus_channel *ch,
+ uint32_t recvlen, uint64_t requestid, int error)
+{
+ struct hv_vmbus_icmsg_hdr *hv_icmsg_hdrp;
+
+ hv_icmsg_hdrp = (struct hv_vmbus_icmsg_hdr *)
+ &rcv_buf[sizeof(struct hv_vmbus_pipe_hdr)];
+
+ if (error)
+ error = HV_E_FAIL;
+
+ hv_icmsg_hdrp->status = error;
+ hv_icmsg_hdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE;
+
+ error = vmbus_chan_send(ch, VMBUS_CHANPKT_TYPE_INBAND, 0,
+ rcv_buf, recvlen, requestid);
+ if (error)
+ hv_vss_log_info("%s: hv_vss_respond_host: sendpacket error:%d\n",
+ __func__, error);
+}
+
+static int
+hv_vss_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ hv_vss_sc *sc = (hv_vss_sc*)dev->si_drv1;
+
+ hv_vss_log_info("%s: Opened device \"hv_vss_device\" successfully.\n", __func__);
+ if (sc->dev_accessed)
+ return (-EBUSY);
+
+ sc->daemon_task = curproc;
+ sc->dev_accessed = true;
+ return (0);
+}
+
+static int
+hv_vss_dev_close(struct cdev *dev __unused, int fflag __unused, int devtype __unused,
+ struct thread *td __unused)
+{
+ hv_vss_sc *sc = (hv_vss_sc*)dev->si_drv1;
+
+ hv_vss_log_info("%s: Closing device \"hv_vss_device\".\n", __func__);
+ sc->dev_accessed = false;
+ sc->register_done = false;
+ return (0);
+}
+
+/*
+ * hv_vss_daemon read invokes this function
+ * acts as a send to daemon
+ */
+static int
+hv_vss_dev_daemon_read(struct cdev *dev, struct uio *uio, int ioflag __unused)
+{
+ size_t amt;
+ int error = 0;
+ struct hv_vss_req_internal* reqp;
+ struct hv_vss_req *hv_vss_dev_buf;
+ hv_vss_sc *sc = (hv_vss_sc*)dev->si_drv1;
+
+ hv_vss_log_info("%s: entered\n", __func__);
+ /* Check hv_vss daemon registration status */
+ if (!sc->register_done)
+ return (ERROR);
+
+ if (uio->uio_resid < BUFFERSIZE) {
+ return (EAGAIN);
+ }
+
+ amt = MIN(uio->uio_resid, BUFFERSIZE);
+ mtx_lock(&sc->pending_mutex);
+ if (!STAILQ_EMPTY(&sc->to_daemon_msg_queue)) {
+ reqp = STAILQ_FIRST(&sc->to_daemon_msg_queue);
+ hv_vss_dev_buf = &reqp->vss_req;
+ if ((error = uiomove(hv_vss_dev_buf, amt, uio)) != 0) {
+ hv_vss_log_info("%s: hv_vss uiomove read failed!\n", __func__);
+ }
+ hv_vss_log_info("%s, read data from daemon for %s (%ld) \n",
+ __func__,
+ reqp->vss_req.msg.hdr.vss_hdr.operation == VSS_OP_FREEZE ?
+ "Freeze" : "Thaw", reqp->vss_req.req_id);
+ STAILQ_REMOVE_HEAD(&sc->to_daemon_msg_queue, slink);
+ /* insert the msg to queue for write */
+ STAILQ_INSERT_TAIL(&sc->to_host_msg_queue, reqp, slink);
+ }
+ mtx_unlock(&sc->pending_mutex);
+
+ return (error);
+}
+
+/*
+ * hv_vss_daemon write invokes this function
+ * acts as a receive from daemon
+ */
+static int
+hv_vss_dev_daemon_write(struct cdev *dev, struct uio *uio, int ioflag __unused)
+{
+ size_t amt;
+ int error = 0;
+ struct hv_vss_req hv_vss_dev_buf;
+ struct hv_vss_req_internal *reqp, *tmp;
+ uint64_t req_id;
+ hv_vss_sc *sc = (hv_vss_sc*)dev->si_drv1;
+
+ uio->uio_offset = 0;
+ hv_vss_log_info("%s: entered\n", __func__);
+ amt = MIN(uio->uio_resid, BUFFERSIZE);
+ error = uiomove(&hv_vss_dev_buf, amt, uio);
+
+ if (error != 0) {
+ return (error);
+ }
+
+ if (sc->register_done == false) {
+ if (hv_vss_dev_buf.msg.hdr.vss_hdr.operation == VSS_OP_REGISTER) {
+ sc->register_done = true;
+ hv_vss_callback(vmbus_get_channel(sc->dev), dev->si_drv1);
+ }
+ else {
+ hv_vss_log_info("%s, VSS Registration Failed\n", __func__);
+ return (ERROR);
+ }
+ } else {
+ /*
+ * search the origin request which was read by daemon
+ * to cancel it timeout check.
+ */
+ req_id = hv_vss_dev_buf.req_id;
+ mtx_lock(&sc->pending_mutex);
+ STAILQ_FOREACH_SAFE(reqp, &sc->to_host_msg_queue, slink, tmp) {
+ if (reqp->vss_req.req_id == req_id) {
+ STAILQ_REMOVE(&sc->to_host_msg_queue,
+ reqp, hv_vss_req_internal, slink);
+ break;
+ }
+ }
+ mtx_unlock(&sc->pending_mutex);
+ callout_drain(&reqp->callout);
+ memcpy(&reqp->vss_req, &hv_vss_dev_buf, BUFFERSIZE);
+ hv_vss_log_info("%s, get response from daemon for %s (%ld) \n",
+ __func__,
+ reqp->vss_req.msg.hdr.vss_hdr.operation == VSS_OP_FREEZE ?
+ "Freeze" : "Thaw", reqp->vss_req.req_id);
+ hv_vss_respond_host(reqp->rcv_buf,
+ vmbus_get_channel(reqp->sc->dev),
+ reqp->host_msg_len, reqp->host_msg_id, SUCCESS);
+ /* recycle the request */
+ LIST_INSERT_HEAD(&sc->req_free_list, reqp, link);
+ }
+
+ return (error);
+}
+
+
+/*
+ * hv_vss_daemon poll invokes this function to check if data is available
+ * for daemon to read.
+ */
+static int
+hv_vss_dev_daemon_poll(struct cdev *dev, int events, struct thread *td)
+{
+ int revent = 0;
+ hv_vss_sc *sc = (hv_vss_sc*)dev->si_drv1;
+
+ mtx_lock(&sc->pending_mutex);
+ /**
+ * if there is data ready, inform daemon's poll
+ */
+ if (!STAILQ_EMPTY(&sc->to_daemon_msg_queue)) {
+ revent = POLLIN;
+ }
+ mtx_unlock(&sc->pending_mutex);
+ selrecord(td, &sc->hv_vss_selinfo);
+
+ hv_vss_log_info("%s return 0x%x\n", __func__, revent);
+ return (revent);
+}
+
+static void
+hv_vss_timeout(void *arg)
+{
+ hv_vss_req_internal *reqp = arg;
+ hv_vss_log_info("request sent to daemon timeout\n");
+ hv_vss_respond_host(reqp->rcv_buf,
+ vmbus_get_channel(reqp->sc->dev),
+ reqp->host_msg_len, reqp->host_msg_id, ERROR);
+}
+
+/*
+ * This routine is called whenever a message is received from the host
+ */
+static void
+hv_vss_init_req(hv_vss_req_internal *reqp,
+ uint32_t recvlen, uint64_t requestid, uint8_t *vss_buf, hv_vss_sc *sc)
+{
+ struct timespec vm_ts;
+ int msgoff = sizeof(struct hv_vmbus_pipe_hdr) +
+ sizeof(struct hv_vmbus_icmsg_hdr);
+
+ memset(reqp, 0, __offsetof(hv_vss_req_internal, callout));
+ reqp->host_msg_len = recvlen;
+ reqp->host_msg_id = requestid;
+ reqp->rcv_buf = vss_buf;
+ reqp->sc = sc;
+ memcpy(&reqp->vss_req.msg,
+ (struct hv_vss_msg *)&vss_buf[msgoff], sizeof(struct hv_vss_msg));
+ /* Use a timestamp as msg request ID */
+ nanotime(&vm_ts);
+ reqp->vss_req.req_id = (vm_ts.tv_sec * NANOSEC) + vm_ts.tv_nsec;
+}
+
+/*
+ * Function to read the vss request buffer from host
+ * and interact with daemon
+ */
+static void
+hv_vss_process_request(void *context, int pending __unused)
+{
+ uint8_t *vss_buf;
+ struct vmbus_channel *channel;
+ uint32_t recvlen = 0;
+ uint64_t requestid;
+ struct hv_vmbus_icmsg_hdr *icmsghdrp;
+ int ret = 0;
+ hv_vss_sc *sc;
+ hv_vss_req_internal *reqp;
+ int msgoff = sizeof(struct hv_vmbus_pipe_hdr) +
+ sizeof(struct hv_vmbus_icmsg_hdr);
+
+ hv_vss_log_info("%s: entering hv_vss_process_request\n", __func__);
+
+ sc = (hv_vss_sc*)context;
+ vss_buf = sc->util_sc.receive_buffer;
+ channel = vmbus_get_channel(sc->dev);
+
+ recvlen = sc->util_sc.ic_buflen;
+ ret = vmbus_chan_recv(channel, vss_buf, &recvlen, &requestid);
+ KASSERT(ret != ENOBUFS, ("hvvss recvbuf is not large enough"));
+ /* XXX check recvlen to make sure that it contains enough data */
+
+ while ((ret == 0) && (recvlen > 0)) {
+ icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
+ &vss_buf[sizeof(struct hv_vmbus_pipe_hdr)];
+
+ if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
+ hv_util_negotiate_version(vss_buf, UTIL_FW_VERSION,
+ VSS_VERSION);
+ hv_vss_respond_host(vss_buf, vmbus_get_channel(sc->dev),
+ recvlen, requestid, ret);
+ hv_vss_log_info("%s: version negotiated\n", __func__);
+ } else {
+ struct hv_vss_msg* msg = (struct hv_vss_msg *)&vss_buf[msgoff];
+ switch(msg->hdr.vss_hdr.operation) {
+ case VSS_OP_FREEZE:
+ case VSS_OP_THAW:
+ mtx_lock(&sc->pending_mutex);
+ if (!STAILQ_EMPTY(&sc->to_daemon_msg_queue) ||
+ !STAILQ_EMPTY(&sc->to_host_msg_queue)) {
+ /*
+ * There is request coming from host before
+ * finishing previous requests
+ */
+ hv_vss_log_info("%s: Warning: "
+ "there is new request "
+ "coming before finishing "
+ "previous requests\n",
+ __func__);
+ }
+ if (!LIST_EMPTY(&sc->req_free_list)) {
+ reqp = LIST_FIRST(&sc->req_free_list);
+ hv_vss_init_req(reqp, recvlen, requestid,
+ vss_buf, sc);
+ STAILQ_INSERT_TAIL(&sc->to_daemon_msg_queue,
+ reqp, slink);
+ hv_vss_log_info("%s: issuing query %s"
+ " (%ld) to daemon\n",
+ __func__,
+ msg->hdr.vss_hdr.operation ==
+ VSS_OP_FREEZE ?
+ "Freeze" : "Thaw",
+ reqp->vss_req.req_id);
+ /*
+ * We should wake up the daemon,
+ * in case it's doing poll()
+ */
+ selwakeup(&sc->hv_vss_selinfo);
+ /*
+ * The response should be received after 5s,
+ * otherwise, trigger timeout.
+ */
+ callout_reset_sbt(&reqp->callout,
+ SBT_1S * 5, 0, hv_vss_timeout, reqp, 0);
+ } else {
+ /* TODO Error: no buffer */
+ hv_vss_log_info("Error: No buffer\n");
+ }
+ mtx_unlock(&sc->pending_mutex);
+
+ break;
+ case VSS_OP_HOT_BACKUP:
+ msg->body.vss_cf.flags =
+ VSS_HBU_NO_AUTO_RECOVERY;
+ hv_vss_respond_host(vss_buf,
+ vmbus_get_channel(sc->dev),
+ recvlen, requestid, 0);
+ break;
+ case VSS_OP_GET_DM_INFO:
+ msg->body.dm_info.flags = 0;
+ hv_vss_respond_host(vss_buf,
+ vmbus_get_channel(sc->dev),
+ recvlen, requestid, 0);
+ break;
+ default:
+ printf("Unknown operation from host: %d\n",
+ msg->hdr.vss_hdr.operation);
+ break;
+ }
+ }
+
+ /*
+ * Try reading next buffer
+ */
+ recvlen = sc->util_sc.ic_buflen;
+ ret = vmbus_chan_recv(channel, vss_buf, &recvlen, &requestid);
+ KASSERT(ret != ENOBUFS, ("hvvss recvbuf is not large enough"));
+ /* XXX check recvlen to make sure that it contains enough data */
+
+ hv_vss_log_info("%s: read: context %p, ret =%d, recvlen=%d\n",
+ __func__, context, ret, recvlen);
+ }
+}
+
+static int
+hv_vss_probe(device_t dev)
+{
+ return (vmbus_ic_probe(dev, vmbus_vss_descs));
+}
+
+static int
+hv_vss_init_send_receive_queue(device_t dev)
+{
+ hv_vss_sc *sc = (hv_vss_sc*)device_get_softc(dev);
+ int i;
+ const int max_list = 64; /* It is big enough for the list */
+ struct hv_vss_req_internal* reqp;
+
+ LIST_INIT(&sc->req_free_list);
+ STAILQ_INIT(&sc->to_daemon_msg_queue);
+ STAILQ_INIT(&sc->to_host_msg_queue);
+
+ for (i = 0; i < max_list; i++) {
+ reqp = malloc(sizeof(struct hv_vss_req_internal),
+ M_DEVBUF, M_WAITOK|M_ZERO);
+ LIST_INSERT_HEAD(&sc->req_free_list, reqp, link);
+ callout_init_mtx(&reqp->callout, &sc->pending_mutex, 0);
+ }
+ return (0);
+}
+
+static int
+hv_vss_destroy_send_receive_queue(device_t dev)
+{
+ hv_vss_sc *sc = (hv_vss_sc*)device_get_softc(dev);
+ hv_vss_req_internal* reqp;
+
+ while (!LIST_EMPTY(&sc->req_free_list)) {
+ reqp = LIST_FIRST(&sc->req_free_list);
+ LIST_REMOVE(reqp, link);
+ free(reqp, M_DEVBUF);
+ }
+
+ while (!STAILQ_EMPTY(&sc->to_daemon_msg_queue)) {
+ reqp = STAILQ_FIRST(&sc->to_daemon_msg_queue);
+ STAILQ_REMOVE_HEAD(&sc->to_daemon_msg_queue, slink);
+ free(reqp, M_DEVBUF);
+ }
+
+ while (!STAILQ_EMPTY(&sc->to_host_msg_queue)) {
+ reqp = STAILQ_FIRST(&sc->to_host_msg_queue);
+ STAILQ_REMOVE_HEAD(&sc->to_host_msg_queue, slink);
+ free(reqp, M_DEVBUF);
+ }
+ return (0);
+}
+
+static int
+hv_vss_attach(device_t dev)
+{
+ int error;
+ struct sysctl_oid_list *child;
+ struct sysctl_ctx_list *ctx;
+
+ hv_vss_sc *sc = (hv_vss_sc*)device_get_softc(dev);
+
+ sc->dev = dev;
+ mtx_init(&sc->pending_mutex, "hv_vss pending mutex",
+ NULL, MTX_DEF);
+
+ ctx = device_get_sysctl_ctx(dev);
+ child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
+
+ SYSCTL_ADD_INT(ctx, child, OID_AUTO, "hv_vss_log",
+ CTLFLAG_RWTUN, &hv_vss_log, 0, "Hyperv VSS service log level");
+
+ TASK_INIT(&sc->task, 0, hv_vss_process_request, sc);
+
+ /* create character device */
+ error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
+ &sc->hv_vss_dev,
+ &hv_vss_cdevsw,
+ 0,
+ UID_ROOT,
+ GID_WHEEL,
+ 0640,
+ "hv_vss_dev");
+
+ if (error != 0) {
+ hv_vss_log_info("Fail to create hv_vss_dev: %d\n", error);
+ return (error);
+ }
+ sc->hv_vss_dev->si_drv1 = sc;
+
+ hv_vss_init_send_receive_queue(dev);
+
+ return hv_util_attach(dev, hv_vss_callback);
+}
+
+static int
+hv_vss_detach(device_t dev)
+{
+ hv_vss_sc *sc = (hv_vss_sc*)device_get_softc(dev);
+
+ if (sc->daemon_task != NULL) {
+ PROC_LOCK(sc->daemon_task);
+ kern_psignal(sc->daemon_task, SIGKILL);
+ PROC_UNLOCK(sc->daemon_task);
+ }
+ hv_vss_destroy_send_receive_queue(dev);
+ destroy_dev(sc->hv_vss_dev);
+ return hv_util_detach(dev);
+}
+
+static device_method_t vss_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, hv_vss_probe),
+ DEVMETHOD(device_attach, hv_vss_attach),
+ DEVMETHOD(device_detach, hv_vss_detach),
+ { 0, 0 }
+};
+
+static driver_t vss_driver = { "hvvss", vss_methods, sizeof(hv_vss_sc)};
+
+static devclass_t vss_devclass;
+
+DRIVER_MODULE(hv_vss, vmbus, vss_driver, vss_devclass, NULL, NULL);
+MODULE_VERSION(hv_vss, 1);
+MODULE_DEPEND(hv_vss, vmbus, 1, 1, 1);
Index: sys/dev/hyperv/utilities/hv_util.h
===================================================================
--- sys/dev/hyperv/utilities/hv_util.h
+++ sys/dev/hyperv/utilities/hv_util.h
@@ -56,4 +56,6 @@
int vmbus_ic_probe(device_t dev, const struct vmbus_ic_desc descs[]);
int vmbus_ic_negomsg(struct hv_util_sc *, void *data, int *dlen);
+boolean_t hv_util_negotiate_version(uint8_t *buf,
+ int framewrk_ver, int service_ver);
#endif
Index: sys/dev/hyperv/utilities/hv_util.c
===================================================================
--- sys/dev/hyperv/utilities/hv_util.c
+++ sys/dev/hyperv/utilities/hv_util.c
@@ -42,6 +42,7 @@
#include <dev/hyperv/include/hyperv.h>
#include <dev/hyperv/include/vmbus.h>
#include <dev/hyperv/utilities/hv_util.h>
+#include <dev/hyperv/utilities/hv_utilreg.h>
#include <dev/hyperv/utilities/vmbus_icreg.h>
#include "vmbus_if.h"
@@ -159,3 +160,83 @@
return (0);
}
+
+/*
+ * version neogtiation function
+ * Create default response for Hyper-V Negotiate message
+ * @buf: Raw buffer channel data
+ * @framewrk_ver specifies the framework version that we can support
+ * @service_ver specifies the service version we can support.
+ */
+
+boolean_t
+hv_util_negotiate_version(uint8_t *buf, int framewrk_ver, int service_ver)
+{
+ struct hv_vmbus_icmsg_negotiate *negop;
+ int icmsg_major, icmsg_minor;
+ int fw_major, fw_minor;
+ int srv_major, srv_minor;
+ int i;
+ int icframe_major, icframe_minor;
+ struct hv_vmbus_icmsg_hdr *icmsghdrp;
+ boolean_t found = FALSE;
+
+ icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
+ &buf[sizeof(struct hv_vmbus_pipe_hdr)];
+ icmsghdrp->icmsgsize = 0x10;
+
+ fw_major = (framewrk_ver >> 16);
+ fw_minor = (framewrk_ver & 0xFFFF);
+
+ srv_major = (service_ver >> 16);
+ srv_minor = (service_ver & 0xFFFF);
+
+ negop = (struct hv_vmbus_icmsg_negotiate *)&buf[
+ sizeof(struct hv_vmbus_pipe_hdr) +
+ sizeof(struct hv_vmbus_icmsg_hdr)];
+
+ icframe_major = negop->icframe_vercnt;
+ icframe_minor = 0;
+ icmsg_major = negop->icmsg_vercnt;
+ icmsg_minor = 0;
+ /*
+ * Select the framework version number we will support
+ */
+ for (i = 0; i < negop->icframe_vercnt; i++) {
+ if ((negop->icversion_data[i].major == fw_major) &&
+ (negop->icversion_data[i].minor == fw_minor)) {
+ icframe_major = negop->icversion_data[i].major;
+ icframe_minor = negop->icversion_data[i].minor;
+ found = true;
+ }
+ }
+
+ if (!found)
+ goto handle_error;
+ found = false;
+
+ for (i = negop->icframe_vercnt;
+ i < negop->icframe_vercnt + negop->icmsg_vercnt; i++) {
+ if ((negop->icversion_data[i].major == srv_major) &&
+ (negop->icversion_data[i].minor == srv_minor)) {
+ icmsg_major = negop->icversion_data[i].major;
+ icmsg_minor = negop->icversion_data[i].minor;
+ found = true;
+ }
+ }
+
+handle_error:
+ if (!found) {
+ negop->icframe_vercnt = 0;
+ negop->icmsg_vercnt = 0;
+ } else {
+ negop->icframe_vercnt = 1;
+ negop->icmsg_vercnt = 1;
+ }
+
+ negop->icversion_data[0].major = icframe_major;
+ negop->icversion_data[0].minor = icframe_minor;
+ negop->icversion_data[1].major = icmsg_major;
+ negop->icversion_data[1].minor = icmsg_minor;
+ return found;
+}
Index: sys/modules/hyperv/utilities/Makefile
===================================================================
--- sys/modules/hyperv/utilities/Makefile
+++ sys/modules/hyperv/utilities/Makefile
@@ -3,7 +3,7 @@
.PATH: ${.CURDIR}/../../../dev/hyperv/utilities
KMOD= hv_utils
-SRCS= hv_util.c hv_kvp.c hv_timesync.c hv_shutdown.c hv_heartbeat.c
+SRCS= hv_util.c hv_kvp.c hv_snapshot.c hv_timesync.c hv_shutdown.c hv_heartbeat.c hv_snapshot.c
SRCS+= bus_if.h device_if.h vmbus_if.h
CFLAGS+= -I${.CURDIR}/../../../dev/hyperv/include \
Index:
===================================================================
--- /dev/null
+++ /dev/null
@@ -1,19 +0,0 @@
-# $FreeBSD$
-# Autogenerated - do NOT edit!
-
-DIRDEPS = \
- gnu/lib/csu \
- gnu/lib/libgcc \
- include \
- include/arpa \
- include/xlocale \
- lib/${CSU_DIR} \
- lib/libc \
- lib/libcompiler_rt \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
Index: usr.sbin/hyperv/tools/kvp/Makefile
===================================================================
--- usr.sbin/hyperv/tools/kvp/Makefile
+++ usr.sbin/hyperv/tools/kvp/Makefile
@@ -2,12 +2,12 @@
.include <bsd.own.mk>
-HV_KVP_DAEMON_DISTDIR?= ${.CURDIR}/../../../contrib/hyperv/tools
+HV_KVP_DAEMON_DISTDIR?= ${.CURDIR}/../../../../contrib/hyperv/tools
.PATH: ${HV_KVP_DAEMON_DISTDIR}
PROG= hv_kvp_daemon
MAN= hv_kvp_daemon.8
-CFLAGS+= -I${.CURDIR}/../../../sys/dev/hyperv/utilities
+CFLAGS+= -I${.CURDIR}/../../../../sys/dev/hyperv/utilities
.include <bsd.prog.mk>
Index: usr.sbin/hyperv/tools/vss/Makefile
===================================================================
--- /dev/null
+++ usr.sbin/hyperv/tools/vss/Makefile
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+HV_VSS_DAEMON_DISTDIR?= ${.CURDIR}/../../../../contrib/hyperv/tools
+.PATH: ${HV_VSS_DAEMON_DISTDIR}
+
+PROG= hv_vss_daemon
+MAN= hv_vss_daemon.8
+
+CFLAGS+= -I${.CURDIR}/../../../../sys/dev/hyperv/utilities
+
+.include <bsd.prog.mk>

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 4, 1:07 AM (2 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30789469
Default Alt Text
D8215.diff (45 KB)

Event Timeline