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_type
, "vfat") == 0)
92 if (strcmp(ent
->mnt_dir
, "/") == 0) {
96 error
|= vss_do_freeze(ent
->mnt_dir
, cmd
, fs_op
);
101 error
|= vss_do_freeze("/", cmd
, fs_op
);
107 static int netlink_send(int fd
, struct cn_msg
*msg
)
109 struct nlmsghdr nlh
= { .nlmsg_type
= NLMSG_DONE
};
111 struct msghdr message
;
114 size
= sizeof(struct cn_msg
) + msg
->len
;
116 nlh
.nlmsg_pid
= getpid();
117 nlh
.nlmsg_len
= NLMSG_LENGTH(size
);
119 iov
[0].iov_base
= &nlh
;
120 iov
[0].iov_len
= sizeof(nlh
);
122 iov
[1].iov_base
= msg
;
123 iov
[1].iov_len
= size
;
125 memset(&message
, 0, sizeof(message
));
126 message
.msg_name
= &addr
;
127 message
.msg_namelen
= sizeof(addr
);
128 message
.msg_iov
= iov
;
129 message
.msg_iovlen
= 2;
131 return sendmsg(fd
, &message
, 0);
136 int fd
, len
, nl_group
;
138 struct cn_msg
*message
;
140 struct nlmsghdr
*incoming_msg
;
141 struct cn_msg
*incoming_cn_msg
;
143 struct hv_vss_msg
*vss_msg
;
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_LENGTH(0) + sizeof(struct cn_msg
) + sizeof(struct hv_vss_msg
);
154 vss_recv_buffer
= calloc(1, vss_recv_buffer_len
);
155 if (!vss_recv_buffer
) {
156 syslog(LOG_ERR
, "Failed to allocate netlink buffers");
160 fd
= socket(AF_NETLINK
, SOCK_DGRAM
, NETLINK_CONNECTOR
);
162 syslog(LOG_ERR
, "netlink socket creation failed; error:%d %s",
163 errno
, strerror(errno
));
166 addr
.nl_family
= AF_NETLINK
;
172 error
= bind(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
174 syslog(LOG_ERR
, "bind failed; error:%d %s", errno
, strerror(errno
));
178 nl_group
= CN_VSS_IDX
;
179 if (setsockopt(fd
, SOL_NETLINK
, NETLINK_ADD_MEMBERSHIP
, &nl_group
, sizeof(nl_group
)) < 0) {
180 syslog(LOG_ERR
, "setsockopt failed; error:%d %s", errno
, strerror(errno
));
185 * Register ourselves with the kernel.
187 message
= (struct cn_msg
*)vss_recv_buffer
;
188 message
->id
.idx
= CN_VSS_IDX
;
189 message
->id
.val
= CN_VSS_VAL
;
191 vss_msg
= (struct hv_vss_msg
*)message
->data
;
192 vss_msg
->vss_hdr
.operation
= VSS_OP_REGISTER
;
194 message
->len
= sizeof(struct hv_vss_msg
);
196 len
= netlink_send(fd
, message
);
198 syslog(LOG_ERR
, "netlink_send failed; error:%d %s", errno
, strerror(errno
));
206 struct sockaddr
*addr_p
= (struct sockaddr
*) &addr
;
207 socklen_t addr_l
= sizeof(addr
);
211 if (poll(&pfd
, 1, -1) < 0) {
212 syslog(LOG_ERR
, "poll failed; error:%d %s", errno
, strerror(errno
));
213 if (errno
== EINVAL
) {
221 len
= recvfrom(fd
, vss_recv_buffer
, vss_recv_buffer_len
, 0,
225 syslog(LOG_ERR
, "recvfrom failed; pid:%u error:%d %s",
226 addr
.nl_pid
, errno
, strerror(errno
));
233 "Received packet from untrusted pid:%u",
238 incoming_msg
= (struct nlmsghdr
*)vss_recv_buffer
;
240 if (incoming_msg
->nlmsg_type
!= NLMSG_DONE
)
243 incoming_cn_msg
= (struct cn_msg
*)NLMSG_DATA(incoming_msg
);
244 vss_msg
= (struct hv_vss_msg
*)incoming_cn_msg
->data
;
245 op
= vss_msg
->vss_hdr
.operation
;
251 error
= vss_operate(op
);
256 syslog(LOG_ERR
, "Illegal op:%d\n", op
);
258 vss_msg
->error
= error
;
259 len
= netlink_send(fd
, incoming_cn_msg
);
261 syslog(LOG_ERR
, "net_link send failed; error:%d %s",
262 errno
, strerror(errno
));