Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F150641902
D8215.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
45 KB
Referenced Files
None
Subscribers
None
D8215.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D8215: hyperv/vss: implement the VSS (Volume Shadow Copy Service)
Attached
Detach File
Event Timeline
Log In to Comment