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>
33 #include <arpa/inet.h>
35 #include <linux/connector.h>
36 #include <linux/hyperv.h>
37 #include <linux/netlink.h>
40 static struct sockaddr_nl addr
;
43 #define SOL_NETLINK 270
47 static int vss_do_freeze(char *dir
, unsigned int cmd
, char *fs_op
)
49 int ret
, fd
= open(dir
, O_RDONLY
);
53 ret
= ioctl(fd
, cmd
, 0);
54 syslog(LOG_INFO
, "VSS: %s of %s: %s\n", fs_op
, dir
, strerror(errno
));
59 static int vss_operate(int operation
)
62 char match
[] = "/dev/";
66 int error
= 0, root_seen
= 0;
81 mounts
= setmntent("/proc/mounts", "r");
85 while ((ent
= getmntent(mounts
))) {
86 if (strncmp(ent
->mnt_fsname
, match
, strlen(match
)))
88 if (strcmp(ent
->mnt_type
, "iso9660") == 0)
90 if (strcmp(ent
->mnt_dir
, "/") == 0) {
94 error
|= vss_do_freeze(ent
->mnt_dir
, cmd
, fs_op
);
99 error
|= vss_do_freeze("/", cmd
, fs_op
);
105 static int netlink_send(int fd
, struct cn_msg
*msg
)
107 struct nlmsghdr nlh
= { .nlmsg_type
= NLMSG_DONE
};
109 struct msghdr message
;
112 size
= sizeof(struct cn_msg
) + msg
->len
;
114 nlh
.nlmsg_pid
= getpid();
115 nlh
.nlmsg_len
= NLMSG_LENGTH(size
);
117 iov
[0].iov_base
= &nlh
;
118 iov
[0].iov_len
= sizeof(nlh
);
120 iov
[1].iov_base
= msg
;
121 iov
[1].iov_len
= size
;
123 memset(&message
, 0, sizeof(message
));
124 message
.msg_name
= &addr
;
125 message
.msg_namelen
= sizeof(addr
);
126 message
.msg_iov
= iov
;
127 message
.msg_iovlen
= 2;
129 return sendmsg(fd
, &message
, 0);
134 int fd
, len
, nl_group
;
136 struct cn_msg
*message
;
138 struct nlmsghdr
*incoming_msg
;
139 struct cn_msg
*incoming_cn_msg
;
141 struct hv_vss_msg
*vss_msg
;
142 char *vss_recv_buffer
;
143 size_t vss_recv_buffer_len
;
148 openlog("Hyper-V VSS", 0, LOG_USER
);
149 syslog(LOG_INFO
, "VSS starting; pid is:%d", getpid());
151 vss_recv_buffer_len
= NLMSG_LENGTH(0) + sizeof(struct cn_msg
) + sizeof(struct hv_vss_msg
);
152 vss_recv_buffer
= calloc(1, vss_recv_buffer_len
);
153 if (!vss_recv_buffer
) {
154 syslog(LOG_ERR
, "Failed to allocate netlink buffers");
158 fd
= socket(AF_NETLINK
, SOCK_DGRAM
, NETLINK_CONNECTOR
);
160 syslog(LOG_ERR
, "netlink socket creation failed; error:%d %s",
161 errno
, strerror(errno
));
164 addr
.nl_family
= AF_NETLINK
;
170 error
= bind(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
172 syslog(LOG_ERR
, "bind failed; error:%d %s", errno
, strerror(errno
));
176 nl_group
= CN_VSS_IDX
;
177 if (setsockopt(fd
, SOL_NETLINK
, NETLINK_ADD_MEMBERSHIP
, &nl_group
, sizeof(nl_group
)) < 0) {
178 syslog(LOG_ERR
, "setsockopt failed; error:%d %s", errno
, strerror(errno
));
183 * Register ourselves with the kernel.
185 message
= (struct cn_msg
*)vss_recv_buffer
;
186 message
->id
.idx
= CN_VSS_IDX
;
187 message
->id
.val
= CN_VSS_VAL
;
189 vss_msg
= (struct hv_vss_msg
*)message
->data
;
190 vss_msg
->vss_hdr
.operation
= VSS_OP_REGISTER
;
192 message
->len
= sizeof(struct hv_vss_msg
);
194 len
= netlink_send(fd
, message
);
196 syslog(LOG_ERR
, "netlink_send failed; error:%d %s", errno
, strerror(errno
));
204 struct sockaddr
*addr_p
= (struct sockaddr
*) &addr
;
205 socklen_t addr_l
= sizeof(addr
);
209 if (poll(&pfd
, 1, -1) < 0) {
210 syslog(LOG_ERR
, "poll failed; error:%d %s", errno
, strerror(errno
));
211 if (errno
== EINVAL
) {
219 len
= recvfrom(fd
, vss_recv_buffer
, vss_recv_buffer_len
, 0,
223 syslog(LOG_ERR
, "recvfrom failed; pid:%u error:%d %s",
224 addr
.nl_pid
, errno
, strerror(errno
));
231 "Received packet from untrusted pid:%u",
236 incoming_msg
= (struct nlmsghdr
*)vss_recv_buffer
;
238 if (incoming_msg
->nlmsg_type
!= NLMSG_DONE
)
241 incoming_cn_msg
= (struct cn_msg
*)NLMSG_DATA(incoming_msg
);
242 vss_msg
= (struct hv_vss_msg
*)incoming_cn_msg
->data
;
243 op
= vss_msg
->vss_hdr
.operation
;
249 error
= vss_operate(op
);
254 syslog(LOG_ERR
, "Illegal op:%d\n", op
);
256 vss_msg
->error
= error
;
257 len
= netlink_send(fd
, incoming_cn_msg
);
259 syslog(LOG_ERR
, "net_link send failed; error:%d %s",
260 errno
, strerror(errno
));