- add hv_vss_daemon (fate#314921)

helper to support host initiated backup

OBS-URL: https://build.opensuse.org/package/show/Virtualization/hyper-v?expand=0&rev=55
This commit is contained in:
Olaf Hering 2013-03-22 16:24:55 +00:00 committed by Git OBS Bridge
parent d6d5232591
commit 906e78cd04
5 changed files with 394 additions and 3 deletions

View File

@ -1,3 +1,9 @@
-------------------------------------------------------------------
Fri Mar 22 17:23:36 CET 2013 - ohering@suse.de
- add hv_vss_daemon (fate#314921)
helper to support host initiated backup
-------------------------------------------------------------------
Fri Mar 22 16:56:57 CET 2013 - ohering@suse.de

View File

@ -27,6 +27,63 @@
#include <linux/types.h>
/*
* Implementation of host controlled snapshot of the guest.
*/
#define VSS_OP_REGISTER 128
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 {
__u8 operation;
__u8 reserved[7];
} __attribute__((packed));
/*
* Flag values for the hv_vss_check_feature. Linux supports only
* one value.
*/
#define VSS_HBU_NO_AUTO_RECOVERY 0x00000005
struct hv_vss_check_feature {
__u32 flags;
} __attribute__((packed));
struct hv_vss_check_dm_info {
__u32 flags;
} __attribute__((packed));
struct hv_vss_msg {
union {
struct hv_vss_hdr vss_hdr;
int error;
};
union {
struct hv_vss_check_feature vss_cf;
struct hv_vss_check_dm_info dm_info;
};
} __attribute__((packed));
/*
* An implementation of HyperV key value pair (KVP) functionality for Linux.
*

82
hyper-v.init.vss.sh Normal file
View File

@ -0,0 +1,82 @@
#!/bin/sh
#
# LSB compatible service control script; see http://www.linuxbase.org/spec/
#
### BEGIN INIT INFO
# Provides: hv_vss_daemon
# Required-Start: $null
# Should-Start: $syslog $remote_fs $time
# Required-Stop: $null
# Should-Stop: $syslog $remote_fs $time
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: hv_vss_daemon assists with host initiated backup
# Description: Start hv_vss_daemon to allow the host to snapshot this guest
### END INIT INFO
# Check for missing binaries (stale symlinks should not happen)
# Note: Special treatment of stop for LSB conformance
HV_VSS_BIN=/usr/sbin/hv_vss_daemon
test -x $HV_VSS_BIN || { echo "$HV_VSS_BIN not installed";
if [ "$1" = "stop" ]; then exit 0;
else exit 5; fi; }
. /etc/rc.status
# Reset status of this service
rc_reset
case "$1" in
start)
echo -n "Starting Hyper-V VSS daemon "
env PATH=/usr/lib/hyper-v/bin:$PATH \
startproc $HV_VSS_BIN
rc_status -v
;;
stop)
echo -n "Shutting down Hyper-V VSS daemon "
killproc -TERM $HV_VSS_BIN
rc_status -v
;;
try-restart|condrestart)
if test "$1" = "condrestart"; then
echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
fi
$0 status
if test $? = 0; then
$0 restart
else
rc_reset # Not running is not a failure.
fi
# Remember status and be quiet
rc_status
;;
restart)
## Stop the service and regardless of whether it was
## running or not, start it again.
$0 stop
$0 start
# Remember status and be quiet
rc_status
;;
force-reload)
echo -n "Reload service Hyper-V VSS daemon "
$0 try-restart
rc_status
;;
reload)
rc_failed 3
rc_status -v
;;
status)
echo -n "Checking for service Hyper-V VSS daemon "
checkproc $HV_VSS_BIN
rc_status -v
;;
*)
echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload}"
exit 1
;;
esac
rc_exit

View File

@ -17,6 +17,7 @@
%define hv_kvp_daemon hv_kvp_daemon
%define hv_vss_daemon hv_vss_daemon
Name: hyper-v
ExclusiveArch: %ix86 x86_64
@ -34,6 +35,8 @@ Source5: hyper-v.kvptest.ps1.txt
Source9: hyper-v.include.linux.hyperv.h
Source10: hyper-v.tools.hv.hv_kvp_daemon.c
Source11: hyper-v.init.sh
Source12: hyper-v.tools.hv.hv_vss_daemon.c
Source13: hyper-v.init.vss.sh
Source20: hyper-v.tools.hv.hv_get_dhcp_info.sh
Source21: hyper-v.tools.hv.hv_get_dns_info.sh
Source22: hyper-v.tools.hv.hv_set_ifconfig.sh
@ -48,9 +51,11 @@ This package contains the Microsoft Hyper-V tools.
cp -avL %{S:5} kvptest.ps1.txt
cp -vL %{S:9} %{hv_kvp_daemon}.h
cp -vL %{S:10} %{hv_kvp_daemon}.c
cp -vL %{S:12} %{hv_vss_daemon}.c
%build
sed -i~ '/#include <linux.hyperv.h>/d' %{hv_kvp_daemon}.c
sed -i~ '/#include <linux.hyperv.h>/d' %{hv_vss_daemon}.c
gcc \
$RPM_OPT_FLAGS \
-Wno-unused-variable \
@ -62,10 +67,22 @@ gcc \
-DCN_KVP_IDX=0x9 \
-DCN_KVP_VAL=0x1 \
-o %{hv_kvp_daemon}
gcc \
$RPM_OPT_FLAGS \
-Wno-unused-variable \
-Wno-pointer-sign \
-D_GNU_SOURCE \
-g \
%{hv_vss_daemon}.c \
-include %{hv_kvp_daemon}.h \
-DCN_VSS_IDX=0xa \
-DCN_VSS_VAL=0x1 \
-o %{hv_vss_daemon}
%install
mkdir -p $RPM_BUILD_ROOT/usr/sbin
install -m755 %{hv_kvp_daemon} $RPM_BUILD_ROOT/usr/sbin
install -m755 %{hv_vss_daemon} $RPM_BUILD_ROOT/usr/sbin
mkdir -p $RPM_BUILD_ROOT/usr/lib/%{name}/bin
cp -avL %{S:20} $RPM_BUILD_ROOT/usr/lib/%{name}/bin/hv_get_dhcp_info
cp -avL %{S:21} $RPM_BUILD_ROOT/usr/lib/%{name}/bin/hv_get_dns_info
@ -74,13 +91,14 @@ chmod 755 $RPM_BUILD_ROOT/usr/lib/%{name}/bin/*
mkdir -p $RPM_BUILD_ROOT/etc/init.d
install -m755 %{S:11} $RPM_BUILD_ROOT/etc/init.d/%{hv_kvp_daemon}
ln -sfvbn ../../etc/init.d/%{hv_kvp_daemon} $RPM_BUILD_ROOT/usr/sbin/rc%{hv_kvp_daemon}
install -m755 %{S:13} $RPM_BUILD_ROOT/etc/init.d/%{hv_vss_daemon}
ln -sfvbn ../../etc/init.d/%{hv_vss_daemon} $RPM_BUILD_ROOT/usr/sbin/rc%{hv_vss_daemon}
%files
%defattr (-,root,root)
%doc kvptest.ps1.txt
/etc/init.d/%{hv_kvp_daemon}
/usr/sbin/rc%{hv_kvp_daemon}
/usr/sbin/%{hv_kvp_daemon}
/etc/init.d/*
/usr/sbin/*
/usr/lib/%{name}
%pre
@ -121,10 +139,13 @@ if test "${board_vendor}" = "Microsoft Corporation" -a "${product_name}" = "Virt
then
echo "Enabling %{hv_kvp_daemon} on '${product_name}' from '${board_vendor}'"
%{insserv_force_if_yast %{hv_kvp_daemon}}
echo "Enabling %{hv_vss_daemon} on '${product_name}' from '${board_vendor}'"
%{insserv_force_if_yast %{hv_vss_daemon}}
fi
%preun
%stop_on_removal %{hv_kvp_daemon}
%stop_on_removal %{hv_vss_daemon}
%postun
# no restart on update because the daemon can not be restarted

View File

@ -0,0 +1,225 @@
/*
* An implementation of the host initiated guest snapshot for Hyper-V.
*
*
* Copyright (C) 2013, Microsoft, Inc.
* Author : K. Y. Srinivasan <kys@microsoft.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more
* details.
*
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <linux/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <arpa/inet.h>
#include <linux/connector.h>
#include <linux/hyperv.h>
#include <linux/netlink.h>
#include <syslog.h>
static char vss_recv_buffer[4096];
static char vss_send_buffer[4096];
static struct sockaddr_nl addr;
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
static int vss_operate(int operation)
{
char *fs_op;
char cmd[512];
char buf[512];
FILE *file;
char *p;
char *x;
int error = -1;
switch (operation) {
case VSS_OP_FREEZE:
fs_op = "-f ";
break;
case VSS_OP_THAW:
fs_op = "-u ";
break;
default:
goto out;
}
file = popen("mount | awk '/^\\/dev\\// { print $3}'", "r");
if (file == NULL)
goto out;
while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
x = strchr(p, '\n');
*x = '\0';
if (!strncmp(p, "/", sizeof("/")))
continue;
sprintf(cmd, "%s %s %s", "fsfreeze ", fs_op, p);
syslog(LOG_INFO, "VSS cmd is %s\n", cmd);
error = system(cmd);
}
pclose(file);
sprintf(cmd, "%s %s %s", "fsfreeze ", fs_op, "/");
syslog(LOG_INFO, "VSS cmd is %s\n", cmd);
error = system(cmd);
out:
return error;
}
static int netlink_send(int fd, struct cn_msg *msg)
{
struct nlmsghdr *nlh;
unsigned int size;
struct msghdr message;
char buffer[64];
struct iovec iov[2];
size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
nlh = (struct nlmsghdr *)buffer;
nlh->nlmsg_seq = 0;
nlh->nlmsg_pid = getpid();
nlh->nlmsg_type = NLMSG_DONE;
nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
nlh->nlmsg_flags = 0;
iov[0].iov_base = nlh;
iov[0].iov_len = sizeof(*nlh);
iov[1].iov_base = msg;
iov[1].iov_len = size;
memset(&message, 0, sizeof(message));
message.msg_name = &addr;
message.msg_namelen = sizeof(addr);
message.msg_iov = iov;
message.msg_iovlen = 2;
return sendmsg(fd, &message, 0);
}
int main(void)
{
int fd, len, nl_group;
int error;
struct cn_msg *message;
struct pollfd pfd;
struct nlmsghdr *incoming_msg;
struct cn_msg *incoming_cn_msg;
int op;
struct hv_vss_msg *vss_msg;
if (daemon(1, 0))
return 1;
openlog("Hyper-V VSS", 0, LOG_USER);
syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());
fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
if (fd < 0) {
syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
exit(EXIT_FAILURE);
}
addr.nl_family = AF_NETLINK;
addr.nl_pad = 0;
addr.nl_pid = 0;
addr.nl_groups = 0;
error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if (error < 0) {
syslog(LOG_ERR, "bind failed; error:%d", error);
close(fd);
exit(EXIT_FAILURE);
}
nl_group = CN_VSS_IDX;
setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group));
/*
* Register ourselves with the kernel.
*/
message = (struct cn_msg *)vss_send_buffer;
message->id.idx = CN_VSS_IDX;
message->id.val = CN_VSS_VAL;
message->ack = 0;
vss_msg = (struct hv_vss_msg *)message->data;
vss_msg->vss_hdr.operation = VSS_OP_REGISTER;
message->len = sizeof(struct hv_vss_msg);
len = netlink_send(fd, message);
if (len < 0) {
syslog(LOG_ERR, "netlink_send failed; error:%d", len);
close(fd);
exit(EXIT_FAILURE);
}
pfd.fd = fd;
while (1) {
struct sockaddr *addr_p = (struct sockaddr *) &addr;
socklen_t addr_l = sizeof(addr);
pfd.events = POLLIN;
pfd.revents = 0;
poll(&pfd, 1, -1);
len = recvfrom(fd, vss_recv_buffer, sizeof(vss_recv_buffer), 0,
addr_p, &addr_l);
if (len < 0 || addr.nl_pid) {
syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
addr.nl_pid, errno, strerror(errno));
close(fd);
return -1;
}
incoming_msg = (struct nlmsghdr *)vss_recv_buffer;
if (incoming_msg->nlmsg_type != NLMSG_DONE)
continue;
incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
vss_msg = (struct hv_vss_msg *)incoming_cn_msg->data;
op = vss_msg->vss_hdr.operation;
error = HV_S_OK;
switch (op) {
case VSS_OP_FREEZE:
case VSS_OP_THAW:
error = vss_operate(op);
if (error)
error = HV_E_FAIL;
break;
default:
syslog(LOG_ERR, "Illegal op:%d\n", op);
}
vss_msg->error = error;
len = netlink_send(fd, incoming_cn_msg);
if (len < 0) {
syslog(LOG_ERR, "net_link send failed; error:%d", len);
exit(EXIT_FAILURE);
}
}
}