2a03d0b4e213f0d4a53f87648e30ae8a6eb5ceee
2 * An implementation of the host initiated guest snapshot for Hyper-V.
5 * Copyright (C) 2013, Microsoft, Inc.
6 * Author : K. Y. Srinivasan <kys@microsoft.com>
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.
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
21 #include <sys/types.h>
22 #include <sys/socket.h>
24 #include <linux/types.h>
31 #include <arpa/inet.h>
32 #include <linux/connector.h>
33 #include <linux/hyperv.h>
34 #include <linux/netlink.h>
37 static char vss_recv_buffer
[4096];
38 static char vss_send_buffer
[4096];
39 static struct sockaddr_nl addr
;
42 #define SOL_NETLINK 270
46 static int vss_operate(int operation
)
67 file
= popen("mount | awk '/^\\/dev\\// { print $3}'", "r");
71 while ((p
= fgets(buf
, sizeof(buf
), file
)) != NULL
) {
74 if (!strncmp(p
, "/", sizeof("/")))
77 sprintf(cmd
, "%s %s %s", "fsfreeze ", fs_op
, p
);
78 syslog(LOG_INFO
, "VSS cmd is %s\n", cmd
);
83 sprintf(cmd
, "%s %s %s", "fsfreeze ", fs_op
, "/");
84 syslog(LOG_INFO
, "VSS cmd is %s\n", cmd
);
90 static int netlink_send(int fd
, struct cn_msg
*msg
)
94 struct msghdr message
;
98 size
= NLMSG_SPACE(sizeof(struct cn_msg
) + msg
->len
);
100 nlh
= (struct nlmsghdr
*)buffer
;
102 nlh
->nlmsg_pid
= getpid();
103 nlh
->nlmsg_type
= NLMSG_DONE
;
104 nlh
->nlmsg_len
= NLMSG_LENGTH(size
- sizeof(*nlh
));
105 nlh
->nlmsg_flags
= 0;
107 iov
[0].iov_base
= nlh
;
108 iov
[0].iov_len
= sizeof(*nlh
);
110 iov
[1].iov_base
= msg
;
111 iov
[1].iov_len
= size
;
113 memset(&message
, 0, sizeof(message
));
114 message
.msg_name
= &addr
;
115 message
.msg_namelen
= sizeof(addr
);
116 message
.msg_iov
= iov
;
117 message
.msg_iovlen
= 2;
119 return sendmsg(fd
, &message
, 0);
124 int fd
, len
, nl_group
;
126 struct cn_msg
*message
;
128 struct nlmsghdr
*incoming_msg
;
129 struct cn_msg
*incoming_cn_msg
;
131 struct hv_vss_msg
*vss_msg
;
136 openlog("Hyper-V VSS", 0, LOG_USER
);
137 syslog(LOG_INFO
, "VSS starting; pid is:%d", getpid());
139 fd
= socket(AF_NETLINK
, SOCK_DGRAM
, NETLINK_CONNECTOR
);
141 syslog(LOG_ERR
, "netlink socket creation failed; error:%d", fd
);
144 addr
.nl_family
= AF_NETLINK
;
150 error
= bind(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
152 syslog(LOG_ERR
, "bind failed; error:%d", error
);
156 nl_group
= CN_VSS_IDX
;
157 setsockopt(fd
, SOL_NETLINK
, NETLINK_ADD_MEMBERSHIP
, &nl_group
, sizeof(nl_group
));
159 * Register ourselves with the kernel.
161 message
= (struct cn_msg
*)vss_send_buffer
;
162 message
->id
.idx
= CN_VSS_IDX
;
163 message
->id
.val
= CN_VSS_VAL
;
165 vss_msg
= (struct hv_vss_msg
*)message
->data
;
166 vss_msg
->vss_hdr
.operation
= VSS_OP_REGISTER
;
168 message
->len
= sizeof(struct hv_vss_msg
);
170 len
= netlink_send(fd
, message
);
172 syslog(LOG_ERR
, "netlink_send failed; error:%d", len
);
180 struct sockaddr
*addr_p
= (struct sockaddr
*) &addr
;
181 socklen_t addr_l
= sizeof(addr
);
186 len
= recvfrom(fd
, vss_recv_buffer
, sizeof(vss_recv_buffer
), 0,
189 if (len
< 0 || addr
.nl_pid
) {
190 syslog(LOG_ERR
, "recvfrom failed; pid:%u error:%d %s",
191 addr
.nl_pid
, errno
, strerror(errno
));
196 incoming_msg
= (struct nlmsghdr
*)vss_recv_buffer
;
198 if (incoming_msg
->nlmsg_type
!= NLMSG_DONE
)
201 incoming_cn_msg
= (struct cn_msg
*)NLMSG_DATA(incoming_msg
);
202 vss_msg
= (struct hv_vss_msg
*)incoming_cn_msg
->data
;
203 op
= vss_msg
->vss_hdr
.operation
;
209 error
= vss_operate(op
);
214 syslog(LOG_ERR
, "Illegal op:%d\n", op
);
216 vss_msg
->error
= error
;
217 len
= netlink_send(fd
, incoming_cn_msg
);
219 syslog(LOG_ERR
, "net_link send failed; error:%d", len
);