aboutsummaryrefslogtreecommitdiffstats
path: root/tools/hv
diff options
context:
space:
mode:
authorK. Y. Srinivasan <kys@microsoft.com>2013-03-15 15:30:06 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-15 15:12:36 -0400
commit96dd86fa588169b745a71aedf2070e80f4943623 (patch)
tree3affd55b169f7c3030b5ecb1d4caf700d31b28c2 /tools/hv
parentc87059793dd02390b504b0292bdb024ffd68b822 (diff)
Drivers: hv: Add a new driver to support host initiated backup
This driver supports host initiated backup of the guest. On Windows guests, the host can generate application consistent backups using the Windows VSS framework. On Linux, we ensure that the backup will be file system consistent. This driver allows the host to initiate a "Freeze" operation on all the mounted file systems in the guest. Once the mounted file systems in the guest are frozen, the host snapshots the guest's file systems. Once this is done, the guest's file systems are "thawed". This driver has a user-level component (daemon) that invokes the appropriate operation on all the mounted file systems in response to the requests from the host. The duration for which the guest is frozen is very short - a few seconds. During this interval, the diff disk is comitted. In this version of the patch I have addressed the feedback from Olaf Herring. Also, some of the connector related issues have been fixed. Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> Cc: Evgeniy Polyakov <zbr@ioremap.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'tools/hv')
-rw-r--r--tools/hv/hv_vss_daemon.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
new file mode 100644
index 000000000000..95269952aa92
--- /dev/null
+++ b/tools/hv/hv_vss_daemon.c
@@ -0,0 +1,220 @@
1/*
2 * An implementation of the host initiated guest snapshot for Hyper-V.
3 *
4 *
5 * Copyright (C) 2013, Microsoft, Inc.
6 * Author : K. Y. Srinivasan <kys@microsoft.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15 * NON INFRINGEMENT. See the GNU General Public License for more
16 * details.
17 *
18 */
19
20
21#include <sys/types.h>
22#include <sys/socket.h>
23#include <sys/poll.h>
24#include <linux/types.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <string.h>
29#include <ctype.h>
30#include <errno.h>
31#include <arpa/inet.h>
32#include <linux/connector.h>
33#include <linux/hyperv.h>
34#include <linux/netlink.h>
35#include <syslog.h>
36
37static char vss_recv_buffer[4096];
38static char vss_send_buffer[4096];
39static struct sockaddr_nl addr;
40
41#ifndef SOL_NETLINK
42#define SOL_NETLINK 270
43#endif
44
45
46static int vss_operate(int operation)
47{
48 char *fs_op;
49 char cmd[512];
50 char buf[512];
51 FILE *file;
52 char *p;
53 char *x;
54 int error;
55
56 switch (operation) {
57 case VSS_OP_FREEZE:
58 fs_op = "-f ";
59 break;
60 case VSS_OP_THAW:
61 fs_op = "-u ";
62 break;
63 }
64
65 file = popen("mount | awk '/^\/dev\// { print $3}'", "r");
66 if (file == NULL)
67 return;
68
69 while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
70 x = strchr(p, '\n');
71 *x = '\0';
72 if (!strncmp(p, "/", sizeof("/")))
73 continue;
74
75 sprintf(cmd, "%s %s %s", "fsfreeze ", fs_op, p);
76 syslog(LOG_INFO, "VSS cmd is %s\n", cmd);
77 error = system(cmd);
78 }
79 pclose(file);
80
81 sprintf(cmd, "%s %s %s", "fsfreeze ", fs_op, "/");
82 syslog(LOG_INFO, "VSS cmd is %s\n", cmd);
83 error = system(cmd);
84
85 return error;
86}
87
88static int netlink_send(int fd, struct cn_msg *msg)
89{
90 struct nlmsghdr *nlh;
91 unsigned int size;
92 struct msghdr message;
93 char buffer[64];
94 struct iovec iov[2];
95
96 size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
97
98 nlh = (struct nlmsghdr *)buffer;
99 nlh->nlmsg_seq = 0;
100 nlh->nlmsg_pid = getpid();
101 nlh->nlmsg_type = NLMSG_DONE;
102 nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
103 nlh->nlmsg_flags = 0;
104
105 iov[0].iov_base = nlh;
106 iov[0].iov_len = sizeof(*nlh);
107
108 iov[1].iov_base = msg;
109 iov[1].iov_len = size;
110
111 memset(&message, 0, sizeof(message));
112 message.msg_name = &addr;
113 message.msg_namelen = sizeof(addr);
114 message.msg_iov = iov;
115 message.msg_iovlen = 2;
116
117 return sendmsg(fd, &message, 0);
118}
119
120int main(void)
121{
122 int fd, len, nl_group;
123 int error;
124 struct cn_msg *message;
125 struct pollfd pfd;
126 struct nlmsghdr *incoming_msg;
127 struct cn_msg *incoming_cn_msg;
128 int op;
129 struct hv_vss_msg *vss_msg;
130
131 daemon(1, 0);
132 openlog("Hyper-V VSS", 0, LOG_USER);
133 syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());
134
135 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
136 if (fd < 0) {
137 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
138 exit(EXIT_FAILURE);
139 }
140 addr.nl_family = AF_NETLINK;
141 addr.nl_pad = 0;
142 addr.nl_pid = 0;
143 addr.nl_groups = 0;
144
145
146 error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
147 if (error < 0) {
148 syslog(LOG_ERR, "bind failed; error:%d", error);
149 close(fd);
150 exit(EXIT_FAILURE);
151 }
152 nl_group = CN_VSS_IDX;
153 setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group));
154 /*
155 * Register ourselves with the kernel.
156 */
157 message = (struct cn_msg *)vss_send_buffer;
158 message->id.idx = CN_VSS_IDX;
159 message->id.val = CN_VSS_VAL;
160 message->ack = 0;
161 vss_msg = (struct hv_vss_msg *)message->data;
162 vss_msg->vss_hdr.operation = VSS_OP_REGISTER;
163
164 message->len = sizeof(struct hv_vss_msg);
165
166 len = netlink_send(fd, message);
167 if (len < 0) {
168 syslog(LOG_ERR, "netlink_send failed; error:%d", len);
169 close(fd);
170 exit(EXIT_FAILURE);
171 }
172
173 pfd.fd = fd;
174
175 while (1) {
176 struct sockaddr *addr_p = (struct sockaddr *) &addr;
177 socklen_t addr_l = sizeof(addr);
178 pfd.events = POLLIN;
179 pfd.revents = 0;
180 poll(&pfd, 1, -1);
181
182 len = recvfrom(fd, vss_recv_buffer, sizeof(vss_recv_buffer), 0,
183 addr_p, &addr_l);
184
185 if (len < 0 || addr.nl_pid) {
186 syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
187 addr.nl_pid, errno, strerror(errno));
188 close(fd);
189 return -1;
190 }
191
192 incoming_msg = (struct nlmsghdr *)vss_recv_buffer;
193
194 if (incoming_msg->nlmsg_type != NLMSG_DONE)
195 continue;
196
197 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
198 vss_msg = (struct hv_vss_msg *)incoming_cn_msg->data;
199 op = vss_msg->vss_hdr.operation;
200 error = HV_S_OK;
201
202 switch (op) {
203 case VSS_OP_FREEZE:
204 case VSS_OP_THAW:
205 error = vss_operate(op);
206 if (error)
207 error = HV_E_FAIL;
208 break;
209 default:
210 syslog(LOG_ERR, "Illegal op:%d\n", op);
211 }
212 vss_msg->error = error;
213 len = netlink_send(fd, incoming_cn_msg);
214 if (len < 0) {
215 syslog(LOG_ERR, "net_link send failed; error:%d", len);
216 exit(EXIT_FAILURE);
217 }
218 }
219
220}