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 <sys/ioctl.h>
25 #include <linux/types.h>
34 #include <arpa/inet.h>
36 #include <linux/connector.h>
37 #include <linux/hyperv.h>
38 #include <linux/netlink.h>
41 static struct sockaddr_nl addr
;
44 #define SOL_NETLINK 270
48 static int vss_do_freeze(char *dir
, unsigned int cmd
, char *fs_op
)
50 int ret
, fd
= open(dir
, O_RDONLY
);
54 ret
= ioctl(fd
, cmd
, 0);
55 syslog(LOG_INFO
, "VSS: %s of %s: %s\n", fs_op
, dir
, strerror(errno
));
60 static int vss_operate(int operation
)
63 char match
[] = "/dev/";
67 int error
= 0, root_seen
= 0;
82 mounts
= setmntent("/proc/mounts", "r");
86 while ((ent
= getmntent(mounts
))) {
87 if (strncmp(ent
->mnt_fsname
, match
, strlen(match
)))
89 if (strcmp(ent
->mnt_type
, "iso9660") == 0)
91 if (strcmp(ent
->mnt_dir
, "/") == 0) {
95 error
|= vss_do_freeze(ent
->mnt_dir
, cmd
, fs_op
);
100 error
|= vss_do_freeze("/", cmd
, fs_op
);
106 static int netlink_send(int fd
, struct cn_msg
*msg
)
108 struct nlmsghdr nlh
= { .nlmsg_type
= NLMSG_DONE
};
110 struct msghdr message
;
113 size
= sizeof(struct cn_msg
) + msg
->len
;
115 nlh
.nlmsg_pid
= getpid();
116 nlh
.nlmsg_len
= NLMSG_LENGTH(size
);
118 iov
[0].iov_base
= &nlh
;
119 iov
[0].iov_len
= sizeof(nlh
);
121 iov
[1].iov_base
= msg
;
122 iov
[1].iov_len
= size
;
124 memset(&message
, 0, sizeof(message
));
125 message
.msg_name
= &addr
;
126 message
.msg_namelen
= sizeof(addr
);
127 message
.msg_iov
= iov
;
128 message
.msg_iovlen
= 2;
130 return sendmsg(fd
, &message
, 0);
135 int fd
, len
, nl_group
;
137 struct cn_msg
*message
;
139 struct nlmsghdr
*incoming_msg
;
140 struct cn_msg
*incoming_cn_msg
;
142 struct hv_vss_msg
*vss_msg
;
143 char *vss_send_buffer
;
144 char *vss_recv_buffer
;
145 size_t vss_recv_buffer_len
;
150 openlog("Hyper-V VSS", 0, LOG_USER
);
151 syslog(LOG_INFO
, "VSS starting; pid is:%d", getpid());
153 vss_recv_buffer_len
= NLMSG_HDRLEN
+ sizeof(struct cn_msg
) + sizeof(struct hv_vss_msg
);
154 vss_send_buffer
= calloc(1, vss_recv_buffer_len
);
155 vss_recv_buffer
= calloc(1, vss_recv_buffer_len
);
156 if (!(vss_send_buffer
&& vss_recv_buffer
)) {
157 syslog(LOG_ERR
, "Failed to allocate netlink buffers");
161 fd
= socket(AF_NETLINK
, SOCK_DGRAM
, NETLINK_CONNECTOR
);
163 syslog(LOG_ERR
, "netlink socket creation failed; error:%d %s",
164 errno
, strerror(errno
));
167 addr
.nl_family
= AF_NETLINK
;
173 error
= bind(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
175 syslog(LOG_ERR
, "bind failed; error:%d %s", errno
, strerror(errno
));
179 nl_group
= CN_VSS_IDX
;
180 if (setsockopt(fd
, SOL_NETLINK
, NETLINK_ADD_MEMBERSHIP
, &nl_group
, sizeof(nl_group
)) < 0) {
181 syslog(LOG_ERR
, "setsockopt failed; error:%d %s", errno
, strerror(errno
));
186 * Register ourselves with the kernel.
188 message
= (struct cn_msg
*)vss_send_buffer
;
189 message
->id
.idx
= CN_VSS_IDX
;
190 message
->id
.val
= CN_VSS_VAL
;
192 vss_msg
= (struct hv_vss_msg
*)message
->data
;
193 vss_msg
->vss_hdr
.operation
= VSS_OP_REGISTER
;
195 message
->len
= sizeof(struct hv_vss_msg
);
197 len
= netlink_send(fd
, message
);
199 syslog(LOG_ERR
, "netlink_send failed; error:%d %s", errno
, strerror(errno
));
207 struct sockaddr
*addr_p
= (struct sockaddr
*) &addr
;
208 socklen_t addr_l
= sizeof(addr
);
212 if (poll(&pfd
, 1, -1) < 0) {
213 syslog(LOG_ERR
, "poll failed; error:%d %s", errno
, strerror(errno
));
214 if (errno
== EINVAL
) {
222 len
= recvfrom(fd
, vss_recv_buffer
, vss_recv_buffer_len
, 0,
226 syslog(LOG_ERR
, "recvfrom failed; pid:%u error:%d %s",
227 addr
.nl_pid
, errno
, strerror(errno
));
234 "Received packet from untrusted pid:%u",
239 incoming_msg
= (struct nlmsghdr
*)vss_recv_buffer
;
241 if (incoming_msg
->nlmsg_type
!= NLMSG_DONE
)
244 incoming_cn_msg
= (struct cn_msg
*)NLMSG_DATA(incoming_msg
);
245 vss_msg
= (struct hv_vss_msg
*)incoming_cn_msg
->data
;
246 op
= vss_msg
->vss_hdr
.operation
;
252 error
= vss_operate(op
);
257 syslog(LOG_ERR
, "Illegal op:%d\n", op
);
259 vss_msg
->error
= error
;
260 len
= netlink_send(fd
, incoming_cn_msg
);
262 syslog(LOG_ERR
, "net_link send failed; error:%d %s",
263 errno
, strerror(errno
));