- 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:
parent
d6d5232591
commit
906e78cd04
@ -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
|
||||
|
||||
|
@ -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
82
hyper-v.init.vss.sh
Normal 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
|
27
hyper-v.spec
27
hyper-v.spec
@ -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
|
||||
|
225
hyper-v.tools.hv.hv_vss_daemon.c
Normal file
225
hyper-v.tools.hv.hv_vss_daemon.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user